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