question

RalfZ avatar image

Venus OS driver for Fronius Smart Meter

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

Venus OSFronius
10 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

2 Answers
RalfZ avatar image
RalfZ answered ·

As written above - the issue is closed - it works as intended.

The code together with some documentation on how to install it on a Raspberry Pi with Venus OS is now on GitHub: venus.dbus-fronius-smartmeter

Share
10 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

Daniël Boekel (Victron Energy Staff) avatar image
Daniël Boekel (Victron Energy Staff) answered ·

Hi @RalfZ

You'll need to use a supported grid-meter, like

https://www.victronenergy.com/live/energy-meters:em24

For no-feed in systems, The Fronius Smart Meter cannot be used together with our ESS system, as they will both try to regulate the grid setpoint. (but that's not the case with your system)


https://www.victronenergy.com/live/ac_coupling:fronius

1 comment Share
10 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

I will use the MultiPlus-II in Mode 3, there will be no conflict between the control loops:

  • The Fronius Symo uses the Fronius Smart Meter to limit the power produced by the PV to a level where feed into the grid reaches 70% of PV-Power-peak. (German legal regulation)
  • My Mode 3 control loop will control the battery inverter of the MultiPlus-II in a way that I am reducing the consumption from the grid as much as possible.