diff --git a/omnikinverter/tcp.py b/omnikinverter/tcp.py index 949eda8..6908996 100644 --- a/omnikinverter/tcp.py +++ b/omnikinverter/tcp.py @@ -255,10 +255,15 @@ def int_to_bool(num: int) -> bool: 1: True, }[num] + # Set temperature to None if it matches 65326, this is returned + # when the inverter is "offline". + def temperature_to_float(temp: int) -> Optional[float]: + return None if temp == 65326 else temp * 0.1 + # Only these fields will be extracted from the structure field_extractors = { "serial_number": None, - "temperature": 0.1, + "temperature": temperature_to_float, "dc_input_voltage": list_divide_10, "dc_input_current": list_divide_10, "ac_output_current": list_divide_10, @@ -272,10 +277,11 @@ def int_to_bool(num: int) -> bool: "firmware_slave": None, } - result = {} + result: dict[str, Any] = {} for (name, extractor) in field_extractors.items(): value = getattr(tcp_data, name) + if name == "ac_output": # Flatten the list of frequency+power AC objects diff --git a/tests/fixtures/tcp_reply_offline.data b/tests/fixtures/tcp_reply_offline.data new file mode 100644 index 0000000..95bba54 Binary files /dev/null and b/tests/fixtures/tcp_reply_offline.data differ diff --git a/tests/test_models.py b/tests/test_models.py index 54290e2..d12ad97 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -569,6 +569,52 @@ def recv_side_effect(_max_bytes: int) -> bytes: assert inverter.firmware == "NL1-V1.0-0077-4" assert inverter.firmware_slave == "V2.0-0024" + async def test_inverter_tcp_offline(self) -> None: + """Test request from an Inverter (offline) - TCP source.""" + serial_number = 1608449224 + socket_mock = asynctest.SocketMock() + socket_mock.type = socket.SOCK_STREAM + + def send_side_effect(data: bytes) -> int: + assert data == tcp.create_information_request(serial_number) + asynctest.set_read_ready(socket_mock, self.loop) + return len(data) + + def recv_side_effect(_max_bytes: int) -> bytes: + return load_fixture_bytes("tcp_reply_offline.data") + + socket_mock.send.side_effect = send_side_effect + socket_mock.recv.side_effect = recv_side_effect + + client = OmnikInverter( + host="example.com", + source_type="tcp", + serial_number=serial_number, + _socket_mock=socket_mock, + ) + + inverter: Inverter = await client.inverter() + + assert inverter + assert inverter.solar_rated_power is None + assert inverter.solar_current_power == 0 + + assert inverter.model is None + assert inverter.serial_number == "NLBN4020157P9024" + assert inverter.temperature is None + assert inverter.dc_input_voltage == [0.0, 0.0, 0.0] + assert inverter.dc_input_current == [0.0, 0.0, 0.0] + assert inverter.ac_output_voltage == [0.0, 0.0, 0.0] + assert inverter.ac_output_current == [0.0, 0.0, 0.0] + assert inverter.ac_output_frequency == [0.0, 0.0, 0.0] + assert inverter.ac_output_power == [0.0, 0.0, 0.0] + assert inverter.solar_energy_today == 4.7 + assert inverter.solar_energy_total == 15818.0 + assert inverter.solar_hours_total == 0 + assert inverter.inverter_active is False + assert inverter.firmware == "" + assert inverter.firmware_slave == "" + async def test_connection_broken(self) -> None: """Test on connection broken after success - TCP source.""" serial_number = 1