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