Domoticz metertjes
Ik kon tot dusver niets vinden over Domoticz integratie voor Zendure, en overstappen op HA via Docker vond ik nog iets teveel gedoe voor nu. Eigenlijk wil ik alleen meten.
Aangezien de API open is, is het uitlezen eigenlijk vrij eenvoudig. Stappenplan:
- Maak in Domoticz een virtual P1 Smart Meter (Electic) aan. De Smart Meter widget is handig, aangezien laden en ontladen worden samengenomen
- Evenzo een Percentage en een Temperature
- Kopiëer onderstaand Python script, en vul zowel het IP van de Zendure als de ELEC_IDX, PERC_IDX en TEMP_IDX van de gecreëerde virtual meters.
- Start het script met python3, en kijk of het werkt

Het script doet grofweg hetvolgende:
- Leest bij de start de huidige meterstanden uit Domoticz
- Vervolgens:
- Leest elke 5 seconden het rapport van de omvormer uit
- Pakt de actuele vermogens
- Rekent het verbruik uit over de tijd
- Leest de lading en temperatuur van de accupacks uit
- Schrijft deze naar de metertjes
Consensus die ik heb aangehouden: positief vermogen = verbruiker (ofwel de accu laadt), negatief = terugleveren (ontladen). Tarief 1 = de netkant, Tarief 2 = de offgrid socket.
Die laatste vind ik nog wel lastig om goed mee te nemen. Als de accu vol is, dan wordt de offgrid gebruik in de netafname geregistreerd (wat technisch juist is), terwijl anderzijds de accu zou ontladen (dus teruglevering). Als iemand hier wat beters weet hoor ik het wel. Ik heb zelf de intentie om de offgrid alleen in nood te gebruiken.
Verder pak ik nu de temperatuur en lading van beide accus zelf (socLevel, maxTemp) ipv de samenvattende (electricLevel, hyperTmp). De acculading kan duidelijk beiden, maar qua temperatuur is deze 2981 en 2911, accus en voor de behuizing (hyperTmp) 3041 geeft. Ook middelen, of de hoogste van de drie laten zien?
Enfin, als alles werkt, heb je zoiets
Wat goed overeenkomt met de Zendure app:
/f/image/IVugYncREzjWOcBmlNCKxizz.png?f=fotoalbum_large)
(Perfect eigenlijk mits je gelijktijdig een screenshot neemt én het script niet herstart voor de handleiding hier

)
Dit is dus alleen uitlezen, en dat is prima zo voor mij. Binnen Domoticz kun je deze input dan weer gebruiken voor verdere aansturing. De accu behoort het sluitstuk te zijn, en met NOM reageert hij prima op alle andere dingen die in huis gebeuren.
Ben je tevreden, stop dan het script en maakt het een service. Voor een Raspberry Pi gaat dat zo:
code: /etc/systemd/system/zendure_accu.service
1
2
3
4
5
6
7
8
9
| [Unit]
Description=Start Zendure battery meter script at Startup
After=domoticz.service
[Service]
ExecStart=/home/ZWARTOOG/scripts/zendure_accu.py
[Install]
WantedBy=multi-user.target |
En dan:
Bash:
1
2
3
4
5
6
| sudo chmod a+x /home/ZWARTOOG/scripts/zendure_accu.py
sudo chmod 664 /etc/systemd/system/zendure_accu.service
sudo systemctl daemon-reload
sudo systemctl enable zendure_accu.service
sudo systemctl start zendure_accu.service
sudo service zendure_accu start |
Wat hierboven gebeurd is dat je er een service van maakt, die pas start nadat domoticz is gestart. Ook wordt de boottime start gezet, zodat hij bij een reboot automatisch opstart.
Het script is overigens sterk gebaseerd op een kWh meterscript van @
klump4u 
Python: zendure_accu.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
| #!/usr/bin/env python3
import time
import json
import urllib3
from urllib.request import urlopen
import threading
import logging
import logging.handlers
ZENDURE_URL = 'http://192.168.1.123/properties/report'
ELEC_IDX = 156
PERC_IDX = 177
TEMP_IDX = 178
GET_URL = 'http://localhost:8080/json.htm?type=command¶m=getdevices&rid=%d'
SET_URL = 'http://localhost:8080/json.htm?type=command¶m=udevice&idx=%d&nvalue=0&svalue=%d;%d;%d;%d;%d;%d'
SET_URL_GENERIC = 'http://localhost:8080/json.htm?type=command¶m=udevice&idx=%d&nvalue=0&svalue=%d'
syslog = logging.handlers.SysLogHandler(address='/dev/log', facility='local1')
syslog.setFormatter(logging.Formatter('zendure_accu.py: %(levelname)s %(message)s'))
logging.getLogger().addHandler(syslog)
logging.getLogger().setLevel(logging.INFO)
logging.info('Started, measuring Zendure thuisaccu')
# Here we wait until Domoticz is started
while True:
try:
res = json.load(urlopen(GET_URL % ELEC_IDX))
if res['status'] != 'OK':
raise Exception('Error reading Zendure')
logging.info('Read current meter start data as: ' + res['result'][0]['Data'])
currentMeters = res['result'][0]['Data'].split(';');
# Read current values
consumptionInput = float(currentMeters[0]);
offGridInput = float(currentMeters[1]);
consumptionOutput = float(currentMeters[2]);
offGridOutput = float(currentMeters[3]);
logging.info('Read current meter start data: Home Output %f, Home Input %f, Grid Output %f, Grid Input %f' % (consumptionOutput , consumptionInput , offGridOutput , offGridInput));
break
except Exception as e:
logging.warning( e )
time.sleep(30.0)
while True:
TIME_PREV = time.time();
try:
time.sleep(5)
# Read values from Zendure
values = json.load(urlopen(ZENDURE_URL))
outputPower = float(values['properties']['outputHomePower']);
inputPower = float(values['properties']['gridInputPower']);
offGridOutputPower = float(values['properties']['gridOffPower']);
offGridInputPower = float(values['properties']['solarInputPower']);
TIME_NOW = time.time();
TIME_ELAP = TIME_NOW - TIME_PREV;
consumptionInput += inputPower*TIME_ELAP/3600; # Charging battery - tariff 1
consumptionOutput += outputPower*TIME_ELAP/3600; # Discharging battery - tariff 1
offGridInput += offGridInputPower*TIME_ELAP/3600; # Charging battery - tariff 2
offGridOutput += offGridOutputPower*TIME_ELAP/3600; # Discharging battery - tariff 2
# Average state of charge and temperature over the battery pack
currentSoC = 0;
currentTemp = 0;
for batteryIdx in range(0, len(values['packData'])):
currentSoC += float(values['packData'][batteryIdx]['socLevel'])/len(values['packData']);
currentTemp += float(values['packData'][batteryIdx]['maxTemp'] - 2731)/len(values['packData'])/10.0;
TIME_PREV = TIME_NOW
# Update counters
try:
res = json.load(urlopen((SET_URL) % (ELEC_IDX, int(consumptionInput), int(offGridInput), int(consumptionOutput), int(offGridOutput), int(inputPower), int(outputPower))))
if res['status'] != 'OK':
raise Exception('Domoticz json error')
logging.info('Zendure accu usage %d %d' % (int(inputPower), int(outputPower) ) )
res = json.load(urlopen((SET_URL_GENERIC) % (PERC_IDX, int(currentSoC) )));
if res['status'] != 'OK':
raise Exception('Domoticz json error')
logging.info('Zendure accu SoC level %d ' % int(currentSoC) )
res = json.load(urlopen((SET_URL_GENERIC) % (TEMP_IDX, currentTemp )));
if res['status'] != 'OK':
raise Exception('Domoticz json error')
logging.info('Zendure accu temperature %d ' % currentTemp )
except Exception as e:
logging.warning( e )
except Exception as e:
logging.warning( e ) |
Have fun