S allius/issue186 (#187)

* Parse more values in Server Mode
Fixes #186

* read OUTPUT_COEFFICIENT and MAC_ADDR in SrvMode

* fix unit test

* increase test coverage
This commit is contained in:
Stefan Allius
2024-09-14 19:49:29 +02:00
committed by GitHub
parent e12c78212f
commit 5ef68280b1
7 changed files with 364 additions and 99 deletions

View File

@@ -11,82 +11,82 @@ else: # pragma: no cover
class RegisterMap:
map = {
0x00092ba8: Register.COLLECTOR_FW_VERSION,
0x000927c0: Register.CHIP_TYPE,
0x00092f90: Register.CHIP_MODEL,
0x00094ae8: Register.MAC_ADDR,
0x00095a88: Register.TRACE_URL,
0x00095aec: Register.LOGGER_URL,
0x0000000a: Register.PRODUCT_NAME,
0x00000014: Register.MANUFACTURER,
0x0000001e: Register.VERSION,
0x00000028: Register.SERIAL_NUMBER,
0x00000032: Register.EQUIPMENT_MODEL,
0x00013880: Register.NO_INPUTS,
0xffffff00: Register.INVERTER_CNT,
0xffffff01: Register.UNKNOWN_SNR,
0xffffff02: Register.UNKNOWN_MSG,
0xffffff03: Register.INVALID_DATA_TYPE,
0xffffff04: Register.INTERNAL_ERROR,
0xffffff05: Register.UNKNOWN_CTRL,
0xffffff06: Register.OTA_START_MSG,
0xffffff07: Register.SW_EXCEPTION,
0xffffff08: Register.MAX_DESIGNED_POWER,
0xffffff09: Register.OUTPUT_COEFFICIENT,
0xffffff0a: Register.INVERTER_STATUS,
0xffffff0b: Register.POLLING_INTERVAL,
0xfffffffe: Register.TEST_REG1,
0xffffffff: Register.TEST_REG2,
0x00000640: Register.OUTPUT_POWER,
0x000005dc: Register.RATED_POWER,
0x00000514: Register.INVERTER_TEMP,
0x000006a4: Register.PV1_VOLTAGE,
0x00000708: Register.PV1_CURRENT,
0x0000076c: Register.PV1_POWER,
0x000007d0: Register.PV2_VOLTAGE,
0x00000834: Register.PV2_CURRENT,
0x00000898: Register.PV2_POWER,
0x000008fc: Register.PV3_VOLTAGE,
0x00000960: Register.PV3_CURRENT,
0x000009c4: Register.PV3_POWER,
0x00000a28: Register.PV4_VOLTAGE,
0x00000a8c: Register.PV4_CURRENT,
0x00000af0: Register.PV4_POWER,
0x00000c1c: Register.PV1_DAILY_GENERATION,
0x00000c80: Register.PV1_TOTAL_GENERATION,
0x00000ce4: Register.PV2_DAILY_GENERATION,
0x00000d48: Register.PV2_TOTAL_GENERATION,
0x00000dac: Register.PV3_DAILY_GENERATION,
0x00000e10: Register.PV3_TOTAL_GENERATION,
0x00000e74: Register.PV4_DAILY_GENERATION,
0x00000ed8: Register.PV4_TOTAL_GENERATION,
0x00000b54: Register.DAILY_GENERATION,
0x00000bb8: Register.TOTAL_GENERATION,
0x000003e8: Register.GRID_VOLTAGE,
0x0000044c: Register.GRID_CURRENT,
0x000004b0: Register.GRID_FREQUENCY,
0x000cfc38: Register.CONNECT_COUNT,
0x000c3500: Register.SIGNAL_STRENGTH,
0x000c96a8: Register.POWER_ON_TIME,
0x000d0020: Register.COLLECT_INTERVAL,
0x000cf850: Register.DATA_UP_INTERVAL,
0x000c7f38: Register.COMMUNICATION_TYPE,
0x00000191: Register.EVENT_401,
0x00000192: Register.EVENT_402,
0x00000193: Register.EVENT_403,
0x00000194: Register.EVENT_404,
0x00000195: Register.EVENT_405,
0x00000196: Register.EVENT_406,
0x00000197: Register.EVENT_407,
0x00000198: Register.EVENT_408,
0x00000199: Register.EVENT_409,
0x0000019a: Register.EVENT_410,
0x0000019b: Register.EVENT_411,
0x0000019c: Register.EVENT_412,
0x0000019d: Register.EVENT_413,
0x0000019e: Register.EVENT_414,
0x0000019f: Register.EVENT_415,
0x000001a0: Register.EVENT_416,
0x00092ba8: {'reg': Register.COLLECTOR_FW_VERSION},
0x000927c0: {'reg': Register.CHIP_TYPE},
0x00092f90: {'reg': Register.CHIP_MODEL},
0x00094ae8: {'reg': Register.MAC_ADDR},
0x00095a88: {'reg': Register.TRACE_URL},
0x00095aec: {'reg': Register.LOGGER_URL},
0x0000000a: {'reg': Register.PRODUCT_NAME},
0x00000014: {'reg': Register.MANUFACTURER},
0x0000001e: {'reg': Register.VERSION},
0x00000028: {'reg': Register.SERIAL_NUMBER},
0x00000032: {'reg': Register.EQUIPMENT_MODEL},
0x00013880: {'reg': Register.NO_INPUTS},
0xffffff00: {'reg': Register.INVERTER_CNT},
0xffffff01: {'reg': Register.UNKNOWN_SNR},
0xffffff02: {'reg': Register.UNKNOWN_MSG},
0xffffff03: {'reg': Register.INVALID_DATA_TYPE},
0xffffff04: {'reg': Register.INTERNAL_ERROR},
0xffffff05: {'reg': Register.UNKNOWN_CTRL},
0xffffff06: {'reg': Register.OTA_START_MSG},
0xffffff07: {'reg': Register.SW_EXCEPTION},
0xffffff08: {'reg': Register.POLLING_INTERVAL},
0xfffffffe: {'reg': Register.TEST_REG1},
0xffffffff: {'reg': Register.TEST_REG2},
0x00000640: {'reg': Register.OUTPUT_POWER},
0x000005dc: {'reg': Register.RATED_POWER},
0x00000514: {'reg': Register.INVERTER_TEMP},
0x000006a4: {'reg': Register.PV1_VOLTAGE},
0x00000708: {'reg': Register.PV1_CURRENT},
0x0000076c: {'reg': Register.PV1_POWER},
0x000007d0: {'reg': Register.PV2_VOLTAGE},
0x00000834: {'reg': Register.PV2_CURRENT},
0x00000898: {'reg': Register.PV2_POWER},
0x000008fc: {'reg': Register.PV3_VOLTAGE},
0x00000960: {'reg': Register.PV3_CURRENT},
0x000009c4: {'reg': Register.PV3_POWER},
0x00000a28: {'reg': Register.PV4_VOLTAGE},
0x00000a8c: {'reg': Register.PV4_CURRENT},
0x00000af0: {'reg': Register.PV4_POWER},
0x00000c1c: {'reg': Register.PV1_DAILY_GENERATION},
0x00000c80: {'reg': Register.PV1_TOTAL_GENERATION},
0x00000ce4: {'reg': Register.PV2_DAILY_GENERATION},
0x00000d48: {'reg': Register.PV2_TOTAL_GENERATION},
0x00000dac: {'reg': Register.PV3_DAILY_GENERATION},
0x00000e10: {'reg': Register.PV3_TOTAL_GENERATION},
0x00000e74: {'reg': Register.PV4_DAILY_GENERATION},
0x00000ed8: {'reg': Register.PV4_TOTAL_GENERATION},
0x00000b54: {'reg': Register.DAILY_GENERATION},
0x00000bb8: {'reg': Register.TOTAL_GENERATION},
0x000003e8: {'reg': Register.GRID_VOLTAGE},
0x0000044c: {'reg': Register.GRID_CURRENT},
0x000004b0: {'reg': Register.GRID_FREQUENCY},
0x000cfc38: {'reg': Register.CONNECT_COUNT},
0x000c3500: {'reg': Register.SIGNAL_STRENGTH},
0x000c96a8: {'reg': Register.POWER_ON_TIME},
0x000d0020: {'reg': Register.COLLECT_INTERVAL},
0x000cf850: {'reg': Register.DATA_UP_INTERVAL},
0x000c7f38: {'reg': Register.COMMUNICATION_TYPE},
0x00000191: {'reg': Register.EVENT_401},
0x00000192: {'reg': Register.EVENT_402},
0x00000193: {'reg': Register.EVENT_403},
0x00000194: {'reg': Register.EVENT_404},
0x00000195: {'reg': Register.EVENT_405},
0x00000196: {'reg': Register.EVENT_406},
0x00000197: {'reg': Register.EVENT_407},
0x00000198: {'reg': Register.EVENT_408},
0x00000199: {'reg': Register.EVENT_409},
0x0000019a: {'reg': Register.EVENT_410},
0x0000019b: {'reg': Register.EVENT_411},
0x0000019c: {'reg': Register.EVENT_412},
0x0000019d: {'reg': Register.EVENT_413},
0x0000019e: {'reg': Register.EVENT_414},
0x0000019f: {'reg': Register.EVENT_415},
0x000001a0: {'reg': Register.EVENT_416},
0x00000064: {'reg': Register.INVERTER_STATUS},
0x0000125c: {'reg': Register.MAX_DESIGNED_POWER},
0x00003200: {'reg': Register.OUTPUT_COEFFICIENT, 'ratio': 100/1024},
}
@@ -104,7 +104,8 @@ class InfosG3(Infos):
entity strings
sug_area:str ==> suggested area string from the config file'''
# iterate over RegisterMap.map and get the register values
for reg in RegisterMap.map.values():
for row in RegisterMap.map.values():
reg = row['reg']
res = self.ha_conf(reg, ha_prfx, node_id, snr, False, sug_area) # noqa: E501
if res:
yield res
@@ -123,9 +124,11 @@ class InfosG3(Infos):
result = struct.unpack_from('!lB', buf, ind)
addr = result[0]
if addr not in RegisterMap.map:
row = None
info_id = -1
else:
info_id = RegisterMap.map[addr]
row = RegisterMap.map[addr]
info_id = row['reg']
data_type = result[1]
ind += 5
@@ -171,9 +174,19 @@ class InfosG3(Infos):
" not supported")
return
result = self.__modify_val(row, result)
yield from self.__store_result(addr, result, info_id, node_id)
i += 1
def __modify_val(self, row, result):
if row:
if 'eval' in row:
result = eval(row['eval'])
if 'ratio' in row:
result = round(result * row['ratio'], 2)
return result
def __store_result(self, addr, result, info_id, node_id):
keys, level, unit, must_incr = self._key_obj(info_id)
if keys:

View File

@@ -19,6 +19,7 @@ class RegisterMap:
0x4102001a: {'reg': Register.HEARTBEAT_INTERVAL, 'fmt': '<B', 'ratio': 1}, # noqa: E501
0x4102001c: {'reg': Register.SIGNAL_STRENGTH, 'fmt': '<B', 'ratio': 1, 'dep': ProxyMode.SERVER}, # noqa: E501
0x4102001e: {'reg': Register.CHIP_MODEL, 'fmt': '!40s'}, # noqa: E501
0x41020046: {'reg': Register.MAC_ADDR, 'fmt': '!BBBBBB', 'eval': '"%02x:%02x:%02x:%02x:%02x:%02x" % res'}, # noqa: E501
0x4102004c: {'reg': Register.IP_ADDRESS, 'fmt': '!16s'}, # noqa: E501
0x4102005f: {'reg': Register.SENSOR_LIST, 'fmt': '<H', 'eval': "f'{result:04x}'"}, # noqa: E501
0x41020064: {'reg': Register.COLLECTOR_FW_VERSION, 'fmt': '!40s'}, # noqa: E501
@@ -59,7 +60,7 @@ class RegisterMap:
0x42010112: {'reg': Register.PV4_TOTAL_GENERATION, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
0x42010126: {'reg': Register.MAX_DESIGNED_POWER, 'fmt': '!H', 'ratio': 1}, # noqa: E501
0xffffff01: {'reg': Register.OUTPUT_COEFFICIENT},
0x42010170: {'reg': Register.OUTPUT_COEFFICIENT, 'fmt': '!H', 'ratio': 100/1024}, # noqa: E501
0xffffff02: {'reg': Register.POLLING_INTERVAL},
# 0x4281001c: {'reg': Register.POWER_ON_TIME, 'fmt': '<H', 'ratio': 1}, # noqa: E501

View File

@@ -1,7 +1,7 @@
# test_with_pytest.py
import pytest, json
from app.src.infos import Register, ClrAtMidnight
from app.src.gen3.infos_g3 import InfosG3
import pytest, json, math
from app.src.infos import Register
from app.src.gen3.infos_g3 import InfosG3, RegisterMap
@pytest.fixture
def contr_data_seq(): # Get Time Request message
@@ -421,21 +421,21 @@ def test_must_incr_total(inv_data_seq2, inv_data_seq2_zero):
if key == 'total' or key == 'inverter' or key == 'env':
assert update == True
tests +=1
assert tests==5
assert tests==8
assert json.dumps(i.db['total']) == json.dumps({'Daily_Generation': 1.7, 'Total_Generation': 17.36})
assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 64.5, "Daily_Generation": 1.08, "Total_Generation": 9.74}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 45.7, "Daily_Generation": 0.62, "Total_Generation": 7.62}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 23})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Status": 1, "Inverter_Temp": 23})
tests = 0
for key, update in i.parse (inv_data_seq2):
if key == 'total' or key == 'env':
assert update == False
tests +=1
assert tests==3
assert tests==4
assert json.dumps(i.db['total']) == json.dumps({'Daily_Generation': 1.7, 'Total_Generation': 17.36})
assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 64.5, "Daily_Generation": 1.08, "Total_Generation": 9.74}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 45.7, "Daily_Generation": 0.62, "Total_Generation": 7.62}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 23})
assert json.dumps(i.db['inverter']) == json.dumps({"Rated_Power": 600, "No_Inputs": 2})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Status": 1, "Inverter_Temp": 23})
assert json.dumps(i.db['inverter']) == json.dumps({"Rated_Power": 600, "Max_Designed_Power": -1, "Output_Coefficient": 100.0, "No_Inputs": 2})
tests = 0
for key, update in i.parse (inv_data_seq2_zero):
@@ -443,13 +443,12 @@ def test_must_incr_total(inv_data_seq2, inv_data_seq2_zero):
assert update == False
tests +=1
elif key == 'env':
assert update == True
tests +=1
assert tests==3
assert tests==4
assert json.dumps(i.db['total']) == json.dumps({'Daily_Generation': 1.7, 'Total_Generation': 17.36})
assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 0.0, "Daily_Generation": 1.08, "Total_Generation": 9.74}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 0.0, "Daily_Generation": 0.62, "Total_Generation": 7.62}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Status": 1, "Inverter_Temp": 0})
def test_must_incr_total2(inv_data_seq2, inv_data_seq2_zero):
i = InfosG3()
@@ -462,10 +461,10 @@ def test_must_incr_total2(inv_data_seq2, inv_data_seq2_zero):
assert update == True
tests +=1
assert tests==3
assert tests==4
assert json.dumps(i.db['total']) == json.dumps({})
assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 0.0}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 0.0}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Status": 1, "Inverter_Temp": 0})
tests = 0
for key, update in i.parse (inv_data_seq2_zero):
@@ -473,18 +472,17 @@ def test_must_incr_total2(inv_data_seq2, inv_data_seq2_zero):
assert update == False
tests +=1
assert tests==3
assert tests==4
assert json.dumps(i.db['total']) == json.dumps({})
assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 0.0}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 0.0}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0})
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Status": 1, "Inverter_Temp": 0})
tests = 0
for key, update in i.parse (inv_data_seq2):
if key == 'total' or key == 'env':
assert update == True
tests +=1
assert tests==3
assert tests==4
assert json.dumps(i.db['total']) == json.dumps({'Daily_Generation': 1.7, 'Total_Generation': 17.36})
assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 64.5, "Daily_Generation": 1.08, "Total_Generation": 9.74}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 45.7, "Daily_Generation": 0.62, "Total_Generation": 7.62}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}})
@@ -522,3 +520,15 @@ def test_invalid_data_type(invalid_data_seq):
val = i.dev_value(Register.INVALID_DATA_TYPE) # check invalid data type counter
assert val == 1
def test_result_eval(inv_data_seq2: bytes):
# add eval to convert temperature from °F to °C
RegisterMap.map[0x00000514]['eval'] = '(result-32)/1.8'
i = InfosG3()
for _, _ in i.parse (inv_data_seq2):
pass # side effect is calling generator i.parse()
assert math.isclose(-5.0, round (i.get_db_value(Register.INVERTER_TEMP, 0),4), rel_tol=1e-09, abs_tol=1e-09)
del RegisterMap.map[0x00000514]['eval'] # remove eval

View File

@@ -86,7 +86,7 @@ def test_parse_4110(str_test_ip, device_data: bytes):
assert json.dumps(i.db) == json.dumps({
'controller': {"Data_Up_Interval": 300, "Collect_Interval": 1, "Heartbeat_Interval": 120, "Signal_Strength": 100, "IP_Address": str_test_ip, "Sensor_List": "02b0"},
'collector': {"Chip_Model": "LSW5BLE_17_02B0_1.05", "Collector_Fw_Version": "V1.1.00.0B"},
'collector': {"Chip_Model": "LSW5BLE_17_02B0_1.05", "MAC-Addr": "40:2a:8f:4f:51:54", "Collector_Fw_Version": "V1.1.00.0B"},
})
def test_parse_4210(inverter_data: bytes):
@@ -98,7 +98,7 @@ def test_parse_4210(inverter_data: bytes):
assert json.dumps(i.db) == json.dumps({
"controller": {"Sensor_List": "02b0", "Power_On_Time": 2051},
"inverter": {"Serial_Number": "Y17E00000000000E", "Version": "V4.0.10", "Rated_Power": 600, "Max_Designed_Power": 2000},
"inverter": {"Serial_Number": "Y17E00000000000E", "Version": "V4.0.10", "Rated_Power": 600, "Max_Designed_Power": 2000, "Output_Coefficient": 100.0},
"env": {"Inverter_Status": 1, "Inverter_Temp": 14},
"grid": {"Voltage": 224.8, "Current": 0.73, "Frequency": 50.05, "Output_Power": 165.8},
"input": {"pv1": {"Voltage": 35.3, "Current": 1.68, "Power": 59.6, "Daily_Generation": 0.04, "Total_Generation": 30.76},

View File

@@ -0,0 +1,160 @@
# test_with_pytest.py
import pytest
import asyncio
from mock import patch
from enum import Enum
from app.src.config import Config
from app.src.singleton import Singleton
from app.src.gen3plus.connection_g3p import ConnectionG3P
from app.src.gen3plus.inverter_g3p import InverterG3P
from app.src.gen3plus.infos_g3p import InfosG3P
from app.src.infos import Infos
pytest_plugins = ('pytest_asyncio',)
# initialize the proxy statistics
Infos.static_init()
@pytest.fixture
def config_conn():
Config.act_config = {'solarman':{'enabled': True, 'host': 'test_cloud.local', 'port': 1234}, 'inverters':{'allow_all':True}}
@pytest.fixture(scope="module", autouse=True)
def module_init():
Singleton._instances.clear()
yield
@pytest.fixture
def patch_conn_init():
with patch.object(ConnectionG3P, '__init__', return_value= None) as conn:
yield conn
@pytest.fixture
def patch_conn_close():
with patch.object(ConnectionG3P, 'close') as conn:
yield conn
class FakeReader():
def __init__(self):
self.on_recv = asyncio.Event()
async def read(self, max_len: int):
await self.on_recv.wait()
return b''
def feed_eof(self):
return
class FakeWriter():
def write(self, buf: bytes):
return
def get_extra_info(self, sel: str):
if sel == 'peername':
return 'remote.intern'
elif sel == 'sockname':
return 'sock:1234'
assert False
def is_closing(self):
return False
def close(self):
return
async def wait_closed(self):
return
class TestType(Enum):
RD_TEST_0_BYTES = 1
RD_TEST_TIMEOUT = 2
RD_TEST_EXCEPT = 3
test = TestType.RD_TEST_0_BYTES
@pytest.fixture
def patch_open_connection():
async def new_conn(conn):
await asyncio.sleep(0)
return FakeReader(), FakeWriter()
def new_open(host: str, port: int):
global test
if test == TestType.RD_TEST_TIMEOUT:
raise ConnectionRefusedError
elif test == TestType.RD_TEST_EXCEPT:
raise ValueError("Value cannot be negative") # Compliant
return new_conn(None)
with patch.object(asyncio, 'open_connection', new_open) as conn:
yield conn
def test_method_calls(patch_conn_init, patch_conn_close):
spy1 = patch_conn_init
spy2 = patch_conn_close
reader = FakeReader()
writer = FakeWriter()
addr = ('proxy.local', 10000)
inverter = InverterG3P(reader, writer, addr, client_mode=False)
inverter.l_addr = ''
inverter.r_addr = ''
spy1.assert_called_once()
spy1.assert_called_once_with(reader, writer, addr, None, server_side=True, client_mode=False)
inverter.close()
spy2.assert_called_once()
@pytest.mark.asyncio
async def test_remote_conn(config_conn, patch_open_connection, patch_conn_close):
_ = config_conn
_ = patch_open_connection
assert asyncio.get_running_loop()
spy1 = patch_conn_close
reader = FakeReader()
writer = FakeWriter()
addr = ('proxy.local', 10000)
inverter = InverterG3P(reader, writer, addr, client_mode=False)
inverter.l_addr = ''
inverter.r_addr = ''
inverter.node_id = 'Test'
inverter.db = InfosG3P(client_mode= False)
await inverter.async_create_remote()
await asyncio.sleep(0)
assert inverter.remote_stream
inverter.close()
spy1.assert_called_once()
@pytest.mark.asyncio
async def test_remote_except(config_conn, patch_open_connection, patch_conn_close):
_ = config_conn
_ = patch_open_connection
assert asyncio.get_running_loop()
spy1 = patch_conn_close
reader = FakeReader()
writer = FakeWriter()
addr = ('proxy.local', 10000)
global test
test = TestType.RD_TEST_TIMEOUT
inverter = InverterG3P(reader, writer, addr, client_mode=False)
inverter.l_addr = ''
inverter.r_addr = ''
inverter.node_id = 'Test'
inverter.db = InfosG3P(client_mode= False)
test = TestType.RD_TEST_TIMEOUT
await inverter.async_create_remote()
await asyncio.sleep(0)
assert inverter.remote_stream==None
test = TestType.RD_TEST_EXCEPT
await inverter.async_create_remote()
await asyncio.sleep(0)
assert inverter.remote_stream==None
inverter.close()
spy1.assert_called_once()

View File

@@ -1,6 +1,7 @@
# test_with_pytest.py
import pytest
import asyncio
from aiomqtt import MqttCodeError
from mock import patch
from enum import Enum
@@ -132,6 +133,22 @@ def patch_no_mqtt():
with patch.object(Mqtt, 'publish') as conn:
yield conn
@pytest.fixture
def patch_mqtt_err():
def new_publish(self, key, data):
raise MqttCodeError(None)
with patch.object(Mqtt, 'publish', new_publish) as conn:
yield conn
@pytest.fixture
def patch_mqtt_except():
def new_publish(self, key, data):
raise ValueError("Test")
with patch.object(Mqtt, 'publish', new_publish) as conn:
yield conn
@pytest.mark.asyncio
async def test_modbus_conn(patch_open):
_ = patch_open
@@ -231,3 +248,67 @@ async def test_modbus_cnf3(config_conn, patch_no_mqtt, patch_open):
assert 2 == test
await asyncio.sleep(0.01)
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
@pytest.mark.asyncio
async def test_mqtt_err(config_conn, patch_mqtt_err, patch_open):
_ = config_conn
_ = patch_open
_ = patch_mqtt_err
global test
assert asyncio.get_running_loop()
Inverter.class_init()
test = TestType.RD_TEST_0_BYTES
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
ModbusTcp(asyncio.get_event_loop(), tim_restart= 0)
await asyncio.sleep(0.01)
test = 0
for m in Message:
if (m.node_id == 'inv_2'):
assert Infos.stat['proxy']['Inverter_Cnt'] == 1
test += 1
if test == 1:
m.shutdown_started = False
m.reader.on_recv.set()
await asyncio.sleep(0.1)
assert m.state == State.closed
await asyncio.sleep(0.1)
else:
m.shutdown_started = True
m.reader.on_recv.set()
del m
await asyncio.sleep(0.01)
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
@pytest.mark.asyncio
async def test_mqtt_except(config_conn, patch_mqtt_except, patch_open):
_ = config_conn
_ = patch_open
_ = patch_mqtt_except
global test
assert asyncio.get_running_loop()
Inverter.class_init()
test = TestType.RD_TEST_0_BYTES
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
ModbusTcp(asyncio.get_event_loop(), tim_restart= 0)
await asyncio.sleep(0.01)
test = 0
for m in Message:
if (m.node_id == 'inv_2'):
assert Infos.stat['proxy']['Inverter_Cnt'] == 1
test += 1
if test == 1:
m.shutdown_started = False
m.reader.on_recv.set()
await asyncio.sleep(0.1)
assert m.state == State.closed
await asyncio.sleep(0.1)
else:
m.shutdown_started = True
m.reader.on_recv.set()
del m
await asyncio.sleep(0.01)
assert Infos.stat['proxy']['Inverter_Cnt'] == 0

View File

@@ -1398,7 +1398,7 @@ def test_msg_inv_ind3(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ack):
m._update_header(m._forward_buffer)
assert m._forward_buffer==msg_inverter_ind_0w
assert m._send_buffer==msg_inverter_ack
assert m.db.get_db_value(Register.INVERTER_STATUS) == None
assert m.db.get_db_value(Register.INVERTER_STATUS) == 1
assert isclose(m.db.db['grid']['Output_Power'], 0.5)
m.close()
assert m.db.get_db_value(Register.INVERTER_STATUS) == 0