Merge branch 'dev-0.8.0' into s-allius/issue77
This commit is contained in:
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- trace heartbeat and regular modbus pakets witl log level DEBUG
|
- trace heartbeat and regular modbus pakets witl log level DEBUG
|
||||||
- GEN3PLUS: don't forward ack paket from tsun to the inverter
|
- GEN3PLUS: don't forward ack paket from tsun to the inverter
|
||||||
|
- add allow and block filter for AT+ commands
|
||||||
- catch all OSError errors in the read loop
|
- catch all OSError errors in the read loop
|
||||||
- log Modbus traces with different log levels
|
- log Modbus traces with different log levels
|
||||||
- add Modbus fifo and timeout handler
|
- add Modbus fifo and timeout handler
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -47,7 +47,9 @@ If you use a Pi-hole, you can also store the host entry in the Pi-hole.
|
|||||||
- `AT-Command` support via MQTT topics (GEN3PLUS only)
|
- `AT-Command` support via MQTT topics (GEN3PLUS only)
|
||||||
- Faster DataUp interval sends measurement data to the MQTT broker every minute
|
- Faster DataUp interval sends measurement data to the MQTT broker every minute
|
||||||
- Self-sufficient island operation without internet
|
- Self-sufficient island operation without internet
|
||||||
- Runs in a non-root Docker Container
|
- Security-Features:
|
||||||
|
- control access via `AT-commands`
|
||||||
|
- Runs in a non-root Docker Container
|
||||||
|
|
||||||
## Home Assistant Screenshots
|
## Home Assistant Screenshots
|
||||||
|
|
||||||
@@ -168,6 +170,12 @@ pv2 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module de
|
|||||||
pv3 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr
|
pv3 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr
|
||||||
pv4 = {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'] # allow this for TSUN access
|
||||||
|
tsun.block = []
|
||||||
|
mqtt.allow = ['AT+'] # allow all via mqtt
|
||||||
|
mqtt.block = []
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Inverter Configuration
|
## Inverter Configuration
|
||||||
|
|||||||
@@ -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
|
#pv3 = {type = 'RSM40-8-410M', manufacturer = 'Risen'} # Optional, PV module descr
|
||||||
#pv4 = {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 = []
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import shutil
|
import shutil
|
||||||
import tomllib
|
import tomllib
|
||||||
import logging
|
import logging
|
||||||
from schema import Schema, And, Use, Optional
|
from schema import Schema, And, Or, Use, Optional
|
||||||
|
|
||||||
|
|
||||||
class Config():
|
class Config():
|
||||||
@@ -38,6 +38,14 @@ class Config():
|
|||||||
'proxy_node_id': Use(str),
|
'proxy_node_id': Use(str),
|
||||||
'proxy_unique_id': Use(str)
|
'proxy_unique_id': Use(str)
|
||||||
},
|
},
|
||||||
|
'gen3plus': {
|
||||||
|
'at_acl': {
|
||||||
|
Or('mqtt', 'tsun'): {
|
||||||
|
'allow': [str],
|
||||||
|
Optional('block', default=[]): [str]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
'inverters': {
|
'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('monitor_sn', default=0): Use(int),
|
||||||
@@ -125,7 +133,8 @@ class Config():
|
|||||||
|
|
||||||
# merge the default and the user config
|
# merge the default and the user config
|
||||||
config = def_config.copy()
|
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:
|
if key in usr_config:
|
||||||
config[key] |= usr_config[key]
|
config[key] |= usr_config[key]
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ class SolarmanV5(Message):
|
|||||||
# MODbus or AT cmd
|
# MODbus or AT cmd
|
||||||
0x4510: self.msg_command_req, # from server
|
0x4510: self.msg_command_req, # from server
|
||||||
0x1510: self.msg_command_rsp, # from inverter
|
0x1510: self.msg_command_rsp, # from inverter
|
||||||
|
# 0x0510: self.msg_command_rsp, # from inverter
|
||||||
}
|
}
|
||||||
|
|
||||||
self.log_lvl = {
|
self.log_lvl = {
|
||||||
@@ -116,6 +117,10 @@ class SolarmanV5(Message):
|
|||||||
0x1510: self.get_cmd_rsp_log_lvl,
|
0x1510: self.get_cmd_rsp_log_lvl,
|
||||||
}
|
}
|
||||||
self.modbus_elms = 0 # for unit tests
|
self.modbus_elms = 0 # for unit tests
|
||||||
|
g3p_cnf = Config.get('gen3plus')
|
||||||
|
|
||||||
|
if 'at_acl' in g3p_cnf: # pragma: no cover
|
||||||
|
self.at_acl = g3p_cnf['at_acl']
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Our puplic methods
|
Our puplic methods
|
||||||
@@ -347,9 +352,24 @@ class SolarmanV5(Message):
|
|||||||
return
|
return
|
||||||
self.mb.build_msg(Modbus.INV_ADDR, func, addr, val, log_lvl)
|
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:
|
async def send_at_cmd(self, AT_cmd: str) -> None:
|
||||||
if self.state != self.STATE_UP:
|
if self.state != self.STATE_UP:
|
||||||
return
|
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.forward_at_cmd_resp = False
|
||||||
self.__build_header(0x4510)
|
self.__build_header(0x4510)
|
||||||
self._send_buffer += struct.pack(f'<BHLLL{len(AT_cmd)}sc', self.AT_CMD,
|
self._send_buffer += struct.pack(f'<BHLLL{len(AT_cmd)}sc', self.AT_CMD,
|
||||||
@@ -457,8 +477,13 @@ class SolarmanV5(Message):
|
|||||||
result = struct.unpack_from('<B', data, 0)
|
result = struct.unpack_from('<B', data, 0)
|
||||||
ftype = result[0]
|
ftype = result[0]
|
||||||
if ftype == self.AT_CMD:
|
if ftype == self.AT_CMD:
|
||||||
|
AT_cmd = data[15:].decode()
|
||||||
|
if self.at_cmd_forbidden(cmd=AT_cmd, connection='tsun'):
|
||||||
|
self.inc_counter('AT_Command_Blocked')
|
||||||
|
return
|
||||||
self.inc_counter('AT_Command')
|
self.inc_counter('AT_Command')
|
||||||
self.forward_at_cmd_resp = True
|
self.forward_at_cmd_resp = True
|
||||||
|
|
||||||
elif ftype == self.MB_RTU_CMD:
|
elif ftype == self.MB_RTU_CMD:
|
||||||
if self.remoteStream.mb.recv_req(data[15:],
|
if self.remoteStream.mb.recv_req(data[15:],
|
||||||
self.__forward_msg()):
|
self.__forward_msg()):
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class Register(Enum):
|
|||||||
INVALID_MSG_FMT = 58
|
INVALID_MSG_FMT = 58
|
||||||
AT_COMMAND = 59
|
AT_COMMAND = 59
|
||||||
MODBUS_COMMAND = 60
|
MODBUS_COMMAND = 60
|
||||||
|
AT_COMMAND_BLOCKED = 61
|
||||||
OUTPUT_POWER = 83
|
OUTPUT_POWER = 83
|
||||||
RATED_POWER = 84
|
RATED_POWER = 84
|
||||||
INVERTER_TEMP = 85
|
INVERTER_TEMP = 85
|
||||||
@@ -210,17 +211,18 @@ class Infos:
|
|||||||
Register.PV6_MODEL: {'name': ['inverter', 'PV6_Model'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
|
Register.PV6_MODEL: {'name': ['inverter', 'PV6_Model'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
|
||||||
|
|
||||||
# proxy:
|
# proxy:
|
||||||
Register.INVERTER_CNT: {'name': ['proxy', 'Inverter_Cnt'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_count_', 'fmt': '| int', 'name': 'Active Inverter Connections', 'icon': 'mdi:counter'}}, # noqa: E501
|
Register.INVERTER_CNT: {'name': ['proxy', 'Inverter_Cnt'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_count_', 'fmt': '| int', 'name': 'Active Inverter Connections', 'icon': 'mdi:counter'}}, # noqa: E501
|
||||||
Register.UNKNOWN_SNR: {'name': ['proxy', 'Unknown_SNR'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'unknown_snr_', 'fmt': '| int', 'name': 'Unknown Serial No', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.UNKNOWN_SNR: {'name': ['proxy', 'Unknown_SNR'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'unknown_snr_', 'fmt': '| int', 'name': 'Unknown Serial No', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.UNKNOWN_MSG: {'name': ['proxy', 'Unknown_Msg'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'unknown_msg_', 'fmt': '| int', 'name': 'Unknown Msg Type', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.UNKNOWN_MSG: {'name': ['proxy', 'Unknown_Msg'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'unknown_msg_', 'fmt': '| int', 'name': 'Unknown Msg Type', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.INVALID_DATA_TYPE: {'name': ['proxy', 'Invalid_Data_Type'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_data_type_', 'fmt': '| int', 'name': 'Invalid Data Type', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.INVALID_DATA_TYPE: {'name': ['proxy', 'Invalid_Data_Type'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_data_type_', 'fmt': '| int', 'name': 'Invalid Data Type', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.INTERNAL_ERROR: {'name': ['proxy', 'Internal_Error'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'intern_err_', 'fmt': '| int', 'name': 'Internal Error', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic', 'en': False}}, # noqa: E501
|
Register.INTERNAL_ERROR: {'name': ['proxy', 'Internal_Error'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'intern_err_', 'fmt': '| int', 'name': 'Internal Error', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic', 'en': False}}, # noqa: E501
|
||||||
Register.UNKNOWN_CTRL: {'name': ['proxy', 'Unknown_Ctrl'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'unknown_ctrl_', 'fmt': '| int', 'name': 'Unknown Control Type', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.UNKNOWN_CTRL: {'name': ['proxy', 'Unknown_Ctrl'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'unknown_ctrl_', 'fmt': '| int', 'name': 'Unknown Control Type', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.OTA_START_MSG: {'name': ['proxy', 'OTA_Start_Msg'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'ota_start_cmd_', 'fmt': '| int', 'name': 'OTA Start Cmd', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.OTA_START_MSG: {'name': ['proxy', 'OTA_Start_Msg'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'ota_start_cmd_', 'fmt': '| int', 'name': 'OTA Start Cmd', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.SW_EXCEPTION: {'name': ['proxy', 'SW_Exception'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'sw_exception_', 'fmt': '| int', 'name': 'Internal SW Exception', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.SW_EXCEPTION: {'name': ['proxy', 'SW_Exception'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'sw_exception_', 'fmt': '| int', 'name': 'Internal SW Exception', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.INVALID_MSG_FMT: {'name': ['proxy', 'Invalid_Msg_Format'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_msg_fmt_', 'fmt': '| int', 'name': 'Invalid Message Format', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.INVALID_MSG_FMT: {'name': ['proxy', 'Invalid_Msg_Format'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_msg_fmt_', 'fmt': '| int', 'name': 'Invalid Message Format', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.AT_COMMAND: {'name': ['proxy', 'AT_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'at_cmd_', 'fmt': '| int', 'name': 'AT Command', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.AT_COMMAND: {'name': ['proxy', 'AT_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'at_cmd_', 'fmt': '| int', 'name': 'AT Command', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
Register.MODBUS_COMMAND: {'name': ['proxy', 'Modbus_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'modbus_cmd_', 'fmt': '| int', 'name': 'Modbus Command', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
Register.AT_COMMAND_BLOCKED: {'name': ['proxy', 'AT_Command_Blocked'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'at_cmd_blocked_', 'fmt': '| int', 'name': 'AT Command Blocked', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
|
Register.MODBUS_COMMAND: {'name': ['proxy', 'Modbus_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'modbus_cmd_', 'fmt': '| int', 'name': 'Modbus Command', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||||
# 0xffffff03: {'name':['proxy', 'Voltage'], 'level': logging.DEBUG, 'unit': 'V', 'ha':{'dev':'proxy', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id':'proxy_volt_', 'fmt':'| float','name': 'Grid Voltage'}}, # noqa: E501
|
# 0xffffff03: {'name':['proxy', 'Voltage'], 'level': logging.DEBUG, 'unit': 'V', 'ha':{'dev':'proxy', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id':'proxy_volt_', 'fmt':'| float','name': 'Grid Voltage'}}, # noqa: E501
|
||||||
|
|
||||||
# events
|
# events
|
||||||
@@ -404,7 +406,7 @@ class Infos:
|
|||||||
attr['unit_of_meas'] = row['unit'] # 'unit_of_meas'
|
attr['unit_of_meas'] = row['unit'] # 'unit_of_meas'
|
||||||
if 'icon' in ha:
|
if 'icon' in ha:
|
||||||
attr['ic'] = ha['icon'] # icon for the entity
|
attr['ic'] = ha['icon'] # icon for the entity
|
||||||
if 'nat_prc' in ha:
|
if 'nat_prc' in ha: # pragma: no cover
|
||||||
attr['sug_dsp_prc'] = ha['nat_prc'] # precison of floats
|
attr['sug_dsp_prc'] = ha['nat_prc'] # precison of floats
|
||||||
if 'ent_cat' in ha:
|
if 'ent_cat' in ha:
|
||||||
attr['ent_cat'] = ha['ent_cat'] # diagnostic, config
|
attr['ent_cat'] = ha['ent_cat'] # diagnostic, config
|
||||||
|
|||||||
@@ -31,10 +31,12 @@ def test_default_config():
|
|||||||
assert True
|
assert True
|
||||||
except:
|
except:
|
||||||
assert False
|
assert False
|
||||||
assert validated == {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'node_id': '', 'monitor_sn': 0, 'suggested_area': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'node_id': '', 'suggested_area': ''}}}
|
assert validated == {'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}}, 'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'node_id': '', 'monitor_sn': 0, 'suggested_area': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'node_id': '', 'suggested_area': ''}}}
|
||||||
|
|
||||||
def test_full_config():
|
def test_full_config():
|
||||||
cnf = {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005},
|
cnf = {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005},
|
||||||
|
'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []},
|
||||||
|
'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}},
|
||||||
'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000},
|
'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000},
|
||||||
'mqtt': {'host': 'mqtt', 'port': 1883, 'user': '', 'passwd': ''},
|
'mqtt': {'host': 'mqtt', 'port': 1883, 'user': '', 'passwd': ''},
|
||||||
'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'},
|
'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'},
|
||||||
@@ -46,10 +48,12 @@ def test_full_config():
|
|||||||
assert True
|
assert True
|
||||||
except:
|
except:
|
||||||
assert False
|
assert False
|
||||||
assert validated == {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'node_id': '', 'monitor_sn': 0, 'pv1': {'manufacturer': 'man1','type': 'type1'},'pv2': {'manufacturer': 'man2','type': 'type2'},'pv3': {'manufacturer': 'man3','type': 'type3'}, 'suggested_area': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'node_id': '', 'suggested_area': ''}}}
|
assert validated == {'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}}, 'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'node_id': '', 'monitor_sn': 0, 'pv1': {'manufacturer': 'man1','type': 'type1'},'pv2': {'manufacturer': 'man2','type': 'type2'},'pv3': {'manufacturer': 'man3','type': 'type3'}, 'suggested_area': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'node_id': '', 'suggested_area': ''}}}
|
||||||
|
|
||||||
def test_mininum_config():
|
def test_mininum_config():
|
||||||
cnf = {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005},
|
cnf = {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005},
|
||||||
|
'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+']},
|
||||||
|
'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE']}}},
|
||||||
'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000},
|
'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000},
|
||||||
'mqtt': {'host': 'mqtt', 'port': 1883, 'user': '', 'passwd': ''},
|
'mqtt': {'host': 'mqtt', 'port': 1883, 'user': '', 'passwd': ''},
|
||||||
'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'},
|
'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'},
|
||||||
@@ -62,7 +66,7 @@ def test_mininum_config():
|
|||||||
assert True
|
assert True
|
||||||
except:
|
except:
|
||||||
assert False
|
assert False
|
||||||
assert validated == {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'node_id': '', 'monitor_sn': 0, 'suggested_area': ''}}}
|
assert validated == {'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}}, 'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'node_id': '', 'monitor_sn': 0, 'suggested_area': ''}}}
|
||||||
|
|
||||||
def test_read_empty():
|
def test_read_empty():
|
||||||
cnf = {}
|
cnf = {}
|
||||||
@@ -70,7 +74,7 @@ def test_read_empty():
|
|||||||
err = TstConfig.read('app/config/')
|
err = TstConfig.read('app/config/')
|
||||||
assert err == None
|
assert err == None
|
||||||
cnf = TstConfig.get()
|
cnf = TstConfig.get()
|
||||||
assert cnf == {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
assert cnf == {'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}}, 'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
||||||
|
|
||||||
defcnf = TstConfig.def_config.get('solarman')
|
defcnf = TstConfig.def_config.get('solarman')
|
||||||
assert defcnf == {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}
|
assert defcnf == {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}
|
||||||
@@ -92,7 +96,7 @@ def test_read_cnf1():
|
|||||||
err = TstConfig.read('app/config/')
|
err = TstConfig.read('app/config/')
|
||||||
assert err == None
|
assert err == None
|
||||||
cnf = TstConfig.get()
|
cnf = TstConfig.get()
|
||||||
assert cnf == {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': False, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
assert cnf == {'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}}, 'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': False, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
||||||
cnf = TstConfig.get('solarman')
|
cnf = TstConfig.get('solarman')
|
||||||
assert cnf == {'enabled': False, 'host': 'iot.talent-monitoring.com', 'port': 10000}
|
assert cnf == {'enabled': False, 'host': 'iot.talent-monitoring.com', 'port': 10000}
|
||||||
defcnf = TstConfig.def_config.get('solarman')
|
defcnf = TstConfig.def_config.get('solarman')
|
||||||
@@ -105,7 +109,7 @@ def test_read_cnf2():
|
|||||||
err = TstConfig.read('app/config/')
|
err = TstConfig.read('app/config/')
|
||||||
assert err == None
|
assert err == None
|
||||||
cnf = TstConfig.get()
|
cnf = TstConfig.get()
|
||||||
assert cnf == {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
assert cnf == {'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}}, 'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
||||||
assert True == TstConfig.is_default('solarman')
|
assert True == TstConfig.is_default('solarman')
|
||||||
|
|
||||||
def test_read_cnf3():
|
def test_read_cnf3():
|
||||||
@@ -122,7 +126,7 @@ def test_read_cnf4():
|
|||||||
err = TstConfig.read('app/config/')
|
err = TstConfig.read('app/config/')
|
||||||
assert err == None
|
assert err == None
|
||||||
cnf = TstConfig.get()
|
cnf = TstConfig.get()
|
||||||
assert cnf == {'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 5000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
assert cnf == {'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': []}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': []}}}, 'tsun': {'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005}, 'solarman': {'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 5000}, 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': None, 'passwd': None}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'inverters': {'allow_all': True, 'R170000000000001': {'suggested_area': '', 'monitor_sn': 0, 'node_id': ''}, 'Y170000000000001': {'monitor_sn': 2000000000, 'suggested_area': '', 'node_id': ''}}}
|
||||||
assert False == TstConfig.is_default('solarman')
|
assert False == TstConfig.is_default('solarman')
|
||||||
|
|
||||||
def test_read_cnf5():
|
def test_read_cnf5():
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ def test_statistic_counter():
|
|||||||
assert val == None or val == 0
|
assert val == None or val == 0
|
||||||
|
|
||||||
i.static_init() # initialize counter
|
i.static_init() # initialize counter
|
||||||
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "Modbus_Command": 0}})
|
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "AT_Command_Blocked": 0, "Modbus_Command": 0}})
|
||||||
|
|
||||||
val = i.dev_value(Register.INVERTER_CNT) # valid and initiliazed addr
|
val = i.dev_value(Register.INVERTER_CNT) # valid and initiliazed addr
|
||||||
assert val == 0
|
assert val == 0
|
||||||
|
|
||||||
i.inc_counter('Inverter_Cnt')
|
i.inc_counter('Inverter_Cnt')
|
||||||
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 1, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "Modbus_Command": 0}})
|
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 1, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "AT_Command_Blocked": 0, "Modbus_Command": 0}})
|
||||||
val = i.dev_value(Register.INVERTER_CNT)
|
val = i.dev_value(Register.INVERTER_CNT)
|
||||||
assert val == 1
|
assert val == 1
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ class MemoryStream(SolarmanV5):
|
|||||||
self.addr = 'Test: SrvSide'
|
self.addr = 'Test: SrvSide'
|
||||||
self.db.stat['proxy']['Invalid_Msg_Format'] = 0
|
self.db.stat['proxy']['Invalid_Msg_Format'] = 0
|
||||||
self.db.stat['proxy']['AT_Command'] = 0
|
self.db.stat['proxy']['AT_Command'] = 0
|
||||||
|
self.db.stat['proxy']['AT_Command_Blocked'] = 0
|
||||||
self.test_exception_async_write = False
|
self.test_exception_async_write = False
|
||||||
self.entity_prfx = ''
|
self.entity_prfx = ''
|
||||||
|
self.at_acl = {'mqtt': {'allow': ['AT+'], 'block': ['AT+WEBU']}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE', 'AT+TIME'], 'block': ['AT+WEBU']}}
|
||||||
|
|
||||||
def _timestamp(self):
|
def _timestamp(self):
|
||||||
return timestamp
|
return timestamp
|
||||||
@@ -465,6 +467,15 @@ def AtCommandIndMsg(): # 0x4510
|
|||||||
msg += b'\x15'
|
msg += b'\x15'
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def AtCommandIndMsgBlock(): # 0x4510
|
||||||
|
msg = b'\xa5\x17\x00\x10\x45\x03\x02' +get_sn() +b'\x01\x02\x00'
|
||||||
|
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
msg += b'AT+WEBU\r'
|
||||||
|
msg += correct_checksum(msg)
|
||||||
|
msg += b'\x15'
|
||||||
|
return msg
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def AtCommandRspMsg(): # 0x1510
|
def AtCommandRspMsg(): # 0x1510
|
||||||
msg = b'\xa5\x0a\x00\x10\x15\x03\x03' +get_sn() +b'\x01\x01'
|
msg = b'\xa5\x0a\x00\x10\x15\x03\x03' +get_sn() +b'\x01\x01'
|
||||||
@@ -1276,11 +1287,49 @@ async def test_AT_cmd(ConfigTsunAllowAll, DeviceIndMsg, DeviceRspMsg, InverterIn
|
|||||||
assert m.forward_at_cmd_resp == False
|
assert m.forward_at_cmd_resp == False
|
||||||
m.close()
|
m.close()
|
||||||
|
|
||||||
def test_at_command_ind(ConfigTsunInv1, AtCommandIndMsg):
|
@pytest.mark.asyncio
|
||||||
|
async def test_AT_cmd_blocked(ConfigTsunAllowAll, DeviceIndMsg, DeviceRspMsg, InverterIndMsg, InverterRspMsg, AtCommandIndMsg):
|
||||||
|
ConfigTsunAllowAll
|
||||||
|
m = MemoryStream(DeviceIndMsg, (0,), True)
|
||||||
|
m.append_msg(InverterIndMsg)
|
||||||
|
m.read()
|
||||||
|
assert m.control == 0x4110
|
||||||
|
assert str(m.seq) == '01:01'
|
||||||
|
assert m._recv_buffer==InverterIndMsg # unhandled next message
|
||||||
|
assert m._send_buffer==DeviceRspMsg
|
||||||
|
assert m._forward_buffer==DeviceIndMsg
|
||||||
|
|
||||||
|
m._send_buffer = bytearray(0) # clear send buffer for next test
|
||||||
|
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||||
|
await m.send_at_cmd('AT+WEBU')
|
||||||
|
assert m._recv_buffer==InverterIndMsg # unhandled next message
|
||||||
|
assert m._send_buffer==b''
|
||||||
|
assert m._forward_buffer==b''
|
||||||
|
assert str(m.seq) == '01:01'
|
||||||
|
|
||||||
|
m.read()
|
||||||
|
assert m.control == 0x4210
|
||||||
|
assert str(m.seq) == '02:02'
|
||||||
|
assert m._recv_buffer==b''
|
||||||
|
assert m._send_buffer==InverterRspMsg
|
||||||
|
assert m._forward_buffer==InverterIndMsg
|
||||||
|
|
||||||
|
m._send_buffer = bytearray(0) # clear send buffer for next test
|
||||||
|
m._forward_buffer = bytearray(0) # clear send buffer for next test
|
||||||
|
await m.send_at_cmd('AT+WEBU')
|
||||||
|
assert m._recv_buffer==b''
|
||||||
|
assert m._send_buffer==b''
|
||||||
|
assert m._forward_buffer==b''
|
||||||
|
assert str(m.seq) == '02:02'
|
||||||
|
assert m.forward_at_cmd_resp == False
|
||||||
|
m.close()
|
||||||
|
|
||||||
|
def test_AT_cmd_ind(ConfigTsunInv1, AtCommandIndMsg):
|
||||||
ConfigTsunInv1
|
ConfigTsunInv1
|
||||||
m = MemoryStream(AtCommandIndMsg, (0,), False)
|
m = MemoryStream(AtCommandIndMsg, (0,), False)
|
||||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||||
m.db.stat['proxy']['AT_Command'] = 0
|
m.db.stat['proxy']['AT_Command'] = 0
|
||||||
|
m.db.stat['proxy']['AT_Command_Blocked'] = 0
|
||||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||||
m.read() # read complete msg, and dispatch msg
|
m.read() # read complete msg, and dispatch msg
|
||||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||||
@@ -1296,6 +1345,32 @@ def test_at_command_ind(ConfigTsunInv1, AtCommandIndMsg):
|
|||||||
assert m._forward_buffer==AtCommandIndMsg
|
assert m._forward_buffer==AtCommandIndMsg
|
||||||
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||||
assert m.db.stat['proxy']['AT_Command'] == 1
|
assert m.db.stat['proxy']['AT_Command'] == 1
|
||||||
|
assert m.db.stat['proxy']['AT_Command_Blocked'] == 0
|
||||||
|
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||||
|
m.close()
|
||||||
|
|
||||||
|
def test_AT_cmd_ind_block(ConfigTsunInv1, AtCommandIndMsgBlock):
|
||||||
|
ConfigTsunInv1
|
||||||
|
m = MemoryStream(AtCommandIndMsgBlock, (0,), False)
|
||||||
|
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||||
|
m.db.stat['proxy']['AT_Command'] = 0
|
||||||
|
m.db.stat['proxy']['AT_Command_Blocked'] = 0
|
||||||
|
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||||
|
m.read() # read complete msg, and dispatch msg
|
||||||
|
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||||
|
assert m.msg_count == 1
|
||||||
|
assert m.header_len==11
|
||||||
|
assert m.snr == 2070233889
|
||||||
|
# assert m.unique_id == '2070233889'
|
||||||
|
assert m.control == 0x4510
|
||||||
|
assert str(m.seq) == '03:02'
|
||||||
|
assert m.data_len == 23
|
||||||
|
assert m._recv_buffer==b''
|
||||||
|
assert m._send_buffer==b''
|
||||||
|
assert m._forward_buffer==b''
|
||||||
|
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
|
||||||
|
assert m.db.stat['proxy']['AT_Command'] == 0
|
||||||
|
assert m.db.stat['proxy']['AT_Command_Blocked'] == 1
|
||||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||||
m.close()
|
m.close()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user