Real-time readout APSystems in Domoticz

Real-time readout APSystems in Domoticz

May 1, 2021 34 Door Bjorn Meijer

We have recently become proud owners of solar panels. Because energy consumption has already been tracked in domoticz and am not in favor of different portals/apps to keep track of everything, I also wanted to have the yield of the solar panels displayed in domoticz.

After the supplier had mounted all the panels on the roof and the system was running, I asked if the ECU-R could also be read via domoticz. Unfortunately, this turned out to be shielded. But there was an app (EMA App) and a web portal with which you could read the consumption. Both options resulted in a delay of approximately five minutes. There was also the ECUAPP. By clicking on the side of the router, it broadcasts a WiFi signal for an hour. By connecting your phone/tablet to this WiFi hotspot, you can read the real-time values with the ECUAPP.

on Tweakers.net they would have also found out and a number of smart minds have already been busy reading a large part of the data via a Python script. It should be noted that this only works via WiFi.

A number of Tweakers members use Home Assistant. So the plug-in needs to be (slightly) adjusted so that it can be used for Domoticz.

Install Plugin

In addition to the code below, you also have the plug-in which can be downloaded from Github.

To run the python scripts on the Raspberry Pi Python 3.x to be installed.

#!/usr/bin/env python3 from APSystemsECUR import APSystemsECUR import time import asyncio import urllib.request import urllib.parse import urllib from pprint import pprint ecu_ip = " " sleep = 300 url = ' :8080/json.htm?' semicolon = '\u003B' loop = asyncio.get_event_loop() ecu = APSystemsECUR(ecu_ip) while True: try: data = loop.run_until_complete(ecu.async_query_ecu()) print(data) lifetime_energy = str(data.get('lifetime_energy ')*1000) today_energy_kwh = str(data.get('today_energy')*1000) current_power = str(data.get('current_power')) print('current_power: ' + current_power) generated_energy = (current_power + semicolon + lifetime_energy ) print('output: ' + today_energy_kwh + ';' + current_power) #pwr = .format(today_energy_kwh, current_power) #print('PWR: ' + pwr) print('Today energy [kWh]: ' + today_energy_kwh) if (float (today_energy_kwh) >= 0 or float(current_power) >= 0): getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1606, 'svalue' : (generated_energy)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) print(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') getVars = {'type ' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx': 1610, 'svalue': data.get('timestamp')} webUrl = urllib.request.urlopen(url + urllib .parse.urlencode(getVars)) #print(url + urllib.parse.urlencode(getVars)) #inverter values inverters = data.get('inverters') #count number of inverters Inverter_qty = len(data.get('inverters')) print('Inverter_cnt: ' + str(Inverter_qty)) # loop through all inverters and get the data for i in range(Inverter_qty): Inverter = list(inverters.keys())[i] print('InverterId: ' + Inverter ) InverterOnline = data['inverters'][Inverter]['online'] print('Online: ' + str(InverterOnline)) InverterTemperature = data['inverters'][Inverter]['temperature'] print('Temperature: ' + str(InverterTemperature)) nVoltage = len(data['inverters'][Inverter]['voltage']) nPower = len(data['inverters'][Inverter]['power']) for x in range( nPower): voltage = data['inverters'][Inverter]['voltage'][x] power = data['inverters'][Inverter]['power'][x] print('Power inverter ' + str( i + 1) + ' panel ' + str(x + 1) + ': ' + str(power) + ' W') #upload values to Domoticz for inverter 1 if (i == 0) and (x == 0) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx': 1624, 'svalue': voltage} webUrl = urllib.request.urlopen(url + urllib. parse.urlencode(getVars)) getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1609, 'svalue' : InverterTemperature} webUrl = urllib.request. urlopen(url + urllib.parse.urlencode(getVars)) if (InverterOnline == True) and (voltage != 0) : getVars = { 'type' : 'command', 'param' : 'switchlight', 'idx' : 1607, 'switchcmd': 'On', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) elif (InverterOnline == True) and (voltage == 0) : getVars = { 'type' : 'command', 'param' : 'switchlight', 'idx': 1607, 'switchcmd': 'Off', 'level': 0, 'passcode' : '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) else : getVars = {'type' : 'command', 'param' : 'switchlight', 'idx': 1607, 'switchcmd': 'Off', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) #upload values to Domoticz for inverter 2 if (i == 1) and (x == 0) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1614, 'svalue' : InverterTemperature} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) if (InverterOnline == True) and (voltage != 0) : getVars = { 'type' : 'command', 'param' : 'switchlight ', 'idx': 1611, 'switchcmd': 'On', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) elif ( InverterOnline == True) and (voltage == 0) : getVars = { 'type' : 'command', 'param' : 'switchlight', 'idx': 1611, 'switchcmd': 'Off', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) else : getVars = {'type' : 'command', 'param' : 'switchlight', ' idx': 1611, 'switchcmd': 'Off', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) #upload values to Domoticz for inverter 3 if (i == 2) and (x == 0) : getVars = { 'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1615, 'svalue ': InverterTemperature} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) if (InverterOnline == True) and (voltage != 0) : getVars = {'type' : 'command', ' param' : 'switchlight', 'idx': 1612, 'switchcmd': 'On', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode( getVars)) elif (InverterOnline == True) and (voltage == 0) : getVars = { 'type' : 'command', 'param' : 'switchlight', 'idx' : 1612, 'switchcmd' : 'Off' , 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) else : getVars = {'type' : 'command', 'param' : 'switchlight', 'idx': 1612, 'switchcmd': 'Off', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) #upload values to Domoticz for inverter 4 if (i == 3) and (x == 0) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1616, 'svalue': InverterTemperature} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) if (InverterOnline == True) and (voltage != 0) : getVars = {'type' : 'command', 'param' : 'switchlight', 'idx': 1613, 'switchcmd': 'On', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib .parse.urlencode(getVars)) elif (InverterOnline == True) and (voltage == 0) : getVars = { 'type' : 'command', 'param' : 'switchlight', 'idx' : 1613, 'switchcmd ': 'Off', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars)) else : getVars = {'type' : 'command' , 'param' : 'switchlight', 'idx': 1613, 'switchcmd': 'Off', 'level': 0, 'passcode': '' } webUrl = urllib.request.urlopen(url + urllib.parse. urlencode(getVars)) #upload power values to Domoticz for inverter 1 if (i == 0) and (x == 0) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx': 1608, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 0 ) and (x == 1) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1617, 'svalue' : (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 0) and (x == 2) : getVars = {'type' : 'command' , 'param' : 'udevice', 'nvalue' : 0, 'idx': 198, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon ) + '0') elif (i == 0) and (x == 3) : getVars = { 'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx': 199, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') #upload power values to Domoticz for inverter 2 if (i == 1) and (x == 0) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1618, 'svalue' : (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 1) and (x == 1) : getVars = {'type' : 'command ', 'param' : 'udevice', 'nvalue' : 0, 'idx': 1619, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + ( semicolon) + '0') elif (i == 1) and (x == 2) : getVars = { 'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 202, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 1) and (x == 3) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 203, 'svalue' : (power)} webUrl = urllib.request.urlopen( url + urllib.parse.urlencode(getVars) + (semicolon) + '0') #upload power values to Domoticz for inverter 3 if (i == 2) and (x == 0) : getVars = {'type' : ' command', 'param' : 'udevice', 'nvalue' : 0, 'idx': 1620, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 2) and (x == 1) : getVars = { 'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx ': 1621, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 2) and (x = = 2) : getVars = { 'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 206, 'svalue' : (power)} webUrl = urllib.request.urlopen (url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 2) and (x == 3) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx': 207, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0' ) #upload power values to Domoticz for inverter 4 if (i == 3) and (x == 0) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, ' idx': 1622, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 3) and (x == 1) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 1623, 'svalue' : (power)} webUrl = urllib.request. urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') elif (i == 3) and (x == 2) : getVars = {'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx': 210, 'svalue': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0 ') elif (i == 3) and (x == 3) : getVars = { 'type' : 'command', 'param' : 'udevice', 'nvalue' : 0, 'idx' : 211, 'svalue ': (power)} webUrl = urllib.request.urlopen(url + urllib.parse.urlencode(getVars) + (semicolon) + '0') except Exception as err: print(f"[ERROR]", {err} ) #print(f"Sleeping for {sleep} sec") time.sleep(sleep)
  • Place the plugin and above script in your Domoticz folder under scripts/python/ECU-R.
  • Create a Dummy sensor in Domoticz and call it 'Virtual switches' or another clear name.

