diff --git a/README.md b/README.md index 444e800..408c08b 100644 --- a/README.md +++ b/README.md @@ -301,7 +301,7 @@ 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} +#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 diff --git a/app/config/default_config.toml b/app/config/default_config.toml index 57b2baf..f4b9364 100644 --- a/app/config/default_config.toml +++ b/app/config/default_config.toml @@ -149,7 +149,7 @@ 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} +#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 diff --git a/app/src/cnf/config.py b/app/src/cnf/config.py index b3ed188..a8f16db 100644 --- a/app/src/cnf/config.py +++ b/app/src/cnf/config.py @@ -189,6 +189,7 @@ here. The default config reader is handled in the Config.init method''' cls.err = f'error: {error}' logging.error( f"Can't read from {reader.descr()} => error\n {error}") + return cls.err logging.info(f'Read from {reader.descr()} => {res}') return cls.err diff --git a/app/src/cnf/config_read_env.py b/app/src/cnf/config_read_env.py index 693d7cc..2fe96fd 100644 --- a/app/src/cnf/config_read_env.py +++ b/app/src/cnf/config_read_env.py @@ -22,4 +22,4 @@ class ConfigReadEnv(ConfigIfc): return conf def descr(self): - return "Read environment" + return "environment" diff --git a/app/src/modbus_tcp.py b/app/src/modbus_tcp.py index 7d371c9..f74b4a0 100644 --- a/app/src/modbus_tcp.py +++ b/app/src/modbus_tcp.py @@ -49,7 +49,7 @@ class ModbusTcp(): and 'monitor_sn' in inv and 'client_mode' in inv): client = inv['client_mode'] - # logging.info(f"SerialNo:{inv['monitor_sn']} host:{client['host']} port:{client['port']}") # noqa: E501 + logger.info(f"'client_mode' for snr: {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'], diff --git a/app/src/server.py b/app/src/server.py index b386ea2..205e842 100644 --- a/app/src/server.py +++ b/app/src/server.py @@ -142,7 +142,7 @@ def main(): # pragma: no cover parser.add_argument('-t', '--toml_config', type=str, help='read user config from toml-file') parser.add_argument('-l', '--log_path', type=str, - default='log/', + default='./log/', help='set path for the logging files') parser.add_argument('-b', '--log_backups', type=int, default=0, @@ -159,11 +159,15 @@ def main(): # pragma: no cover logging.config.fileConfig('logging.ini') logging.info(f'Server "{serv_name} - {version}" will be started') + logging.info(f'current dir: {os.getcwd()}') logging.info(f"config_path: {args.config_path}") logging.info(f"json_config: {args.json_config}") logging.info(f"toml_config: {args.toml_config}") logging.info(f"log_path: {args.log_path}") - logging.info(f"log_backups: {args.log_backups} days") + if args.log_backups == 0: + logging.info("log_backups: unlimited") + else: + logging.info(f"log_backups: {args.log_backups} days") log_level = get_log_level() logging.info('******') @@ -204,6 +208,7 @@ def main(): # pragma: no cover # and we can't receive and handle the UNIX signals! # for inv_class, port in [(InverterG3, 5005), (InverterG3P, 10000)]: + logging.info(f'listen on port: {port} for inverters') loop.create_task(asyncio.start_server(lambda r, w, i=inv_class: handle_client(r, w, i), '0.0.0.0', port)) diff --git a/app/tests/test_config_read_json.py b/app/tests/test_config_read_json.py index 0fd7b07..696a529 100644 --- a/app/tests/test_config_read_json.py +++ b/app/tests/test_config_read_json.py @@ -195,10 +195,10 @@ def test_cnv4(): "node_id": "PV-Garage/", "suggested_area": "Garage", "modbus_polling": False, - "pv1_manufacturer": "man1", - "pv1_type": "type1", - "pv2_manufacturer": "man2", - "pv2_type": "type2", + "pv1.manufacturer": "man1", + "pv1.type": "type1", + "pv2.manufacturer": "man2", + "pv2.type": "type2", "sensor_list": 688 }, { @@ -207,16 +207,17 @@ def test_cnv4(): "node_id": "PV-Garage2/", "suggested_area": "Garage2", "modbus_polling": True, - "client_mode_host": "InverterIP", - "client_mode_port": 1234, - "pv1_manufacturer": "man1", - "pv1_type": "type1", - "pv2_manufacturer": "man2", - "pv2_type": "type2", - "pv3_manufacturer": "man3", - "pv3_type": "type3", - "pv4_manufacturer": "man4", - "pv4_type": "type4", + "client_mode.host": "InverterIP", + "client_mode.port": 1234, + "client_mode.forward": True, + "pv1.manufacturer": "man1", + "pv1.type": "type1", + "pv2.manufacturer": "man2", + "pv2.type": "type2", + "pv3.manufacturer": "man3", + "pv3.type": "type3", + "pv4.manufacturer": "man4", + "pv4.type": "type4", "sensor_list": 688 } ], @@ -247,25 +248,33 @@ def test_cnv4(): 'block': ['AT+SUPDATE']}}}, 'inverters': {'R170000000000001': {'modbus_polling': False, 'node_id': 'PV-Garage/', - 'pv1_manufacturer': 'man1', - 'pv1_type': 'type1', - 'pv2_manufacturer': 'man2', - 'pv2_type': 'type2', + 'pv1': { + 'manufacturer': 'man1', + 'type': 'type1'}, + 'pv2': { + 'manufacturer': 'man2', + 'type': 'type2'}, 'sensor_list': 688, 'suggested_area': 'Garage'}, - 'Y170000000000001': {'client_mode_host': 'InverterIP', - 'client_mode_port': 1234, + 'Y170000000000001': {'client_mode': { + 'host': 'InverterIP', + 'port': 1234, + 'forward': True}, 'modbus_polling': True, 'monitor_sn': 2000000000, 'node_id': 'PV-Garage2/', - 'pv1_manufacturer': 'man1', - 'pv1_type': 'type1', - 'pv2_manufacturer': 'man2', - 'pv2_type': 'type2', - 'pv3_manufacturer': 'man3', - 'pv3_type': 'type3', - 'pv4_manufacturer': 'man4', - 'pv4_type': 'type4', + 'pv1': { + 'manufacturer': 'man1', + 'type': 'type1'}, + 'pv2': { + 'manufacturer': 'man2', + 'type': 'type2'}, + 'pv3': { + 'manufacturer': 'man3', + 'type': 'type3'}, + 'pv4': { + 'manufacturer': 'man4', + 'type': 'type4'}, 'sensor_list': 688, 'suggested_area': 'Garage2'}, 'allow_all': False}, @@ -362,8 +371,6 @@ def test_full_config(ConfigComplete): "node_id": "PV-Garage2/", "suggested_area": "Garage2", "modbus_polling": true, - "client_mode_host": "InverterIP", - "client_mode_port": 1234, "pv1.manufacturer": "man1", "pv1.type": "type1", "pv2.manufacturer": "man2", diff --git a/ha_addons/Makefile b/ha_addons/Makefile index ea948ca..b52954c 100644 --- a/ha_addons/Makefile +++ b/ha_addons/Makefile @@ -105,15 +105,17 @@ FORCE : ; INST=$(INST_BASE)/ha_addon_dev repro_files = DOCS.md icon.png logo.png translations/de.yaml translations/en.yaml +repro_root = CHANGELOG.md repro_templates = config.yaml repro_subdirs = translations repro_vers = debug dev rel repro_all_files := $(foreach dir,$(repro_vers), $(foreach file,$(repro_files),$(INST_BASE)/ha_addon_$(dir)/$(file))) +repro_root_files := $(foreach dir,$(repro_vers), $(foreach file,$(repro_root),$(INST_BASE)/ha_addon_$(dir)/$(file))) repro_all_templates := $(foreach dir,$(repro_vers), $(foreach file,$(repro_templates),$(INST_BASE)/ha_addon_$(dir)/$(file))) repro_all_subdirs := $(foreach dir,$(repro_vers), $(foreach file,$(repro_subdirs),$(INST_BASE)/ha_addon_$(dir)/$(file))) -repro: $(repro_all_subdirs) $(repro_all_templates) $(repro_all_files) +repro: $(repro_all_subdirs) $(repro_all_templates) $(repro_all_files) $(repro_root_files) $(repro_all_subdirs) : mkdir -p $@ @@ -121,6 +123,8 @@ $(repro_all_subdirs) : $(repro_all_templates) : $(INST_BASE)/ha_addon_%/config.yaml: $(TEMPL)/config.jinja $(TEMPL)/%_data.json $(SRC)/.version $(JINJA) --strict -D AppVersion=$(VERSION) $< $(filter %.json,$^) -o $@ +$(repro_root_files) : %/CHANGELOG.md : ../CHANGELOG.md + cp $< $@ $(filter $(INST_BASE)/ha_addon_debug/%,$(repro_all_files)) : $(INST_BASE)/ha_addon_debug/% : ha_addon/% cp $< $@ diff --git a/ha_addons/ha_addon/DOCS.md b/ha_addons/ha_addon/DOCS.md index 310c54a..cce376c 100644 --- a/ha_addons/ha_addon/DOCS.md +++ b/ha_addons/ha_addon/DOCS.md @@ -71,6 +71,9 @@ inverters: node_id: PV-Garage suggested_area: Garage modbus_polling: true + client_mode.host: 192.168.x.x + client_mode.port: 8899 + client_mode.forward: true pv1.manufacturer: Shinefar pv1.type: SF-M18/144550 pv2.manufacturer: Shinefar @@ -83,6 +86,8 @@ inverters: **Note**: _This is just an example, you need to replace the values with your own!_ +more information about the configuration can be found in the [configuration details page][configdetails]. + ## MQTT settings By default, this add-on requires no `mqtt` config from the user. **This is not an error!** @@ -154,3 +159,4 @@ SOFTWARE. [AdGuard]: https://github.com/hassio-addons/addon-adguard-home [repository-badge]: https://img.shields.io/badge/Add%20repository%20to%20my-Home%20Assistant-41BDF5?logo=home-assistant&style=for-the-badge [repository-url]: https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Fs-allius%2Fha-addons +[configdetails]: https://github.com/s-allius/tsun-gen3-proxy/wiki/Configuration-details diff --git a/ha_addons/ha_addon/translations/de.yaml b/ha_addons/ha_addon/translations/de.yaml index 57a6959..cf48599 100755 --- a/ha_addons/ha_addon/translations/de.yaml +++ b/ha_addons/ha_addon/translations/de.yaml @@ -5,83 +5,91 @@ configuration: description: >+ Für jeden Wechselrichter muss die Seriennummer des Wechselrichters einer MQTT Definition zugeordnet werden. Dazu wird der entsprechende Konfigurationsblock mit der - <16-stellige Seriennummer> gestartet, so dass alle nachfolgenden Parameter diesem - Wechselricher zugeordnet sind. + 16-stellige Seriennummer gestartet, so dass alle nachfolgenden Parameter diesem + Wechselrichter zugeordnet sind. Weitere wechselrichterspezifische Parameter (z.B. Polling Mode) können im Konfigurationsblock gesetzt werden. - Die Seriennummer der GEN3 Wechselrichter beginnne mit `R17` und die der GEN3PLUS + Die Seriennummer der GEN3 Wechselrichter beginnen mit `R17` und die der GEN3PLUS Wechselrichter mir `Y17`oder `47`! - monitor_sn # Die GEN3PLUS "Monitoring SN:" - node_id # MQTT-Ersatz für die Seriennummer des Wechselrichters - suggested_area # Vorgeschlagener Installationsbereich für Home-Assistant - modbus_polling # Optionale MODBUS-Polling deaktivieren - pv1 # Optional, PV Module Beschreibung - pv2 # Optional, PV Module Beschreibung + Siehe Beispielkonfiguration im Dokumentations-Tab tsun.enabled: name: Verbindung zur TSUN Cloud - nur für GEN3-Wechselrichter - description: >- - switch on/off connection to the TSUN cloud - This connection is only required if you want send data to the TSUN cloud - eg. to use the TSUN APPs or receive firmware updates. + description: >+ + Schaltet die Verbindung zur TSUN Cloud ein/aus. + Diese Verbindung ist erforderlich, wenn Sie Daten an die TSUN Cloud senden möchten, + z.B. um die TSUN-Apps zu nutzen oder Firmware-Updates zu erhalten. - on - normal proxy operation - off - The Inverter become isolated from Internet + ein => normaler Proxy-Betrieb. + aus => Der Wechselrichter wird vom Internet isoliert. solarman.enabled: - name: Connection to Solarman Cloud - for GEN3PLUS inverter only - description: >- - switch on/off connection to the Solarman cloud - This connection is only required if you want send data to the Solarman cloud - eg. to use the Solarman APPs or receive firmware updates. + name: Verbindung zur Solarman Cloud - nur für GEN3PLUS Wechselrichter + description: >+ + Schaltet die Verbindung zur Solarman Cloud ein/aus. + Diese Verbindung ist erforderlich, wenn Sie Daten an die Solarman Cloud senden möchten, + z.B. um die Solarman Apps zu nutzen oder Firmware-Updates zu erhalten. - on - normal proxy operation - off - The Inverter become isolated from Internet + ein => normaler Proxy-Betrieb. + aus => Der Wechselrichter wird vom Internet isoliert. inverters.allow_all: - name: Allow all connections from all inverters + name: Erlaube Verbindungen von sämtlichen Wechselrichtern description: >- - The proxy only usually accepts connections from known inverters. - Switch on for test purposes and unknown serial numbers. + Der Proxy akzeptiert normalerweise nur Verbindungen von konfigurierten Wechselrichtern. + Schalten Sie dies für Testzwecke und unbekannte Seriennummern ein. mqtt.host: name: MQTT Broker Host description: >- - Hostname or IP address of the MQTT broker. if not set, the addon will try to connect to the Home Assistant MQTT broker + Hostname oder IP-Adresse des MQTT-Brokers. Wenn nicht gesetzt, versucht das Addon, eine Verbindung zum Home Assistant MQTT-Broker herzustellen. mqtt.port: name: MQTT Broker Port description: >- - Port of the MQTT broker. if not set, the addon will try to connect to the Home Assistant MQTT broker + Port des MQTT-Brokers. Wenn nicht gesetzt, versucht das Addon, eine Verbindung zum Home Assistant MQTT-Broker herzustellen. mqtt.user: - name: MQTT Broker User + name: MQTT Broker Benutzer description: >- - User for the MQTT broker. if not set, the addon will try to connect to the Home Assistant MQTT broker + Benutzer für den MQTT-Broker. Wenn nicht gesetzt, versucht das Addon, eine Verbindung zum Home Assistant MQTT-Broker herzustellen. mqtt.passwd: - name: MQTT Broker Password + name: MQTT Broker Passwort description: >- - Password for the MQTT broker. if not set, the addon will try to connect to the Home Assistant MQTT broker + Passwort für den MQTT-Broker. Wenn nicht gesetzt, versucht das Addon, eine Verbindung zum Home Assistant MQTT-Broker herzustellen. ha.auto_conf_prefix: - name: MQTT prefix for subscribing for homeassistant status updates + name: MQTT-Präfix für das Abonnieren von Home Assistant-Statusaktualisierungen ha.discovery_prefix: - name: MQTT prefix for discovery topic + name: MQTT-Präfix für das discovery topic ha.entity_prefix: - name: MQTT topic prefix for publishing inverter values + name: MQTT-Themenpräfix für die Veröffentlichung von Wechselrichterwerten ha.proxy_node_id: - name: MQTT node id, for the proxy_node_id + name: MQTT-Knoten-ID für die proxy_node_id ha.proxy_unique_id: - name: MQTT unique id, to identify a proxy instance + name: MQTT-eindeutige ID zur Identifizierung einer Proxy-Instanz tsun.host: name: TSUN Cloud Host description: >- - Hostname or IP address of the TSUN cloud. if not set, the addon will try to connect to the cloud default - on logger.talent-monitoring.com + Hostname oder IP-Adresse der TSUN-Cloud. Wenn nicht gesetzt, versucht das Addon, eine Verbindung zur Cloud logger.talent-monitoring.com herzustellen. solarman.host: name: Solarman Cloud Host description: >- - Hostname or IP address of the Solarman cloud. if not set, the addon will try to connect to the cloud default - on iot.talent-monitoring.com + Hostname oder IP-Adresse der Solarman-Cloud. Wenn nicht gesetzt, versucht das Addon, eine Verbindung zur Cloud iot.talent-monitoring.com herzustellen. + gen3plus.at_acl.tsun.allow: + name: TSUN GEN3PLUS ACL allow + description: >- + Liste erlaubter AT-Befehle für TSUN GEN3PLUS + gen3plus.at_acl.tsun.block: + name: TSUN GEN3 ACL block + description: >- + Liste blockierter AT-Befehle für TSUN GEN3PLUS + gen3plus.at_acl.mqtt.allow: + name: MQTT GEN3PLUS ACL allow + description: >- + Liste erlaubter MQTT-Befehle für GEN3PLUS + gen3plus.at_acl.mqtt.block: + name: MQTT GEN3PLUS ACL block + description: >- + Liste blockierter MQTT-Befehle für GEN3PLUS network: - 8127/tcp: x... - 5005/tcp: listening Port for TSUN GEN3 Devices - 10000/tcp: listening Port for TSUN GEN3PLUS Devices + 5005/tcp: listening Port für TSUN GEN3 Wechselrichter + 10000/tcp: listening Port für TSUN GEN3PLUS Wechselrichter diff --git a/ha_addons/ha_addon/translations/en.yaml b/ha_addons/ha_addon/translations/en.yaml index b6025d8..42d01da 100755 --- a/ha_addons/ha_addon/translations/en.yaml +++ b/ha_addons/ha_addon/translations/en.yaml @@ -5,42 +5,37 @@ configuration: description: >+ 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 - <16-digit serial number> so that all subsequent parameters are assigned + 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 The serial numbers of all GEN3 inverters start with `R17` and that of the GEN3PLUS inverters with ‘Y17’ or ‘47’! - - monitor_sn # The GEN3PLUS "Monitoring SN:" - node_id # MQTT replacement for inverters serial number - suggested_area # suggested installation area for home-assistant - modbus_polling # Disable optional MODBUS polling - pv1 # Optional, PV module descr - pv2 # Optional, PV module descr + + For reference see example configuration in Documentation Tab tsun.enabled: name: Connection to TSUN Cloud - for GEN3 inverter only - description: >- - switch on/off connection to the TSUN cloud + description: >+ + switch on/off connection to the TSUN cloud. This connection is only required if you want send data to the TSUN cloud eg. to use the TSUN APPs or receive firmware updates. - on - normal proxy operation - off - The Inverter become isolated from Internet + on => normal proxy operation. + off => The Inverter become isolated from Internet. solarman.enabled: name: Connection to Solarman Cloud - for GEN3PLUS inverter only - description: >- - switch on/off connection to the Solarman cloud + description: >+ + switch on/off connection to the Solarman cloud. This connection is only required if you want send data to the Solarman cloud eg. to use the Solarman APPs or receive firmware updates. - on - normal proxy operation - off - The Inverter become isolated from Internet + on => normal proxy operation. + off => The Inverter become isolated from Internet inverters.allow_all: name: Allow all connections from all inverters description: >- - The proxy only usually accepts connections from known inverters. + The proxy only usually accepts connections from configured inverters. Switch on for test purposes and unknown serial numbers. mqtt.host: name: MQTT Broker Host @@ -71,16 +66,30 @@ configuration: tsun.host: name: TSUN Cloud Host description: >- - Hostname or IP address of the TSUN cloud. if not set, the addon will try to connect to the cloud default + Hostname or IP address of the TSUN cloud. if not set, the addon will try to connect to the cloud on logger.talent-monitoring.com solarman.host: name: Solarman Cloud Host description: >- - Hostname or IP address of the Solarman cloud. if not set, the addon will try to connect to the cloud default + Hostname or IP address of the Solarman cloud. if not set, the addon will try to connect to the cloud on iot.talent-monitoring.com - + gen3plus.at_acl.tsun.allow: + name: TSUN GEN3PLUS ACL allow + description: >- + List of allowed TSUN GEN3PLUS AT commands + gen3plus.at_acl.tsun.block: + name: TSUN GEN3 ACL block + description: >- + List of blocked TSUN GEN3PLUS AT commands + gen3plus.at_acl.mqtt.allow: + name: MQTT GEN3PLUS ACL allow + description: >- + List of allowed MQTT GEN3PLUS commands + gen3plus.at_acl.mqtt.block: + name: MQTT GEN3PLUS ACL block + description: >- + List of blocked MQTT GEN3PLUS commands network: - 8127/tcp: x... 5005/tcp: listening Port for TSUN GEN3 Devices 10000/tcp: listening Port for TSUN GEN3PLUS Devices diff --git a/ha_addons/templates/config.jinja b/ha_addons/templates/config.jinja index b8d40c4..646f6ac 100755 --- a/ha_addons/templates/config.jinja +++ b/ha_addons/templates/config.jinja @@ -39,8 +39,9 @@ schema: node_id: str suggested_area: str modbus_polling: bool - client_mode_host: str? - client_mode_port: int? + client_mode.host: str? + client_mode.port: int? + client_mode.forward: bool? #strings: # leider funktioniert es nicht die folgenden 3 parameter im schema aufzulisten. möglicherweise wird die verschachtelung nicht unterstützt. # - string: str # type: str