mirror of
https://github.com/pommi/python-itho-wpu.git
synced 2024-11-22 14:02:15 +01:00
feat(itho-wpu): get datalog structure from the database
Instead of hardcoding the datalog structure for listversion 11 (my WPU version), get the datalog structure from the database and match that against the result from the getdatatype call. This way all WPU versions that are in the database are automatically supported.
This commit is contained in:
parent
00f098f4e1
commit
96f91cb9d3
90
itho-wpu.py
90
itho-wpu.py
@ -10,6 +10,7 @@ import time
|
|||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import db
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
consolelogformatter = logging.Formatter("%(asctime)-15s %(levelname)s: %(message)s")
|
consolelogformatter = logging.Formatter("%(asctime)-15s %(levelname)s: %(message)s")
|
||||||
@ -175,6 +176,7 @@ class IthoWPU():
|
|||||||
self.cache = IthoWPUCache()
|
self.cache = IthoWPUCache()
|
||||||
self.nodeid = self.get('getnodeid')
|
self.nodeid = self.get('getnodeid')
|
||||||
self.datatype = self.get('getdatatype')
|
self.datatype = self.get('getdatatype')
|
||||||
|
self.heatpump_db = db.sqlite('heatpump.sqlite')
|
||||||
|
|
||||||
def get(self, action):
|
def get(self, action):
|
||||||
if not self.no_cache:
|
if not self.no_cache:
|
||||||
@ -205,6 +207,45 @@ class IthoWPU():
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def get_listversion_from_nodeid(self):
|
||||||
|
if self.nodeid is None:
|
||||||
|
return
|
||||||
|
return int(self.nodeid[10], 0)
|
||||||
|
|
||||||
|
def get_datalog_structure(self):
|
||||||
|
listversion = self.get_listversion_from_nodeid()
|
||||||
|
datalabel_version = self.heatpump_db.execute(
|
||||||
|
f"SELECT datalabel FROM versiebeheer WHERE version = {listversion}")[0]['datalabel']
|
||||||
|
if datalabel_version is None or not type(datalabel_version) == int:
|
||||||
|
logger.error(f"Datalabel not found in database for version {listversion}")
|
||||||
|
return None
|
||||||
|
datalabel = self.heatpump_db.execute(
|
||||||
|
f"SELECT name, title, tooltip, unit FROM datalabel_v{datalabel_version} order by id")
|
||||||
|
|
||||||
|
if len(self.datatype[5:-1]) != len(datalabel):
|
||||||
|
logger.warning(f"Number of datatype items ({len(self.datatype[5:-1])}) is not equal to the number of datalabels ({len(datalabel)}) in the database.")
|
||||||
|
|
||||||
|
Field = namedtuple('Field', 'index type label description')
|
||||||
|
|
||||||
|
datalog = []
|
||||||
|
index = 0
|
||||||
|
for dl, dt in zip(datalabel, self.datatype[5:-1]):
|
||||||
|
description = dl['title'].title()
|
||||||
|
if dl['unit'] is not None:
|
||||||
|
description = f"{description} ({dl['unit']})"
|
||||||
|
datalog.append(Field(index, int(dt, 0), dl['name'].lower(), description))
|
||||||
|
|
||||||
|
if dt in ['0x0', '0xc']:
|
||||||
|
index = index + 1
|
||||||
|
elif dt in ['0x10', '0x12', '0x92']:
|
||||||
|
index = index + 2
|
||||||
|
elif dt in ['0x20']:
|
||||||
|
index = index + 4
|
||||||
|
else:
|
||||||
|
logger.error(f"Unknown data type for label {dl['name']}: {dt}")
|
||||||
|
return datalog
|
||||||
|
return datalog
|
||||||
|
|
||||||
|
|
||||||
class IthoWPUCache:
|
class IthoWPUCache:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -259,7 +300,7 @@ def is_messageclass_valid(action, response):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def process_response(action, response, args):
|
def process_response(action, response, args, wpu):
|
||||||
if int(response[3], 0) != 0x01:
|
if int(response[3], 0) != 0x01:
|
||||||
logger.error(f"Response MessageType != 0x01 (response), but {response[3]}")
|
logger.error(f"Response MessageType != 0x01 (response), but {response[3]}")
|
||||||
return
|
return
|
||||||
@ -267,7 +308,7 @@ def process_response(action, response, args):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if action == "getdatalog":
|
if action == "getdatalog":
|
||||||
measurements = process_datalog(response)
|
measurements = process_datalog(response, wpu)
|
||||||
if args.export_to_influxdb:
|
if args.export_to_influxdb:
|
||||||
export_to_influxdb(action, measurements)
|
export_to_influxdb(action, measurements)
|
||||||
elif action == "getnodeid":
|
elif action == "getnodeid":
|
||||||
@ -302,42 +343,8 @@ def process_serial(response):
|
|||||||
logger.info(f"Serial: {serial}")
|
logger.info(f"Serial: {serial}")
|
||||||
|
|
||||||
|
|
||||||
def process_datalog(response):
|
def process_datalog(response, wpu):
|
||||||
# 0 = Byte
|
datalog = wpu.get_datalog_structure()
|
||||||
# 1 = UnsignedInt
|
|
||||||
# 2 = SignedIntDec2
|
|
||||||
Field = namedtuple('Field', 'index type label description')
|
|
||||||
datalog = [
|
|
||||||
Field(0, 0x92, "t_out", "Buitentemperatuur"),
|
|
||||||
Field(2, 0x92, "t_boiltop", "Boiler laag"),
|
|
||||||
Field(4, 0x92, "t_boildwn", "Boiler hoog"),
|
|
||||||
Field(6, 0x92, "t_evap", "Verdamper temperatuur"),
|
|
||||||
Field(8, 0x92, "t_suct", "Zuiggas temperatuur"),
|
|
||||||
Field(10, 0x92, "t_disc", "Persgas temperatuur"),
|
|
||||||
Field(12, 0x92, "t_cond", "Vloeistof temperatuur"),
|
|
||||||
Field(14, 0x92, "t_source_r", "Naar bron"),
|
|
||||||
Field(16, 0x92, "t_source_s", "Van bron"),
|
|
||||||
Field(18, 0x92, "t_ch_supp", "CV aanvoer"),
|
|
||||||
Field(20, 0x92, "t_ch_ret", "CV retour"),
|
|
||||||
Field(22, 0x92, "p_sens", "Druksensor (Bar)"),
|
|
||||||
Field(24, 0x92, "i_tr1", "Stroom trafo 1 (A)"),
|
|
||||||
Field(26, 0x92, "i_tr2", "Stroom trafo 2 (A)"),
|
|
||||||
Field(34, 0x10, "in_flow", "Flow sensor bron (l/h)"),
|
|
||||||
Field(37, 0x0, "out_ch", "Snelheid cv pomp (%)"),
|
|
||||||
Field(38, 0x0, "out_src", "Snelheid bron pomp (%)"),
|
|
||||||
Field(39, 0x0, "out_dhw", "Snelheid boiler pomp (%)"),
|
|
||||||
Field(44, 0xc, "out_c1", "Compressor aan/uit"),
|
|
||||||
Field(45, 0xc, "out_ele", "Elektrisch element aan/uit"),
|
|
||||||
Field(46, 0xc, "out_trickle", "Trickle heating aan/uit"),
|
|
||||||
Field(47, 0xc, "out_fault", "Fout aanwezig (0=J, 1=N)"),
|
|
||||||
Field(48, 0xc, "out_fc", "Vrijkoelen actief (0=uit, 1=aan)"),
|
|
||||||
Field(51, 0x92, "ot_room", "Kamertemperatuur"),
|
|
||||||
Field(55, 0x0, "ot_mod", "Warmtevraag (%)"),
|
|
||||||
Field(56, 0x0, "state", "State (0=init,1=uit,2=CV,3=boiler,4=vrijkoel,5=ontluchten)"),
|
|
||||||
Field(57, 0x0, "sub_state", "Substatus (255=geen)"),
|
|
||||||
Field(67, 0x0, "fault_reported", "Fout gevonden (foutcode)"),
|
|
||||||
Field(92, 0x10, "tr_fc", "Vrijkoelen interval (sec)"),
|
|
||||||
]
|
|
||||||
message = response[5:]
|
message = response[5:]
|
||||||
measurements = {}
|
measurements = {}
|
||||||
for d in datalog:
|
for d in datalog:
|
||||||
@ -356,6 +363,11 @@ def process_datalog(response):
|
|||||||
if num >= 32768:
|
if num >= 32768:
|
||||||
num -= 65536
|
num -= 65536
|
||||||
num = round(num / 100, 2)
|
num = round(num / 100, 2)
|
||||||
|
elif d.type == 0x20:
|
||||||
|
m = message[d.index:d.index+4]
|
||||||
|
num = ((int(m[0], 0) << 24) + (int(m[1], 0) << 16) + (int(m[2], 0) << 8) + int(m[3], 0))
|
||||||
|
else:
|
||||||
|
logger.error(f"Unknown message type for datalog {d.name}: {d.type}")
|
||||||
logger.info(f"{d.description}: {num}")
|
logger.info(f"{d.description}: {num}")
|
||||||
measurements[d.label] = num
|
measurements[d.label] = num
|
||||||
return measurements
|
return measurements
|
||||||
@ -370,4 +382,4 @@ if __name__ == "__main__":
|
|||||||
wpu = IthoWPU(args.master_only, args.slave_only, args.slave_timeout, args.no_cache)
|
wpu = IthoWPU(args.master_only, args.slave_only, args.slave_timeout, args.no_cache)
|
||||||
response = wpu.get(args.action)
|
response = wpu.get(args.action)
|
||||||
if response is not None:
|
if response is not None:
|
||||||
process_response(args.action, response, args)
|
process_response(args.action, response, args, wpu)
|
||||||
|
Loading…
Reference in New Issue
Block a user