Add dummy sensors in Domoticz

Add dummy sensor in Domoticz
Add dummy sensor in Domoticz
  • Create a virtual sensor of the type 'Elektra (Current + counter)'. Name the sensor 'Solar generation'.
Create a virtual sensor for generating solar panels
Create a virtual sensor for generating solar panels
  • Create a virtual sensor of type 'Switch' and name it Inverter [number inverter].
  • Repeat this step for the number of microinverters you have.
Create virtual sensor for APSystem inverter
Create virtual sensor for APSystems inverter
  • Create a virtual sensor of the type 'Consumption (Electric)' and name it Inverter [number inverter] – Power [panel number].
  • Repeat this step for the number of panels per microinverter.
Virtual sensor for generated power inverter
Virtual sensor for generated power inverter
  • Create a virtual sensor of type 'Temperature' and name it Inverter [number inverter] – Temperature.
  • Repeat this step for the number of microinverters you have.
Virtual sensor for temperature display inverter
Virtual sensor for temperature display inverter
  • Create a virtual sensor of type 'Text' and name it Timestamp.
  • Go to 'Devices' and adjust the idx's in the above script to the idx of the virtual sensors you just created and save the script.
  • Start the script with the command python3 /scripts/python/ECU-R/ECU-R.py.
  • To have the script start automatically after every reboot of the Raspberry Pi, add the following line in crontab: @reboot python3 /home/pi/domoticz/scripts/python/ECU-R/ECU-R.py.

Update 25-01-2023

User Sebastiaan Terlouw has slightly modified the script so that it is now also compatible with the DS3 controller.

Update 2/15/2023

Sebastiaan Terlouw has added the mains voltage to the script.