S allius/issue281 (#282)
* accept DCU serial number starting with '410' * determine sensor-list by serial number * adapt unit test for DCU support * send first batterie measurements to home assistant * add test case for sensor-list==3036 * add more registers for batteries * improve error logging (Monitoring SN) * update the add-on repro only for one stage * add configuration for energie storages * add License and Readme file to the add-on * addon: add date and time to dev and debug docker container tag * disable duplicate code check for config.py * cleanup unit test, remove trailing whitespaces * update changelog * fix example config for batteries * cleanup config.jinja template * fix comments * improve help texts
This commit is contained in:
@@ -116,6 +116,33 @@ class RegisterMap:
|
||||
0x4201000c: {'reg': Register.SENSOR_LIST, 'fmt': '<H', 'func': Fmt.hex4}, # noqa: E501
|
||||
0x4201001c: {'reg': Register.POWER_ON_TIME, 'fmt': '<H', 'ratio': 1, 'dep': ProxyMode.SERVER}, # noqa: E501, or packet number
|
||||
0x42010020: {'reg': Register.SERIAL_NUMBER, 'fmt': '!16s'}, # noqa: E501
|
||||
0x42010030: {'reg': Register.BATT_PV1_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 voltage
|
||||
0x42010032: {'reg': Register.BATT_PV1_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 current
|
||||
0x42010034: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 voltage
|
||||
0x42010036: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 current
|
||||
0x42010038: {'reg': Register.BATT_38, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201003a: {'reg': Register.BATT_3a, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201003c: {'reg': Register.BATT_3c, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201003e: {'reg': Register.BATT_3e, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010040: {'reg': Register.BATT_40, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x42010042: {'reg': Register.BATT_42, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x42010044: {'reg': Register.BATT_SOC, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, state of charge (SOC) in percent
|
||||
0x42010046: {'reg': Register.BATT_46, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010048: {'reg': Register.BATT_48, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201004a: {'reg': Register.BATT_4a, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201004c: {'reg': Register.BATT_4c, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201004e: {'reg': Register.BATT_4e, 'fmt': '!h'}, # noqa: E501
|
||||
|
||||
0x42010066: {'reg': Register.BATT_66, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010068: {'reg': Register.BATT_68, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201006a: {'reg': Register.BATT_6a, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201006c: {'reg': Register.BATT_6c, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201006e: {'reg': Register.BATT_6e, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010070: {'reg': Register.BATT_70, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010072: {'reg': Register.BATT_72, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010074: {'reg': Register.BATT_74, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010076: {'reg': Register.BATT_76, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010078: {'reg': Register.BATT_78, 'fmt': '!h'}, # noqa: E501
|
||||
}
|
||||
|
||||
|
||||
@@ -162,9 +189,15 @@ 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 _, row in chain(RegisterMap.map.items(),
|
||||
RegisterMap.map_02b0.items(),
|
||||
RegisterMap.map_3026.items()):
|
||||
sensor = self.get_db_value(Register.SENSOR_LIST)
|
||||
if "3026" == sensor:
|
||||
items = RegisterMap.map_3026.items()
|
||||
elif "02b0" == sensor:
|
||||
items = RegisterMap.map_02b0.items()
|
||||
else:
|
||||
items = {}
|
||||
|
||||
for _, row in chain(RegisterMap.map.items(), items):
|
||||
info_id = row['reg']
|
||||
if self.__hide_topic(row):
|
||||
res = self.ha_remove(info_id, node_id, snr) # noqa: E501
|
||||
|
||||
@@ -2,6 +2,7 @@ import struct
|
||||
import logging
|
||||
import time
|
||||
import asyncio
|
||||
from itertools import chain
|
||||
from datetime import datetime
|
||||
|
||||
from async_ifc import AsyncIfc
|
||||
@@ -376,12 +377,23 @@ class SolarmanV5(SolarmanBase):
|
||||
self.ifc.fwd_add(build_msg)
|
||||
self.ifc.fwd_add(struct.pack('<BB', 0, 0x15)) # crc & stop
|
||||
|
||||
def __set_config_parms(self, inv: dict):
|
||||
def __set_config_parms(self, inv: dict, serial_no: str):
|
||||
'''init connection with params from the configuration'''
|
||||
self.node_id = inv['node_id']
|
||||
self.sug_area = inv['suggested_area']
|
||||
self.modbus_polling = inv['modbus_polling']
|
||||
self.sensor_list = inv['sensor_list']
|
||||
if 0 == self.sensor_list:
|
||||
snr = serial_no[:3]
|
||||
if '410' == snr:
|
||||
self.sensor_list = 0x3026
|
||||
else:
|
||||
self.sensor_list = 0x02b0
|
||||
self.db.set_db_def_value(Register.SENSOR_LIST,
|
||||
f"{self.sensor_list:04x}")
|
||||
logging.debug(f"Use sensor-list: {self.sensor_list:#04x}"
|
||||
f" for '{serial_no}'")
|
||||
|
||||
if self.mb:
|
||||
self.mb.set_node_id(self.node_id)
|
||||
|
||||
@@ -392,13 +404,14 @@ class SolarmanV5(SolarmanBase):
|
||||
logger.debug(f'SerialNo: {serial_no}')
|
||||
else:
|
||||
inverters = Config.get('inverters')
|
||||
batteries = Config.get('batteries')
|
||||
# logger.debug(f'Inverters: {inverters}')
|
||||
|
||||
for key, inv in inverters.items():
|
||||
for key, inv in chain(inverters.items(), batteries.items()):
|
||||
# logger.debug(f'key: {key} -> {inv}')
|
||||
if (type(inv) is dict and 'monitor_sn' in inv
|
||||
and inv['monitor_sn'] == snr):
|
||||
self.__set_config_parms(inv)
|
||||
self.__set_config_parms(inv, key)
|
||||
self.db.set_pv_module_details(inv)
|
||||
logger.debug(f'SerialNo {serial_no} allowed! area:{self.sug_area}') # noqa: E501
|
||||
|
||||
@@ -411,9 +424,11 @@ class SolarmanV5(SolarmanBase):
|
||||
if 'allow_all' not in inverters or not inverters['allow_all']:
|
||||
self.inc_counter('Unknown_SNR')
|
||||
self.unique_id = None
|
||||
logger.warning(f'ignore message from unknow inverter! (SerialNo: {serial_no})') # noqa: E501
|
||||
logging.error(f"Ignore message from unknow inverter with Monitoring-SN: {serial_no})!\n" # noqa: E501
|
||||
" !!Check the 'monitor_sn' setting in your configuration!!") # noqa: E501
|
||||
return
|
||||
logger.warning(f'SerialNo {serial_no} not known but accepted!')
|
||||
logging.warning(f"Monitoring-SN: {serial_no} not configured but accepted!" # noqa: E501
|
||||
" !!Check the 'monitor_sn' setting in your configuration!!") # noqa: E501
|
||||
|
||||
self.unique_id = serial_no
|
||||
|
||||
@@ -460,11 +475,11 @@ class SolarmanV5(SolarmanBase):
|
||||
def mb_timout_cb(self, exp_cnt):
|
||||
self.mb_timer.start(self.mb_timeout)
|
||||
|
||||
self._send_modbus_cmd(Modbus.READ_REGS, 0x3000, 48, logging.DEBUG)
|
||||
self._send_modbus_cmd(Modbus.READ_REGS, 0x3000, 48, logging.INFO)
|
||||
|
||||
if 1 == (exp_cnt % 30):
|
||||
# logging.info("Regular Modbus Status request")
|
||||
self._send_modbus_cmd(Modbus.READ_REGS, 0x2000, 96, logging.DEBUG)
|
||||
self._send_modbus_cmd(Modbus.READ_REGS, 0x2000, 96, logging.INFO)
|
||||
|
||||
def at_cmd_forbidden(self, cmd: str, connection: str) -> bool:
|
||||
return not cmd.startswith(tuple(self.at_acl[connection]['allow'])) or \
|
||||
|
||||
Reference in New Issue
Block a user