This commit is contained in:
Stefan Allius
2024-08-11 23:22:07 +02:00
committed by GitHub
parent 22df381da5
commit e34afcb523
4 changed files with 59 additions and 57 deletions

View File

@@ -12,12 +12,12 @@ logger_mqtt = logging.getLogger('mqtt')
class Mqtt(metaclass=Singleton): class Mqtt(metaclass=Singleton):
__client = None __client = None
__cb_MqttIsUp = None __cb_mqtt_is_up = None
def __init__(self, cb_MqttIsUp): def __init__(self, cb_mqtt_is_up):
logger_mqtt.debug('MQTT: __init__') logger_mqtt.debug('MQTT: __init__')
if cb_MqttIsUp: if cb_mqtt_is_up:
self.__cb_MqttIsUp = cb_MqttIsUp self.__cb_mqtt_is_up = cb_mqtt_is_up
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
self.task = loop.create_task(self.__loop()) self.task = loop.create_task(self.__loop())
self.ha_restarts = 0 self.ha_restarts = 0
@@ -71,8 +71,8 @@ class Mqtt(metaclass=Singleton):
async with self.__client: async with self.__client:
logger_mqtt.info('MQTT broker connection established') logger_mqtt.info('MQTT broker connection established')
if self.__cb_MqttIsUp: if self.__cb_mqtt_is_up:
await self.__cb_MqttIsUp() await self.__cb_mqtt_is_up()
# async with self.__client.messages() as messages: # async with self.__client.messages() as messages:
await self.__client.subscribe(ha_status_topic) await self.__client.subscribe(ha_status_topic)
@@ -89,7 +89,7 @@ class Mqtt(metaclass=Singleton):
f' {status}') f' {status}')
if status == 'online': if status == 'online':
self.ha_restarts += 1 self.ha_restarts += 1
await self.__cb_MqttIsUp() await self.__cb_mqtt_is_up()
if message.topic.matches(mb_rated_topic): if message.topic.matches(mb_rated_topic):
await self.modbus_cmd(message, await self.modbus_cmd(message,

View File

@@ -4,7 +4,7 @@ from app.src.infos import Register, ClrAtMidnight
from app.src.gen3.infos_g3 import InfosG3 from app.src.gen3.infos_g3 import InfosG3
@pytest.fixture @pytest.fixture
def ContrDataSeq(): # Get Time Request message def contr_data_seq(): # Get Time Request message
msg = b'\x00\x00\x00\x15\x00\x09\x2b\xa8\x54\x10\x52\x53\x57\x5f\x34\x30\x30\x5f\x56\x31\x2e\x30\x30\x2e\x30\x36\x00\x09\x27\xc0\x54\x06\x52\x61\x79\x6d\x6f' msg = b'\x00\x00\x00\x15\x00\x09\x2b\xa8\x54\x10\x52\x53\x57\x5f\x34\x30\x30\x5f\x56\x31\x2e\x30\x30\x2e\x30\x36\x00\x09\x27\xc0\x54\x06\x52\x61\x79\x6d\x6f'
msg += b'\x6e\x00\x09\x2f\x90\x54\x0b\x52\x53\x57\x2d\x31\x2d\x31\x30\x30\x30\x31\x00\x09\x5a\x88\x54\x0f\x74\x2e\x72\x61\x79\x6d\x6f\x6e\x69\x6f\x74\x2e\x63\x6f\x6d\x00\x09\x5a\xec\x54' msg += b'\x6e\x00\x09\x2f\x90\x54\x0b\x52\x53\x57\x2d\x31\x2d\x31\x30\x30\x30\x31\x00\x09\x5a\x88\x54\x0f\x74\x2e\x72\x61\x79\x6d\x6f\x6e\x69\x6f\x74\x2e\x63\x6f\x6d\x00\x09\x5a\xec\x54'
msg += b'\x1c\x6c\x6f\x67\x67\x65\x72\x2e\x74\x61\x6c\x65\x6e\x74\x2d\x6d\x6f\x6e\x69\x74\x6f\x72\x69\x6e\x67\x2e\x63\x6f\x6d\x00\x0d\x00\x20\x49\x00\x00\x00\x01\x00\x0c\x35\x00\x49\x00' msg += b'\x1c\x6c\x6f\x67\x67\x65\x72\x2e\x74\x61\x6c\x65\x6e\x74\x2d\x6d\x6f\x6e\x69\x74\x6f\x72\x69\x6e\x67\x2e\x63\x6f\x6d\x00\x0d\x00\x20\x49\x00\x00\x00\x01\x00\x0c\x35\x00\x49\x00'
@@ -14,7 +14,7 @@ def ContrDataSeq(): # Get Time Request message
return msg return msg
@pytest.fixture @pytest.fixture
def Contr2DataSeq(): # Get Time Request message def contr2_data_seq(): # Get Time Request message
msg = b'\x00\x00\x00\x39\x00\x09\x2b\xa8\x54\x10\x52' msg = b'\x00\x00\x00\x39\x00\x09\x2b\xa8\x54\x10\x52'
msg += b'\x53\x57\x5f\x34\x30\x30\x5f\x56\x31\x2e\x30\x30\x2e\x32\x30\x00' msg += b'\x53\x57\x5f\x34\x30\x30\x5f\x56\x31\x2e\x30\x30\x2e\x32\x30\x00'
msg += b'\x09\x27\xc0\x54\x06\x52\x61\x79\x6d\x6f\x6e\x00\x09\x2f\x90\x54' msg += b'\x09\x27\xc0\x54\x06\x52\x61\x79\x6d\x6f\x6e\x00\x09\x2f\x90\x54'
@@ -94,19 +94,19 @@ def Contr2DataSeq(): # Get Time Request message
return msg return msg
@pytest.fixture @pytest.fixture
def InvDataSeq(): # Data indication from the controller def inv_data_seq(): # Data indication from the controller
msg = b'\x00\x00\x00\x06\x00\x00\x00\x0a\x54\x08\x4d\x69\x63\x72\x6f\x69\x6e\x76\x00\x00\x00\x14\x54\x04\x54\x53\x55\x4e\x00\x00\x00\x1E\x54\x07\x56\x35\x2e\x30\x2e\x31\x31\x00\x00\x00\x28' msg = b'\x00\x00\x00\x06\x00\x00\x00\x0a\x54\x08\x4d\x69\x63\x72\x6f\x69\x6e\x76\x00\x00\x00\x14\x54\x04\x54\x53\x55\x4e\x00\x00\x00\x1E\x54\x07\x56\x35\x2e\x30\x2e\x31\x31\x00\x00\x00\x28'
msg += b'\x54\x10T170000000000001\x00\x00\x00\x32\x54\x0a\x54\x53\x4f\x4c\x2d\x4d\x53\x36\x30\x30\x00\x00\x00\x3c\x54\x05\x41\x2c\x42\x2c\x43' msg += b'\x54\x10T170000000000001\x00\x00\x00\x32\x54\x0a\x54\x53\x4f\x4c\x2d\x4d\x53\x36\x30\x30\x00\x00\x00\x3c\x54\x05\x41\x2c\x42\x2c\x43'
return msg return msg
@pytest.fixture @pytest.fixture
def InvalidDataSeq(): # Data indication from the controller def invalid_data_seq(): # Data indication from the controller
msg = b'\x00\x00\x00\x06\x00\x00\x00\x0a\x54\x08\x4d\x69\x63\x72\x6f\x69\x6e\x76\x00\x00\x00\x14\x64\x04\x54\x53\x55\x4e\x00\x00\x00\x1E\x54\x07\x56\x35\x2e\x30\x2e\x31\x31\x00\x00\x00\x28' msg = b'\x00\x00\x00\x06\x00\x00\x00\x0a\x54\x08\x4d\x69\x63\x72\x6f\x69\x6e\x76\x00\x00\x00\x14\x64\x04\x54\x53\x55\x4e\x00\x00\x00\x1E\x54\x07\x56\x35\x2e\x30\x2e\x31\x31\x00\x00\x00\x28'
msg += b'\x54\x10T170000000000001\x00\x00\x00\x32\x54\x0a\x54\x53\x4f\x4c\x2d\x4d\x53\x36\x30\x30\x00\x00\x00\x3c\x54\x05\x41\x2c\x42\x2c\x43' msg += b'\x54\x10T170000000000001\x00\x00\x00\x32\x54\x0a\x54\x53\x4f\x4c\x2d\x4d\x53\x36\x30\x30\x00\x00\x00\x3c\x54\x05\x41\x2c\x42\x2c\x43'
return msg return msg
@pytest.fixture @pytest.fixture
def InvDataSeq2(): # Data indication from the controller def inv_data_seq2(): # Data indication from the controller
msg = b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x02\x00\x00\x01\x2c\x53\x00\x00\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00' msg = b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x02\x00\x00\x01\x2c\x53\x00\x00\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00'
msg += b'\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00' msg += b'\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00'
msg += b'\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00\x00\x01\x9d\x53' msg += b'\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00\x00\x01\x9d\x53'
@@ -141,7 +141,7 @@ def InvDataSeq2(): # Data indication from the controller
return msg return msg
@pytest.fixture @pytest.fixture
def InvDataNew(): # Data indication from DSP V5.0.17 def inv_data_new(): # Data indication from DSP V5.0.17
msg = b'\x00\x00\x00\xa3\x00\x00\x00\x00\x53\x00\x00' msg = b'\x00\x00\x00\xa3\x00\x00\x00\x00\x53\x00\x00'
msg += b'\x00\x00\x00\x80\x53\x00\x00\x00\x00\x01\x04\x53\x00\x00\x00\x00' msg += b'\x00\x00\x00\x80\x53\x00\x00\x00\x00\x01\x04\x53\x00\x00\x00\x00'
msg += b'\x01\x90\x41\x00\x00\x01\x91\x53\x00\x00\x00\x00\x01\x90\x53\x00' msg += b'\x01\x90\x41\x00\x00\x01\x91\x53\x00\x00\x00\x00\x01\x90\x53\x00'
@@ -217,7 +217,7 @@ def InvDataNew(): # Data indication from DSP V5.0.17
return msg return msg
@pytest.fixture @pytest.fixture
def InvDataSeq2_Zero(): # Data indication from the controller def inv_data_seq2_zero(): # Data indication from the controller
msg = b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x02\x00\x00\x01\x2c\x53\x00\x00\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00' msg = b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x02\x00\x00\x01\x2c\x53\x00\x00\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00'
msg += b'\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00' msg += b'\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00'
msg += b'\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00\x00\x01\x9d\x53' msg += b'\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00\x00\x01\x9d\x53'
@@ -252,37 +252,37 @@ def InvDataSeq2_Zero(): # Data indication from the controller
return msg return msg
def test_parse_control(ContrDataSeq): def test_parse_control(contr_data_seq):
i = InfosG3() i = InfosG3()
for key, result in i.parse (ContrDataSeq): for key, result in i.parse (contr_data_seq):
pass pass # side effect in calling i.parse()
assert json.dumps(i.db) == json.dumps( assert json.dumps(i.db) == json.dumps(
{"collector": {"Collector_Fw_Version": "RSW_400_V1.00.06", "Chip_Type": "Raymon", "Chip_Model": "RSW-1-10001", "Trace_URL": "t.raymoniot.com", "Logger_URL": "logger.talent-monitoring.com"}, "controller": {"Collect_Interval": 1, "Signal_Strength": 100, "Power_On_Time": 29, "Communication_Type": 1, "Connect_Count": 1, "Data_Up_Interval": 300}}) {"collector": {"Collector_Fw_Version": "RSW_400_V1.00.06", "Chip_Type": "Raymon", "Chip_Model": "RSW-1-10001", "Trace_URL": "t.raymoniot.com", "Logger_URL": "logger.talent-monitoring.com"}, "controller": {"Collect_Interval": 1, "Signal_Strength": 100, "Power_On_Time": 29, "Communication_Type": 1, "Connect_Count": 1, "Data_Up_Interval": 300}})
def test_parse_control2(Contr2DataSeq): def test_parse_control2(contr2_data_seq):
i = InfosG3() i = InfosG3()
for key, result in i.parse (Contr2DataSeq): for key, result in i.parse (contr2_data_seq):
pass pass # side effect in calling i.parse()
assert json.dumps(i.db) == json.dumps( assert json.dumps(i.db) == json.dumps(
{"collector": {"Collector_Fw_Version": "RSW_400_V1.00.20", "Chip_Type": "Raymon", "Chip_Model": "RSW-1-10001", "Trace_URL": "t.raymoniot.com", "Logger_URL": "logger.talent-monitoring.com"}, "controller": {"Collect_Interval": 1, "Signal_Strength": 16, "Power_On_Time": 334, "Communication_Type": 1, "Connect_Count": 1, "Data_Up_Interval": 300}}) {"collector": {"Collector_Fw_Version": "RSW_400_V1.00.20", "Chip_Type": "Raymon", "Chip_Model": "RSW-1-10001", "Trace_URL": "t.raymoniot.com", "Logger_URL": "logger.talent-monitoring.com"}, "controller": {"Collect_Interval": 1, "Signal_Strength": 16, "Power_On_Time": 334, "Communication_Type": 1, "Connect_Count": 1, "Data_Up_Interval": 300}})
def test_parse_inverter(InvDataSeq): def test_parse_inverter(inv_data_seq):
i = InfosG3() i = InfosG3()
for key, result in i.parse (InvDataSeq): for key, result in i.parse (inv_data_seq):
pass pass # side effect in calling i.parse()
assert json.dumps(i.db) == json.dumps( assert json.dumps(i.db) == json.dumps(
{"inverter": {"Product_Name": "Microinv", "Manufacturer": "TSUN", "Version": "V5.0.11", "Serial_Number": "T170000000000001", "Equipment_Model": "TSOL-MS600"}}) {"inverter": {"Product_Name": "Microinv", "Manufacturer": "TSUN", "Version": "V5.0.11", "Serial_Number": "T170000000000001", "Equipment_Model": "TSOL-MS600"}})
def test_parse_cont_and_invert(ContrDataSeq, InvDataSeq): def test_parse_cont_and_invert(contr_data_seq, inv_data_seq):
i = InfosG3() i = InfosG3()
for key, result in i.parse (ContrDataSeq): for key, result in i.parse (contr_data_seq):
pass pass # side effect in calling i.parse()
for key, result in i.parse (InvDataSeq): for key, result in i.parse (inv_data_seq):
pass pass # side effect in calling i.parse()
assert json.dumps(i.db) == json.dumps( assert json.dumps(i.db) == json.dumps(
{ {
@@ -290,7 +290,7 @@ def test_parse_cont_and_invert(ContrDataSeq, InvDataSeq):
"inverter": {"Product_Name": "Microinv", "Manufacturer": "TSUN", "Version": "V5.0.11", "Serial_Number": "T170000000000001", "Equipment_Model": "TSOL-MS600"}}) "inverter": {"Product_Name": "Microinv", "Manufacturer": "TSUN", "Version": "V5.0.11", "Serial_Number": "T170000000000001", "Equipment_Model": "TSOL-MS600"}})
def test_build_ha_conf1(ContrDataSeq): def test_build_ha_conf1(contr_data_seq):
i = InfosG3() i = InfosG3()
i.static_init() # initialize counter i.static_init() # initialize counter
@@ -346,14 +346,14 @@ def test_build_ha_conf1(ContrDataSeq):
assert tests==5 assert tests==5
def test_build_ha_conf2(ContrDataSeq, InvDataSeq, InvDataSeq2): def test_build_ha_conf2(contr_data_seq, inv_data_seq, inv_data_seq2):
i = InfosG3() i = InfosG3()
for key, result in i.parse (ContrDataSeq): for key, result in i.parse (contr_data_seq):
pass pass # side effect in calling i.parse()
for key, result in i.parse (InvDataSeq): for key, result in i.parse (inv_data_seq):
pass pass # side effect in calling i.parse()
for key, result in i.parse (InvDataSeq2): for key, result in i.parse (inv_data_seq2):
pass pass # side effect in calling i.parse()
tests = 0 tests = 0
for d_json, comp, node_id, id in i.ha_confs(ha_prfx="tsun/", node_id="garagendach/", snr='123', sug_area = 'roof'): for d_json, comp, node_id, id in i.ha_confs(ha_prfx="tsun/", node_id="garagendach/", snr='123', sug_area = 'roof'):
@@ -384,10 +384,10 @@ def test_build_ha_conf2(ContrDataSeq, InvDataSeq, InvDataSeq2):
tests +=1 tests +=1
assert tests==5 assert tests==5
def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero): def test_must_incr_total(inv_data_seq2, inv_data_seq2_zero):
i = InfosG3() i = InfosG3()
tests = 0 tests = 0
for key, update in i.parse (InvDataSeq2): for key, update in i.parse (inv_data_seq2):
if key == 'total' or key == 'inverter' or key == 'env': if key == 'total' or key == 'inverter' or key == 'env':
assert update == True assert update == True
tests +=1 tests +=1
@@ -396,7 +396,7 @@ def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero):
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['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_Temp": 23})
tests = 0 tests = 0
for key, update in i.parse (InvDataSeq2): for key, update in i.parse (inv_data_seq2):
if key == 'total': if key == 'total':
assert update == False assert update == False
tests +=1 tests +=1
@@ -411,7 +411,7 @@ def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero):
assert json.dumps(i.db['inverter']) == json.dumps({"Rated_Power": 600, "No_Inputs": 2}) assert json.dumps(i.db['inverter']) == json.dumps({"Rated_Power": 600, "No_Inputs": 2})
tests = 0 tests = 0
for key, update in i.parse (InvDataSeq2_Zero): for key, update in i.parse (inv_data_seq2_zero):
if key == 'total': if key == 'total':
assert update == False assert update == False
tests +=1 tests +=1
@@ -424,10 +424,10 @@ def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero):
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['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_Temp": 0})
def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero): def test_must_incr_total2(inv_data_seq2, inv_data_seq2_zero):
i = InfosG3() i = InfosG3()
tests = 0 tests = 0
for key, update in i.parse (InvDataSeq2_Zero): for key, update in i.parse (inv_data_seq2_zero):
if key == 'total': if key == 'total':
assert update == False assert update == False
tests +=1 tests +=1
@@ -441,7 +441,7 @@ def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero):
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0}) assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0})
tests = 0 tests = 0
for key, update in i.parse (InvDataSeq2_Zero): for key, update in i.parse (inv_data_seq2_zero):
if key == 'total': if key == 'total':
assert update == False assert update == False
tests +=1 tests +=1
@@ -455,7 +455,7 @@ def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero):
assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0}) assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0})
tests = 0 tests = 0
for key, update in i.parse (InvDataSeq2): for key, update in i.parse (inv_data_seq2):
if key == 'total': if key == 'total':
assert update == True assert update == True
tests +=1 tests +=1
@@ -467,10 +467,10 @@ def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero):
assert json.dumps(i.db['total']) == json.dumps({'Daily_Generation': 1.7, 'Total_Generation': 17.36}) 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['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}})
def test_new_data_types(InvDataNew): def test_new_data_types(inv_data_new):
i = InfosG3() i = InfosG3()
tests = 0 tests = 0
for key, update in i.parse (InvDataNew): for key, update in i.parse (inv_data_new):
if key == 'events': if key == 'events':
tests +=1 tests +=1
elif key == 'inverter': elif key == 'inverter':
@@ -487,7 +487,7 @@ def test_new_data_types(InvDataNew):
assert json.dumps(i.db['input']) == json.dumps({"pv1": {}}) assert json.dumps(i.db['input']) == json.dumps({"pv1": {}})
assert json.dumps(i.db['events']) == json.dumps({"401_": 0, "404_": 0, "405_": 0, "408_": 0, "409_No_Utility": 0, "406_": 0, "416_": 0}) assert json.dumps(i.db['events']) == json.dumps({"401_": 0, "404_": 0, "405_": 0, "408_": 0, "409_No_Utility": 0, "406_": 0, "416_": 0})
def test_invalid_data_type(InvalidDataSeq): def test_invalid_data_type(invalid_data_seq):
i = InfosG3() i = InfosG3()
i.static_init() # initialize counter i.static_init() # initialize counter
@@ -495,8 +495,8 @@ def test_invalid_data_type(InvalidDataSeq):
assert val == 0 assert val == 0
for key, result in i.parse (InvalidDataSeq): for key, result in i.parse (invalid_data_seq):
pass pass # side effect in calling i.parse()
assert json.dumps(i.db) == json.dumps({"inverter": {"Product_Name": "Microinv"}}) assert json.dumps(i.db) == json.dumps({"inverter": {"Product_Name": "Microinv"}})
val = i.dev_value(Register.INVALID_DATA_TYPE) # check invalid data type counter val = i.dev_value(Register.INVALID_DATA_TYPE) # check invalid data type counter

View File

@@ -3,6 +3,7 @@ import struct
import time import time
import asyncio import asyncio
import logging import logging
from math import isclose
from app.src.gen3plus.solarman_v5 import SolarmanV5 from app.src.gen3plus.solarman_v5 import SolarmanV5
from app.src.config import Config from app.src.config import Config
from app.src.infos import Infos, Register from app.src.infos import Infos, Register
@@ -1665,7 +1666,7 @@ async def test_modbus_polling(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp
m._send_buffer = bytearray(0) # clear send buffer for next test m._send_buffer = bytearray(0) # clear send buffer for next test
assert m.state == State.up assert m.state == State.up
assert m.mb_timeout == 0.5 assert isclose(m.mb_timeout, 0.5)
assert next(m.mb_timer.exp_count) == 0 assert next(m.mb_timer.exp_count) == 0
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
@@ -1695,14 +1696,14 @@ async def test_start_client_mode(config_tsun_inv1):
await m.send_start_cmd(get_sn_int(), '192.168.1.1', m.mb_first_timeout) await m.send_start_cmd(get_sn_int(), '192.168.1.1', m.mb_first_timeout)
assert m.writer.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x01\x00!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x030\x00\x000J\xde\xf1\x15') assert m.writer.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x01\x00!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x030\x00\x000J\xde\xf1\x15')
assert m.db.get_db_value(Register.IP_ADDRESS) == '192.168.1.1' assert m.db.get_db_value(Register.IP_ADDRESS) == '192.168.1.1'
assert m.db.get_db_value(Register.POLLING_INTERVAL) == 0.5 assert isclose(m.db.get_db_value(Register.POLLING_INTERVAL), 0.5)
assert m.db.get_db_value(Register.HEARTBEAT_INTERVAL) == 120 assert m.db.get_db_value(Register.HEARTBEAT_INTERVAL) == 120
assert m.state == State.up assert m.state == State.up
assert m.no_forwarding == True assert m.no_forwarding == True
assert m._send_buffer==b'' assert m._send_buffer==b''
assert m.mb_timeout == 0.5 assert isclose(m.mb_timeout, 0.5)
assert next(m.mb_timer.exp_count) == 0 assert next(m.mb_timer.exp_count) == 0
await asyncio.sleep(0.5) await asyncio.sleep(0.5)

View File

@@ -1,5 +1,6 @@
# test_with_pytest.py # test_with_pytest.py
import pytest, logging, asyncio import pytest, logging, asyncio
from math import isclose
from app.src.gen3.talent import Talent, Control from app.src.gen3.talent import Talent, Control
from app.src.config import Config from app.src.config import Config
from app.src.infos import Infos, Register from app.src.infos import Infos, Register
@@ -1023,7 +1024,7 @@ def test_msg_inv_ind3(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ack):
assert m._forward_buffer==msg_inverter_ind_0w assert m._forward_buffer==msg_inverter_ind_0w
assert m._send_buffer==msg_inverter_ack 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) == None
assert m.db.db['grid']['Output_Power'] == 0.5 assert isclose(m.db.db['grid']['Output_Power'], 0.5)
m.close() m.close()
assert m.db.get_db_value(Register.INVERTER_STATUS) == 0 assert m.db.get_db_value(Register.INVERTER_STATUS) == 0
@@ -1206,15 +1207,15 @@ def test_timestamp_cnv():
m = MemoryStream(b'') m = MemoryStream(b'')
ts = 1722645998453 # Saturday, 3. August 2024 00:46:38.453 (GMT+2:00) ts = 1722645998453 # Saturday, 3. August 2024 00:46:38.453 (GMT+2:00)
utc =1722638798.453 # GMT: Friday, 2. August 2024 22:46:38.453 utc =1722638798.453 # GMT: Friday, 2. August 2024 22:46:38.453
assert utc == m._utcfromts(ts) assert isclose(utc, m._utcfromts(ts))
ts = 1691246944000 # Saturday, 5. August 2023 14:49:04 (GMT+2:00) ts = 1691246944000 # Saturday, 5. August 2023 14:49:04 (GMT+2:00)
utc =1691239744.0 # GMT: Saturday, 5. August 2023 12:49:04 utc =1691239744.0 # GMT: Saturday, 5. August 2023 12:49:04
assert utc == m._utcfromts(ts) assert isclose(utc, m._utcfromts(ts))
ts = 1704152544000 # Monday, 1. January 2024 23:42:24 (GMT+1:00) ts = 1704152544000 # Monday, 1. January 2024 23:42:24 (GMT+1:00)
utc =1704148944.0 # GMT: Monday, 1. January 2024 22:42:24 utc =1704148944.0 # GMT: Monday, 1. January 2024 22:42:24
assert utc == m._utcfromts(ts) assert isclose(utc, m._utcfromts(ts))
m.close() m.close()
@@ -1581,7 +1582,7 @@ async def test_modbus_polling(config_tsun_inv1, msg_inverter_ind):
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
m._send_buffer = bytearray(0) # clear send buffer for next test m._send_buffer = bytearray(0) # clear send buffer for next test
assert m.mb_timeout == 0.5 assert isclose(m.mb_timeout, 0.5)
assert next(m.mb_timer.exp_count) == 0 assert next(m.mb_timer.exp_count) == 0
await asyncio.sleep(0.5) await asyncio.sleep(0.5)