parse gen3plus inverter data
This commit is contained in:
@@ -122,7 +122,6 @@ class InfosG3(Infos):
|
||||
info_id = RegisterMap.map[addr]
|
||||
data_type = result[1]
|
||||
ind += 5
|
||||
keys, level, unit, must_incr, new_val = self._key_obj(info_id)
|
||||
|
||||
if data_type == 0x54: # 'T' -> Pascal-String
|
||||
str_len = buf[ind]
|
||||
@@ -132,26 +131,18 @@ class InfosG3(Infos):
|
||||
ind += str_len+1
|
||||
|
||||
elif data_type == 0x49: # 'I' -> int32
|
||||
# if new_val:
|
||||
# struct.pack_into('!l', buf, ind, new_val)
|
||||
result = struct.unpack_from('!l', buf, ind)[0]
|
||||
ind += 4
|
||||
|
||||
elif data_type == 0x53: # 'S' -> short
|
||||
# if new_val:
|
||||
# struct.pack_into('!h', buf, ind, new_val)
|
||||
result = struct.unpack_from('!h', buf, ind)[0]
|
||||
ind += 2
|
||||
|
||||
elif data_type == 0x46: # 'F' -> float32
|
||||
# if new_val:
|
||||
# struct.pack_into('!f', buf, ind, new_val)
|
||||
result = round(struct.unpack_from('!f', buf, ind)[0], 2)
|
||||
ind += 4
|
||||
|
||||
elif data_type == 0x4c: # 'L' -> int64
|
||||
# if new_val:
|
||||
# struct.pack_into('!q', buf, ind, new_val)
|
||||
result = struct.unpack_from('!q', buf, ind)[0]
|
||||
ind += 8
|
||||
|
||||
@@ -161,31 +152,14 @@ class InfosG3(Infos):
|
||||
" not supported")
|
||||
return
|
||||
|
||||
keys, level, unit, must_incr, new_val = self._key_obj(info_id)
|
||||
|
||||
if keys:
|
||||
dict = self.db
|
||||
name = ''
|
||||
|
||||
for key in keys[:-1]:
|
||||
if key not in dict:
|
||||
dict[key] = {}
|
||||
dict = dict[key]
|
||||
name += key + '.'
|
||||
|
||||
if keys[-1] not in dict:
|
||||
update = (not must_incr or result > 0)
|
||||
else:
|
||||
if must_incr:
|
||||
update = dict[keys[-1]] < result
|
||||
else:
|
||||
update = dict[keys[-1]] != result
|
||||
|
||||
if update:
|
||||
dict[keys[-1]] = result
|
||||
name += keys[-1]
|
||||
name, update = self.update_db(keys, must_incr, result)
|
||||
yield keys[0], update
|
||||
else:
|
||||
update = False
|
||||
name = str(f'info-id.0x{info_id:x}')
|
||||
name = str(f'info-id.0x{addr:x}')
|
||||
|
||||
self.tracer.log(level, f'{name} : {result}{unit}'
|
||||
f' update: {update}')
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
import struct
|
||||
import logging
|
||||
from typing import Generator
|
||||
|
||||
if __name__ == "app.src.gen3plus.infos_g3p":
|
||||
@@ -10,9 +9,59 @@ else: # pragma: no cover
|
||||
|
||||
|
||||
class RegisterMap:
|
||||
# make the class read/only by using __slots__
|
||||
|
||||
# __slots__ = ()
|
||||
map = {
|
||||
0x00092ba8: Register.COLLECTOR_FW_VERSION,
|
||||
0x00d2: {'reg': Register.GRID_VOLTAGE, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00d4: {'reg': Register.GRID_CURRENT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x00d6: {'reg': Register.GRID_FREQUENCY, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x00d8: {'reg': Register.INVERTER_TEMP, 'fmt': '!H', 'ratio': 1}, # noqa: E501
|
||||
0x00dc: {'reg': Register.RATED_POWER, 'fmt': '!H', 'ratio': 1}, # noqa: E501
|
||||
0x00de: {'reg': Register.OUTPUT_POWER, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00e0: {'reg': Register.PV1_VOLTAGE, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00e2: {'reg': Register.PV1_CURRENT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x00e4: {'reg': Register.PV1_POWER, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00e6: {'reg': Register.PV2_VOLTAGE, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00e8: {'reg': Register.PV2_CURRENT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x00ea: {'reg': Register.PV2_POWER, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00ec: {'reg': Register.PV3_VOLTAGE, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00ee: {'reg': Register.PV3_CURRENT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x00f0: {'reg': Register.PV3_POWER, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00f2: {'reg': Register.PV4_VOLTAGE, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00f4: {'reg': Register.PV4_CURRENT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x00f6: {'reg': Register.PV4_POWER, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501
|
||||
0x00f8: {'reg': Register.DAILY_GENERATION, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x00fa: {'reg': Register.TOTAL_GENERATION, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
|
||||
0x00fe: {'reg': Register.PV1_DAILY_GENERATION, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x0100: {'reg': Register.PV1_TOTAL_GENERATION, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
|
||||
0x0104: {'reg': Register.PV2_DAILY_GENERATION, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x0106: {'reg': Register.PV2_TOTAL_GENERATION, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
|
||||
0x010a: {'reg': Register.PV3_DAILY_GENERATION, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x010c: {'reg': Register.PV3_TOTAL_GENERATION, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
|
||||
0x0110: {'reg': Register.PV4_DAILY_GENERATION, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x0112: {'reg': Register.PV4_TOTAL_GENERATION, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
|
||||
}
|
||||
'''
|
||||
COMMUNICATION_TYPE = 400
|
||||
SIGNAL_STRENGTH = 401
|
||||
POWER_ON_TIME = 402
|
||||
COLLECT_INTERVAL = 403
|
||||
DATA_UP_INTERVAL = 404
|
||||
CONNECT_COUNT = 405
|
||||
|
||||
COLLECTOR_FW_VERSION = 1
|
||||
CHIP_TYPE = 2
|
||||
CHIP_MODEL = 3
|
||||
TRACE_URL = 4
|
||||
LOGGER_URL = 5
|
||||
PRODUCT_NAME = 20
|
||||
MANUFACTURER = 21
|
||||
VERSION = 22
|
||||
SERIAL_NUMBER = 23
|
||||
EQUIPMENT_MODEL = 24
|
||||
NO_INPUTS = 25
|
||||
'''
|
||||
|
||||
|
||||
class InfosG3P(Infos):
|
||||
@@ -28,8 +77,9 @@ class InfosG3P(Infos):
|
||||
entity strings
|
||||
sug_area:str ==> suggested area string from the config file'''
|
||||
# iterate over RegisterMap.map and get the register values
|
||||
for reg in RegisterMap.map.values():
|
||||
res = self.ha_conf(reg, ha_prfx, node_id, snr, False, sug_area) # noqa: E501
|
||||
for row in RegisterMap.map.values():
|
||||
info_id = row['reg']
|
||||
res = self.ha_conf(info_id, ha_prfx, node_id, snr, False, sug_area) # noqa: E501
|
||||
if res:
|
||||
yield res
|
||||
|
||||
@@ -38,85 +88,28 @@ class InfosG3P(Infos):
|
||||
stores the values in Infos.db
|
||||
|
||||
buf: buffer of the sequence to parse'''
|
||||
result = struct.unpack_from('!l', buf, ind)
|
||||
elms = result[0]
|
||||
i = 0
|
||||
ind += 4
|
||||
while i < elms:
|
||||
result = struct.unpack_from('!lB', buf, ind)
|
||||
info_id = result[0]
|
||||
data_type = result[1]
|
||||
ind += 5
|
||||
for addr, row in RegisterMap.map.items():
|
||||
if isinstance(row, dict):
|
||||
info_id = row['reg']
|
||||
fmt = row['fmt']
|
||||
res = struct.unpack_from(fmt, buf, addr)
|
||||
result = res[0]
|
||||
if 'ratio' in row:
|
||||
ratio = row['ratio']
|
||||
result *= ratio
|
||||
|
||||
keys, level, unit, must_incr, new_val = self._key_obj(info_id)
|
||||
|
||||
if data_type == 0x54: # 'T' -> Pascal-String
|
||||
str_len = buf[ind]
|
||||
result = struct.unpack_from(f'!{str_len+1}p', buf,
|
||||
ind)[0].decode(encoding='ascii',
|
||||
errors='replace')
|
||||
ind += str_len+1
|
||||
|
||||
elif data_type == 0x49: # 'I' -> int32
|
||||
# if new_val:
|
||||
# struct.pack_into('!l', buf, ind, new_val)
|
||||
result = struct.unpack_from('!l', buf, ind)[0]
|
||||
ind += 4
|
||||
|
||||
elif data_type == 0x53: # 'S' -> short
|
||||
# if new_val:
|
||||
# struct.pack_into('!h', buf, ind, new_val)
|
||||
result = struct.unpack_from('!h', buf, ind)[0]
|
||||
ind += 2
|
||||
|
||||
elif data_type == 0x46: # 'F' -> float32
|
||||
# if new_val:
|
||||
# struct.pack_into('!f', buf, ind, new_val)
|
||||
result = round(struct.unpack_from('!f', buf, ind)[0], 2)
|
||||
ind += 4
|
||||
|
||||
elif data_type == 0x4c: # 'L' -> int64
|
||||
# if new_val:
|
||||
# struct.pack_into('!q', buf, ind, new_val)
|
||||
result = struct.unpack_from('!q', buf, ind)[0]
|
||||
ind += 8
|
||||
|
||||
else:
|
||||
self.inc_counter('Invalid_Data_Type')
|
||||
logging.error(f"Infos.parse: data_type: {data_type}"
|
||||
" not supported")
|
||||
return
|
||||
|
||||
if keys:
|
||||
dict = self.db
|
||||
name = ''
|
||||
|
||||
for key in keys[:-1]:
|
||||
if key not in dict:
|
||||
dict[key] = {}
|
||||
dict = dict[key]
|
||||
name += key + '.'
|
||||
|
||||
if keys[-1] not in dict:
|
||||
update = (not must_incr or result > 0)
|
||||
else:
|
||||
if must_incr:
|
||||
update = dict[keys[-1]] < result
|
||||
else:
|
||||
update = dict[keys[-1]] != result
|
||||
|
||||
if update:
|
||||
dict[keys[-1]] = result
|
||||
name += keys[-1]
|
||||
name, update = self.update_db(keys, must_incr, result)
|
||||
yield keys[0], update
|
||||
else:
|
||||
name = str(f'info-id.0x{addr:x}')
|
||||
update = False
|
||||
name = str(f'info-id.0x{info_id:x}')
|
||||
|
||||
self.tracer.log(level, f'{name} : {result}{unit}'
|
||||
f' update: {update}')
|
||||
|
||||
i += 1
|
||||
|
||||
def ignore_this_device(self, dep: dict) -> bool:
|
||||
'''Checks the equation in the dep dict
|
||||
|
||||
|
||||
@@ -277,6 +277,8 @@ class SolarmanV5(Message):
|
||||
logger.info(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}')
|
||||
|
||||
if (ftype == 1):
|
||||
self.__process_data()
|
||||
|
||||
result = struct.unpack_from('!HH', data, 0xdc)
|
||||
rated = result[0]/1
|
||||
actual = result[1]/10
|
||||
@@ -300,6 +302,11 @@ class SolarmanV5(Message):
|
||||
|
||||
self.forward(self._recv_buffer, self.header_len+self.data_len+2)
|
||||
|
||||
def __process_data(self):
|
||||
for key, update in self.db.parse(self._recv_buffer, 0):
|
||||
if update:
|
||||
self.new_data[key] = True
|
||||
|
||||
def msg_data_rsp(self):
|
||||
self.msg_response()
|
||||
|
||||
|
||||
@@ -402,3 +402,23 @@ class Infos:
|
||||
# new_val = d['new_value']
|
||||
|
||||
return d['name'], d['level'], d['unit'], must_incr, new_val
|
||||
|
||||
def update_db(self, keys, must_incr, result):
|
||||
name = ''
|
||||
dict = self.db
|
||||
for key in keys[:-1]:
|
||||
if key not in dict:
|
||||
dict[key] = {}
|
||||
dict = dict[key]
|
||||
name += key + '.'
|
||||
if keys[-1] not in dict:
|
||||
update = (not must_incr or result > 0)
|
||||
else:
|
||||
if must_incr:
|
||||
update = dict[keys[-1]] < result
|
||||
else:
|
||||
update = dict[keys[-1]] != result
|
||||
if update:
|
||||
dict[keys[-1]] = result
|
||||
name += keys[-1]
|
||||
return name, update
|
||||
|
||||
Reference in New Issue
Block a user