So i’ve been looking around to have solar data inside HA without using cloud api from APSystems. The newer versions of the ECU-R dont have a webinterface anymore, so that was no longer an option. Together with some other folks, I first started to trace the data pull from their own ECU app, which normally only connects when the local WIFI SSID is enabled.
This showed it pulled binary data over TCP layer on port 8899. After some time we found most bytes to be usefull and i created a first python script to fetch and output for HA consumption.
Please bear with me, I have no dev skills at all, so what you see is dirty as it can be. I’m hoping for some support here to clean this up and maybe even a dev can pick it to make it an official integration.
import socket
import struct
import binascii
import json
import datetime
from struct import unpack
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.1.xx", 8899 ))
# datasend = bytes.fromhex('41505331313030323830303032323136303030303631373238454E440A')
mystring ='APS1100280002216000061728END'
datasend = mystring.encode('utf-8')
s.send(datasend)
dataecu = s.recv(1024)
#dataecu = bytes.fromhex('415053313130313736303030323030303100072020112412051040800009401601303101f3006f001400e4001400e440800009562201303101f3006f001300e4001400e440800009182601303101f3006f001400e3001400e340800009293301303101f3006f001400e3001300e340800009191301303101f3006f001500e3001400e340800009243401303101f3006f001400e3001400e340800009184001303101f3006f001400e2001400e2454e440a')
# print (dataecu)
s = binascii.b2a_hex (dataecu)
timestamp = str(s[38:52])
# print (timestamp)
inverterid1 = str(s[52:64])
#print (inverterid1)
inverterid1online = str(bool(s[64:66]))
#print (inverterid1online)
something1 = str(int(s[66:68],16))
something2 = str(int(s[68:70],16))
#print (something1 +" " + something2)
inverterid1freq = str(int(s[70:74],16)/10)
#print (inverterid1freq + " Hz")
inverterid1temp = str(int(s[76:78],16)-100)
# print (inverterid1temp + " C")
inverterid1powerA = str(int(s[78:82],16))
# print (inverterid1powerA + " Watt")
inverterid1volt = str(int(s[82:86],16))
# print (inverterid1volt + " V")
inverterid1powerB = str(int(s[86:90],16))
# print (inverterid1powerB + " Watt")
# f = open("/home/pi/PI/.homeassistant/custom_components/ecudata.txt", "a")
print("{ \"Time\": \"" + timestamp + "\", \"inv1\": \"" + inverterid1 + "\", \"inv1on\": \"" + inverterid1online + "\", \"inv1freq\": \"" + inverterid1freq + "\", \"inv1temp\": \"" + inverterid1temp + "\", \"inv1powerA\": \"" + inverterid1powerA +"\", \"inv1volt\": \""+ inverterid1volt + "\", \"inv1powerB\": \"" + inverterid1powerB + "\"} ")
So above will kind of output a json thing (cant really call it json nor object :-)).
This is just for one inverter, i have 7, so I can repeat this for each inverter, as bytes are repeated for other inverters in next parts of hex stream.
in HA some templates
- platform: command_line
name: ECUDataInverter1
command: "python3 /home/pi/PI/.homeassistant/custom_components/apsinv1.py"
scan_interval: 240
command_timeout: 5
json_attributes:
- Time
- inv1
- inv1powerA
- inv1powerB
- inv1volt
- inv1temp
and templates to make right sensors:
sensors:
ecu_inverter_1_powera:
value_template: '{{ states.sensor.ecudatainverter1.attributes["inv1powerA"] | float }}'
unit_of_measurement: 'W'
ecu_inverter_1_powerb:
value_template: '{{ states.sensor.ecudatainverter1.attributes["inv1powerB"] | float }}'
unit_of_measurement: 'W'
ecu_inverter_1_temp:
value_template: '{{ states.sensor.ecudatainverter1.attributes["inv1temp"] | float }}'
unit_of_measurement: 'C'
note, the Temperature is wrong, still need to fix this.
Resulting in frontend thing like:
So, happy so far with Proof of Concept. But things could be improved:
- query IP adress to fetch ECU id, so no need for hardcoding
- based on response of command, it also tells the number of inverters present, so this could help to loop and fetch all inverter data
- output as real json (way above my grade)
- handle ‘no update’ scenario as only a new timestamp would give new data
- create real HA integration component would be very nice
anyone to share thoughts or chip in, i’m open for suggestions