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:
Stefan Allius
2025-02-24 22:39:34 +01:00
committed by GitHub
parent 1f0ac97368
commit 036dd6d1dc
24 changed files with 691 additions and 132 deletions

View File

@@ -78,7 +78,8 @@ class Config():
}
},
'inverters': {
'allow_all': Use(bool), And(Use(str), lambda s: len(s) == 16): {
'allow_all': Use(bool),
And(Use(str), lambda s: len(s) == 16): {
Optional('monitor_sn', default=0): Use(int),
Optional('node_id', default=""): And(Use(str),
Use(lambda s: s + '/'
@@ -93,7 +94,7 @@ class Config():
},
Optional('modbus_polling', default=True): Use(bool),
Optional('suggested_area', default=""): Use(str),
Optional('sensor_list', default=0x2b0): Use(int),
Optional('sensor_list', default=0): Use(int),
Optional('pv1'): {
Optional('type'): Use(str),
Optional('manufacturer'): Use(str),
@@ -119,6 +120,33 @@ class Config():
Optional('manufacturer'): Use(str),
}
}
},
'batteries': {
And(Use(str), lambda s: len(s) == 16): {
Optional('monitor_sn', default=0): Use(int),
Optional('node_id', default=""): And(Use(str),
Use(lambda s: s + '/'
if len(s) > 0
and s[-1] != '/'
else s)),
Optional('client_mode'): {
'host': Use(str),
Optional('port', default=8899):
And(Use(int), lambda n: 1024 <= n <= 65535),
Optional('forward', default=False): Use(bool),
},
Optional('modbus_polling', default=True): Use(bool),
Optional('suggested_area', default=""): Use(str),
Optional('sensor_list', default=0): Use(int),
Optional('pv1'): {
Optional('type'): Use(str),
Optional('manufacturer'): Use(str),
},
Optional('pv2'): {
Optional('type'): Use(str),
Optional('manufacturer'): Use(str),
}
}
}
}, ignore_extra_keys=True
)
@@ -178,7 +206,7 @@ here. The default config reader is handled in the Config.init method'''
rd_config = reader.get_config()
config = cls.act_config.copy()
for key in ['tsun', 'solarman', 'mqtt', 'ha', 'inverters',
'gen3plus']:
'gen3plus', 'batteries']:
if key in rd_config:
config[key] = config[key] | rd_config[key]

View File

@@ -31,7 +31,8 @@ class ConfigReadJson(ConfigIfc):
def convert_to_obj(self, data):
conf = {}
for key, val in data.items():
if key == 'inverters' and isinstance(val, list):
if (key == 'inverters' or key == 'batteries') and \
isinstance(val, list):
self.convert_inv_arr(conf, key, val)
else:
self._extend_key(conf, key, val)

View File

@@ -113,7 +113,7 @@ inverters.allow_all = false # only allow known inverters
##
## For each GEN3 inverter, the serial number of the inverter must be mapped to an MQTT
## definition. To do this, the corresponding configuration block is started with
## `[Inverter.“<16-digit serial number>”]` so that all subsequent parameters are assigned
## `[inverters.“<16-digit serial number>”]` so that all subsequent parameters are assigned
## to this inverter. Further inverter-specific parameters (e.g. polling mode) can be set
## in the configuration block
##
@@ -132,7 +132,7 @@ pv2 = {type = 'RSM40-8-395M', manufacturer = 'Risen'} # Optional, PV module de
##
## For each GEN3PLUS inverter, the serial number of the inverter must be mapped to an MQTT
## definition. To do this, the corresponding configuration block is started with
## `[Inverter.“<16-digit serial number>”]` so that all subsequent parameters are assigned
## `[inverters.“<16-digit serial number>”]` so that all subsequent parameters are assigned
## to this inverter. Further inverter-specific parameters (e.g. polling mode, client mode)
## can be set in the configuration block
##
@@ -157,6 +157,33 @@ pv3 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module de
pv4 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr
##########################################################################################
##
## For each GEN3PLUS enrgy storage system, the serial number must be mapped to an MQTT
## definition. To do this, the corresponding configuration block is started with
## `[batteries.“<16-digit serial number>”]` so that all subsequent parameters are assigned
## to this energy storage system. Further device-specific parameters (e.g. polling mode,
## client mode) can be set in the configuration block
##
## The serial numbers of all GEN3PLUS energy storage systems/batteries start with `410`!
## Each GEN3PLUS device is supplied with a “Monitoring SN:”. This can be found on a
## sticker enclosed with the inverter.
##
[batteries."4100000000000001"]
monitor_sn = 3000000000 # The GEN3PLUS "Monitoring SN:"
node_id = '' # MQTT replacement for devices serial number
suggested_area = '' # suggested installation place for home-assistant
modbus_polling = true # Enable optional MODBUS polling
# if your inverter supports SSL connections you must use the client_mode. Pls, uncomment
# the next line and configure the fixed IP of your inverter
#client_mode = {host = '192.168.0.1', port = 8899, forward = true}
pv1 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr
pv2 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr
##########################################################################################
###
### If the proxy mode is configured, commands from TSUN can be sent to the inverter via

View File

@@ -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

View File

@@ -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 \

View File

@@ -121,6 +121,32 @@ class Register(Enum):
TS_INPUT = 600
TS_GRID = 601
TS_TOTAL = 602
BATT_PV1_VOLT = 1000
BATT_PV1_CUR = 1001
BATT_PV2_VOLT = 1002
BATT_PV2_CUR = 1003
BATT_38 = 1004
BATT_3a = 1005
BATT_3c = 1006
BATT_3e = 1007
BATT_40 = 1010
BATT_42 = 1011
BATT_SOC = 1012
BATT_46 = 1013
BATT_48 = 1014
BATT_4a = 1015
BATT_4c = 1016
BATT_4e = 1017
BATT_66 = 1018
BATT_68 = 1019
BATT_6a = 1020
BATT_6c = 1021
BATT_6e = 1022
BATT_70 = 1023
BATT_72 = 1024
BATT_74 = 1025
BATT_76 = 1026
BATT_78 = 1027
VALUE_1 = 9000
TEST_REG1 = 10000
TEST_REG2 = 10001
@@ -266,6 +292,7 @@ class Infos:
__info_devs = {
'proxy': {'singleton': True, 'name': 'Proxy', 'mf': 'Stefan Allius'}, # noqa: E501
'controller': {'via': 'proxy', 'name': 'Controller', 'mdl': Register.CHIP_MODEL, 'mf': Register.CHIP_TYPE, 'sw': Register.COLLECTOR_FW_VERSION, 'mac': Register.MAC_ADDR, 'sn': Register.COLLECTOR_SNR}, # noqa: E501
'inverter': {'via': 'controller', 'name': 'Micro Inverter', 'mdl': Register.EQUIPMENT_MODEL, 'mf': Register.MANUFACTURER, 'sw': Register.VERSION, 'sn': Register.SERIAL_NUMBER}, # noqa: E501
'input_pv1': {'via': 'inverter', 'name': 'Module PV1', 'mdl': Register.PV1_MODEL, 'mf': Register.PV1_MANUFACTURER}, # noqa: E501
'input_pv2': {'via': 'inverter', 'name': 'Module PV2', 'mdl': Register.PV2_MODEL, 'mf': Register.PV2_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 2}}, # noqa: E501
@@ -273,6 +300,10 @@ class Infos:
'input_pv4': {'via': 'inverter', 'name': 'Module PV4', 'mdl': Register.PV4_MODEL, 'mf': Register.PV4_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 4}}, # noqa: E501
'input_pv5': {'via': 'inverter', 'name': 'Module PV5', 'mdl': Register.PV5_MODEL, 'mf': Register.PV5_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 5}}, # noqa: E501
'input_pv6': {'via': 'inverter', 'name': 'Module PV6', 'mdl': Register.PV6_MODEL, 'mf': Register.PV6_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 6}}, # noqa: E501
'batterie': {'via': 'controller', 'name': 'Batterie', 'mdl': Register.EQUIPMENT_MODEL, 'mf': Register.MANUFACTURER, 'sw': Register.VERSION, 'sn': Register.SERIAL_NUMBER}, # noqa: E501
'bat_inp_pv1': {'via': 'batterie', 'name': 'Module PV1', 'mdl': Register.PV1_MODEL, 'mf': Register.PV1_MANUFACTURER}, # noqa: E501
'bat_inp_pv2': {'via': 'batterie', 'name': 'Module PV2', 'mdl': Register.PV2_MODEL, 'mf': Register.PV2_MANUFACTURER}, # noqa: E501
}
__comm_type_val_tpl = "{%set com_types = ['n/a','Wi-Fi', 'G4', 'G5', 'GPRS'] %}{{com_types[value_json['Communication_Type']|int(0)]|default(value_json['Communication_Type'])}}" # noqa: E501
@@ -518,15 +549,15 @@ class Infos:
Register.TOTAL_GENERATION: {'name': ['total', 'Total_Generation'], 'level': logging.INFO, 'unit': 'kWh', 'ha': {'dev': 'inverter', 'dev_cla': 'energy', 'stat_cla': 'total', 'id': 'total_gen_', 'fmt': FMT_FLOAT, 'name': TOTAL_GEN, 'icon': SOLAR_POWER, 'must_incr': True}}, # noqa: E501
# controller:
Register.SIGNAL_STRENGTH: {'name': ['controller', 'Signal_Strength'], 'level': logging.DEBUG, 'unit': '%', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'signal_', 'fmt': FMT_INT, 'name': 'Signal Strength', 'icon': WIFI}}, # noqa: E501
Register.POWER_ON_TIME: {'name': ['controller', 'Power_On_Time'], 'level': logging.DEBUG, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': 'duration', 'stat_cla': 'measurement', 'id': 'power_on_time_', 'fmt': FMT_INT, 'name': 'Power on Time', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.COLLECT_INTERVAL: {'name': ['controller', 'Collect_Interval'], 'level': logging.DEBUG, 'unit': 'min', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'data_collect_intval_', 'fmt': '| string + " min"', 'name': 'Data Collect Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.CONNECT_COUNT: {'name': ['controller', 'Connect_Count'], 'level': logging.DEBUG, 'unit': '', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'connect_count_', 'fmt': FMT_INT, 'name': 'Connect Count', 'icon': COUNTER, 'comp': 'sensor', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.COMMUNICATION_TYPE: {'name': ['controller', 'Communication_Type'], 'level': logging.DEBUG, 'unit': '', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'comm_type_', 'name': 'Communication Type', 'val_tpl': __comm_type_val_tpl, 'comp': 'sensor', 'icon': WIFI}}, # noqa: E501
Register.DATA_UP_INTERVAL: {'name': ['controller', 'Data_Up_Interval'], 'level': logging.DEBUG, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'data_up_intval_', 'fmt': FMT_STRING_SEC, 'name': 'Data Up Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.HEARTBEAT_INTERVAL: {'name': ['controller', 'Heartbeat_Interval'], 'level': logging.DEBUG, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'heartbeat_intval_', 'fmt': FMT_STRING_SEC, 'name': 'Heartbeat Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.IP_ADDRESS: {'name': ['controller', 'IP_Address'], 'level': logging.DEBUG, 'unit': '', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'ip_address_', 'fmt': '| string', 'name': 'IP Address', 'icon': WIFI, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.POLLING_INTERVAL: {'name': ['controller', 'Polling_Interval'], 'level': logging.DEBUG, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'polling_intval_', 'fmt': FMT_STRING_SEC, 'name': 'Polling Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.SIGNAL_STRENGTH: {'name': ['controller', 'Signal_Strength'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'signal_', 'fmt': FMT_INT, 'name': 'Signal Strength', 'icon': WIFI}}, # noqa: E501
Register.POWER_ON_TIME: {'name': ['controller', 'Power_On_Time'], 'level': logging.INFO, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': 'duration', 'stat_cla': 'measurement', 'id': 'power_on_time_', 'fmt': FMT_INT, 'name': 'Power on Time', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.COLLECT_INTERVAL: {'name': ['controller', 'Collect_Interval'], 'level': logging.INFO, 'unit': 'min', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'data_collect_intval_', 'fmt': '| string + " min"', 'name': 'Data Collect Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.CONNECT_COUNT: {'name': ['controller', 'Connect_Count'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'connect_count_', 'fmt': FMT_INT, 'name': 'Connect Count', 'icon': COUNTER, 'comp': 'sensor', 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.COMMUNICATION_TYPE: {'name': ['controller', 'Communication_Type'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'comm_type_', 'name': 'Communication Type', 'val_tpl': __comm_type_val_tpl, 'comp': 'sensor', 'icon': WIFI}}, # noqa: E501
Register.DATA_UP_INTERVAL: {'name': ['controller', 'Data_Up_Interval'], 'level': logging.INFO, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'data_up_intval_', 'fmt': FMT_STRING_SEC, 'name': 'Data Up Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.HEARTBEAT_INTERVAL: {'name': ['controller', 'Heartbeat_Interval'], 'level': logging.INFO, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'heartbeat_intval_', 'fmt': FMT_STRING_SEC, 'name': 'Heartbeat Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.IP_ADDRESS: {'name': ['controller', 'IP_Address'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'ip_address_', 'fmt': '| string', 'name': 'IP Address', 'icon': WIFI, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.POLLING_INTERVAL: {'name': ['controller', 'Polling_Interval'], 'level': logging.INFO, 'unit': 's', 'ha': {'dev': 'controller', 'dev_cla': None, 'stat_cla': None, 'id': 'polling_intval_', 'fmt': FMT_STRING_SEC, 'name': 'Polling Interval', 'icon': UPDATE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.SENSOR_LIST: {'name': ['controller', 'Sensor_List'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
Register.SSID: {'name': ['controller', 'WiFi_SSID'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
@@ -536,6 +567,33 @@ class Infos:
Register.PROD_COMPL_TYPE: {'name': ['other', 'Prod_Compliance_Type'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
Register.INV_UNKNOWN_1: {'name': ['inv_unknown', 'Unknown_1'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
Register.BATT_PV1_VOLT: {'name': ['batterie', 'pv1', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'bat_inp_pv1', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_pv1_', 'val_tpl': "{{ (value_json['pv1']['Voltage'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV1_CUR: {'name': ['batterie', 'pv1', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'bat_inp_pv1', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_pv1_', 'val_tpl': "{{ (value_json['pv1']['Current'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV2_VOLT: {'name': ['batterie', 'pv2', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_pv2_', 'val_tpl': "{{ (value_json['pv2']['Voltage'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_PV2_CUR: {'name': ['batterie', 'pv2', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_pv2_', 'val_tpl': "{{ (value_json['pv2']['Current'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_38: {'name': ['batterie', 'Reg_38'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_38_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_3a: {'name': ['batterie', 'Reg_3a'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_3a_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_3c: {'name': ['batterie', 'Reg_3c'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_3c_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_3e: {'name': ['batterie', 'Reg_3e'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_3e_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_40: {'name': ['batterie', 'Reg_40'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_40_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_42: {'name': ['batterie', 'Reg_42'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_42_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_SOC: {'name': ['batterie', 'SOC'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'batterie', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'soc_', 'fmt': FMT_FLOAT, 'name': 'State of Charge', 'icon': 'mdi:battery-90'}}, # noqa: E501
# Register.BATT_46: {'name': ['batterie', 'Reg_46'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_46_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
# Register.BATT_48: {'name': ['batterie', 'Reg_48'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_48_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
# Register.BATT_4a: {'name': ['batterie', 'Reg_4a'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_4a_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
# Register.BATT_4c: {'name': ['batterie', 'Reg_4c'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_4c_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
# Register.BATT_4e: {'name': ['batterie', 'Reg_4e'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_4e_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_66: {'name': ['batterie', 'Reg_66'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_66_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_68: {'name': ['batterie', 'Reg_68'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_68_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_6a: {'name': ['batterie', 'Reg_6a'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_6a_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_6c: {'name': ['batterie', 'Reg_6c'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_6c_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_6e: {'name': ['batterie', 'Reg_6e'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_6e_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_70: {'name': ['batterie', 'Reg_70'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_70_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_72: {'name': ['batterie', 'Reg_72'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_72_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_74: {'name': ['batterie', 'Reg_74'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_74_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_76: {'name': ['batterie', 'Reg_76'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_76_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
Register.BATT_78: {'name': ['batterie', 'Reg_78'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_78_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
}
@property

View File

@@ -151,6 +151,8 @@ class InverterBase(InverterIfc, Proxy):
# home assistant has changed the status back to online
try:
if (('inverter' in stream.new_data and stream.new_data['inverter'])
or ('batterie' in stream.new_data and
stream.new_data['batterie'])
or ('collector' in stream.new_data and
stream.new_data['collector'])
or self.mqtt.ha_restarts != self.__ha_restarts):

View File

@@ -1,6 +1,7 @@
import logging
import traceback
import asyncio
from itertools import chain
from cnf.config import Config
from gen3plus.inverter_g3p import InverterG3P
@@ -42,14 +43,15 @@ class ModbusTcp():
self.tim_restart = tim_restart
inverters = Config.get('inverters')
batteries = Config.get('batteries')
# logging.info(f'Inverters: {inverters}')
for inv in inverters.values():
for _, inv in chain(inverters.items(), batteries.items()):
if (type(inv) is dict
and 'monitor_sn' in inv
and 'client_mode' in inv):
client = inv['client_mode']
logger.info(f"'client_mode' for snr: {inv['monitor_sn']} host: {client['host']}:{client['port']}, forward: {client['forward']}") # noqa: E501
logger.info(f"'client_mode' for Monitoring-SN: {inv['monitor_sn']} host: {client['host']}:{client['port']}, forward: {client['forward']}") # noqa: E501
loop.create_task(self.modbus_loop(client['host'],
client['port'],
inv['monitor_sn'],

View File

@@ -1,6 +1,7 @@
import asyncio
import logging
import json
from itertools import chain
from cnf.config import Config
from mqtt import Mqtt
@@ -56,8 +57,9 @@ class Proxy():
# reset at midnight when you restart the proxy just before
# midnight!
inverters = Config.get('inverters')
batteries = Config.get('batteries')
# logger.debug(f'Proxys: {inverters}')
for inv in inverters.values():
for _, inv in chain(inverters.items(), batteries.items()):
if (type(inv) is dict):
node_id = inv['node_id']
cls.db_stat.reg_clr_at_midnight(f'{cls.entity_prfx}{node_id}',