Updated with latest results on 17-Apr-2020
Situation
At home, I have three roofs (east, south and west) with 9.9 kWp PV feeding into a Fronius Symo 8.2-3-M. The setup has Fronius Smart Meter 63A-3.
In a few days I am adding a Multiplus-II 48/5000/70-50 and 2x Pylontech US2000 (4.4 kWh net) LiFePO battery.
Problem
I am running Venus OS on a Raspberry 3B+. It nicely shows the power fed in by the Symo, with all details.
Venus is not showing any data from the Fronius Smart Meter.
Vision
I would like to have the data from the Fronius Smart Meter available on the Venus.
My idea is that I need a driver for Venus OS, which gets the data from the Smart Meter via the http API that Fronius provides and passes that information onto dbus - where hopefully Venus treats the data as if it came from a meter that it knows.
Steps Forward
I searched for a solution to my problem on the internet.I thought that I can not be the first to have this issue. But I found no direct solution.
There are several projects that might be a good start for getting to a solution:
- dbusdummyservice.py from velib_python
A simple service on the dbus. - dbus-cgwacs
Reads energy measuremens from Carlo Gavazzi Wired AC Sensors (hence cgwacs), and puts it on the D-Bus.
Both projects look like a good start for programming my own solution.
Python script emulating the Victron Grid meter
Using dbusdummyservice.py from velib_python as a basis, I wrote this script:
- #!/usr/bin/env python
- """
- Used https://github.com/victronenergy/velib_python/blob/master/dbusdummyservice.py as basis for this service.
- Reading information from the Fronius Smart Meter via http REST API and puts the info on dbus.
- """
- import gobject
- import platform
- #import argparse
- import logging
- import sys
- import os
- import requests # for http GET
- # our own packages
- sys.path.insert(1, os.path.join(os.path.dirname(__file__), '../ext/velib_python'))
- from vedbus import VeDbusService
- class DbusDummyService:
- def __init__(self, servicename, deviceinstance, paths, productname='Fronius Smart Meter', connection='Fronius SM service'):
- self._dbusservice = VeDbusService(servicename)
- self._paths = paths
- logging.debug("%s /DeviceInstance = %d" % (servicename, deviceinstance))
- # Create the management objects, as specified in the ccgx dbus-api document
- self._dbusservice.add_path('/Mgmt/ProcessName', __file__)
- self._dbusservice.add_path('/Mgmt/ProcessVersion', 'Unkown version, and running on Python ' + platform.python_version())
- self._dbusservice.add_path('/Mgmt/Connection', connection)
- # Create the mandatory objects
- self._dbusservice.add_path('/DeviceInstance', deviceinstance)
- self._dbusservice.add_path('/ProductId', 16) # value used in ac_sensor_bridge.cpp of dbus-cgwacs
- self._dbusservice.add_path('/ProductName', productname)
- self._dbusservice.add_path('/FirmwareVersion', 0.1)
- self._dbusservice.add_path('/HardwareVersion', 0)
- self._dbusservice.add_path('/Connected', 1)
- for path, settings in self._paths.iteritems():
- self._dbusservice.add_path(
- path, settings['initial'], writeable=True, onchangecallback=self._handlechangedvalue)
- gobject.timeout_add(200, self._update) # pause 200ms before the next request
- def _update(self):
- URL = "http://10.194.65.143/solar_api/v1/GetMeterRealtimeData.cgi?Scope=Device&DeviceId=0&DataCollection=MeterRealtimeData"
- meter_r = requests.get(url = URL)
- meter_data = meter_r.json()
- MeterConsumption = meter_data['Body']['Data']['PowerReal_P_Sum']
- self._dbusservice['/Ac/Power'] = MeterConsumption # positive: consumption, negative: feed into grid
- self._dbusservice['/Ac/L1/Voltage'] = meter_data['Body']['Data']['Voltage_AC_Phase_1']
- self._dbusservice['/Ac/L2/Voltage'] = meter_data['Body']['Data']['Voltage_AC_Phase_2']
- self._dbusservice['/Ac/L3/Voltage'] = meter_data['Body']['Data']['Voltage_AC_Phase_3']
- self._dbusservice['/Ac/L1/Current'] = meter_data['Body']['Data']['Current_AC_Phase_1']
- self._dbusservice['/Ac/L2/Current'] = meter_data['Body']['Data']['Current_AC_Phase_2']
- self._dbusservice['/Ac/L3/Current'] = meter_data['Body']['Data']['Current_AC_Phase_3']
- self._dbusservice['/Ac/L1/Power'] = meter_data['Body']['Data']['PowerReal_P_Phase_1']
- self._dbusservice['/Ac/L2/Power'] = meter_data['Body']['Data']['PowerReal_P_Phase_2']
- self._dbusservice['/Ac/L3/Power'] = meter_data['Body']['Data']['PowerReal_P_Phase_3']
- self._dbusservice['/Ac/Energy/Forward'] = meter_data['Body']['Data']['EnergyReal_WAC_Sum_Consumed']
- self._dbusservice['/Ac/Energy/Reverse'] = meter_data['Body']['Data']['EnergyReal_WAC_Sum_Produced']
- logging.info("House Consumption: %s" % (MeterConsumption))
- return True
- def _handlechangedvalue(self, path, value):
- logging.debug("someone else updated %s to %s" % (path, value))
- return True # accept the change
- def main():
- logging.basicConfig(level=logging.INFO)
- from dbus.mainloop.glib import DBusGMainLoop
- # Have a mainloop, so we can send/receive asynchronous calls to and from dbus
- DBusGMainLoop(set_as_default=True)
- pvac_output = DbusDummyService(
- servicename='com.victronenergy.grid',
- deviceinstance=0,
- paths={
- '/Ac/Power': {'initial': 0},
- '/Ac/L1/Voltage': {'initial': 0},
- '/Ac/L2/Voltage': {'initial': 0},
- '/Ac/L3/Voltage': {'initial': 0},
- '/Ac/L1/Current': {'initial': 0},
- '/Ac/L2/Current': {'initial': 0},
- '/Ac/L3/Current': {'initial': 0},
- '/Ac/L1/Power': {'initial': 0},
- '/Ac/L2/Power': {'initial': 0},
- '/Ac/L3/Power': {'initial': 0},
- '/Ac/Energy/Forward': {'initial': 0}, # energy bought from the grid
- '/Ac/Energy/Reverse': {'initial': 0}, # energy sold to the grid
- })
- logging.info('Connected to dbus, and switching over to gobject.MainLoop() (= event based)')
- mainloop = gobject.MainLoop()
- mainloop.run()
- if __name__ == "__main__":
- main()
The script registers itself on dbus as "com.victronenergy.grid" and publishes values as defined on Venus wiki - dbus - Grid meter .
Before I run the script, I have the following situation on the remote console, feeding 3.9 kW to the grid:
When I run the script, I see the following situation on the remote console, as if the AC Loads would consume 3.9 kW:
So, clearly, my script does something. But not what I wanted.
As the next step, I added three paths to the script: "/Ac/L1/Power", "/Ac/L2/Power" and "/Ac/L3/Power" and then it worked. So, the "/Ac/Power" was not enough for Venus to accept the data as valid- it needed power for all three phases separately.
Now the remote console shows:
Final thoughts
So, it is possible to use a Fronius Smart Meter and make Venus see it correctly.
I think this could be useful for other users as well, therefore it now can be found together with some documentation on GitHub: venus.dbus-fronius-smartmeter