From 063850c7fb148df981a651c36631ac0597cc983f Mon Sep 17 00:00:00 2001 From: Stefan Allius Date: Thu, 30 May 2024 18:38:05 +0200 Subject: [PATCH] add allow and block filter for AT+ commands --- app/config/default_config.toml | 5 +++++ app/src/config.py | 13 +++++++++++-- app/src/gen3plus/solarman_v5.py | 24 ++++++++++++++++++++++++ app/tests/test_config.py | 18 +++++++++++------- app/tests/test_solarman.py | 1 + 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/app/config/default_config.toml b/app/config/default_config.toml index cd95d75..fbe2651 100644 --- a/app/config/default_config.toml +++ b/app/config/default_config.toml @@ -49,3 +49,8 @@ monitor_sn = 2000000000 # The "Monitoring SN:" can be found on a sticker e #pv3 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr #pv4 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr +[gen3plus.at_acl] +tsun.allow = ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'] +tsun.block = [] +mqtt.allow = ['AT+'] +mqtt.block = [] diff --git a/app/src/config.py b/app/src/config.py index eef0c86..e1ef749 100644 --- a/app/src/config.py +++ b/app/src/config.py @@ -3,7 +3,7 @@ import shutil import tomllib import logging -from schema import Schema, And, Use, Optional +from schema import Schema, And, Or, Use, Optional class Config(): @@ -38,6 +38,14 @@ class Config(): 'proxy_node_id': Use(str), 'proxy_unique_id': Use(str) }, + 'gen3plus': { + 'at_acl': { + Or('mqtt', 'tsun'): { + 'allow': [str], + Optional('block', default=[]): [str] + } + } + }, 'inverters': { 'allow_all': Use(bool), And(Use(str), lambda s: len(s) == 16): { Optional('monitor_sn', default=0): Use(int), @@ -125,7 +133,8 @@ class Config(): # merge the default and the user config config = def_config.copy() - for key in ['tsun', 'solarman', 'mqtt', 'ha', 'inverters']: + for key in ['tsun', 'solarman', 'mqtt', 'ha', 'inverters', + 'gen3plus']: if key in usr_config: config[key] |= usr_config[key] diff --git a/app/src/gen3plus/solarman_v5.py b/app/src/gen3plus/solarman_v5.py index 1529057..e3ed438 100644 --- a/app/src/gen3plus/solarman_v5.py +++ b/app/src/gen3plus/solarman_v5.py @@ -91,8 +91,13 @@ class SolarmanV5(Message): # MODbus or AT cmd 0x4510: self.msg_command_req, # from server 0x1510: self.msg_command_rsp, # from inverter + # 0x0510: self.msg_command_rsp, # from inverter } self.modbus_elms = 0 # for unit tests + g3p_cnf = Config.get('gen3plus') + + if 'at_acl' in g3p_cnf: + self.at_acl = g3p_cnf['at_acl'] ''' Our puplic methods @@ -320,9 +325,24 @@ class SolarmanV5(Message): return self.mb.build_msg(Modbus.INV_ADDR, func, addr, val, log_lvl) + def at_cmd_forbidden(self, cmd: str, connection: str) -> bool: + return not cmd.startswith(tuple(self.at_acl[connection]['allow'])) or \ + cmd.startswith(tuple(self.at_acl[connection]['block'])) + async def send_at_cmd(self, AT_cmd: str) -> None: if self.state != self.STATE_UP: return + AT_cmd = AT_cmd.strip() + + if self.at_cmd_forbidden(cmd=AT_cmd, connection='mqtt'): + data_json = f'\'{AT_cmd}\' is forbidden' + node_id = self.node_id + key = 'at_resp' + logger.info(f'{key}: {data_json}') + asyncio.ensure_future( + self.publish_mqtt(f'{self.entity_prfx}{node_id}{key}', data_json)) # noqa: E501 + return + self.forward_at_cmd_resp = False self.__build_header(0x4510) self._send_buffer += struct.pack(f'