diff --git a/goodwe/et.py b/goodwe/et.py index 7007db2..adad714 100644 --- a/goodwe/et.py +++ b/goodwe/et.py @@ -116,7 +116,7 @@ class ET(Inverter): Voltage("nbus_voltage", 35179, "NBus Voltage", None), Voltage("vbattery1", 35180, "Battery Voltage", Kind.BAT), CurrentS("ibattery1", 35181, "Battery Current", Kind.BAT), - Power4("pbattery1", 35182, "Battery Power", Kind.BAT), + Power4S("pbattery1", 35182, "Battery Power", Kind.BAT), Integer("battery_mode", 35184, "Battery Mode code", "", Kind.BAT), Enum2("battery_mode_label", 35184, BATTERY_MODES, "Battery Mode", Kind.BAT), Integer("warning_code", 35185, "Warning code"), @@ -149,7 +149,7 @@ class ET(Inverter): read_bytes4(data, 35109) + read_bytes4(data, 35113) + read_bytes4(data, 35117) + - read_bytes4(data, 35182) - + read_bytes4_signed(data, 35182) - read_bytes2(data, 35140), "House Consumption", "W", Kind.AC), ) @@ -238,10 +238,10 @@ class ET(Inverter): Frequency("meter_freq", 36014, "Meter Frequency", Kind.GRID), Float("meter_e_total_exp", 36015, 1000, "Meter Total Energy (export)", "kWh", Kind.GRID), Float("meter_e_total_imp", 36017, 1000, "Meter Total Energy (import)", "kWh", Kind.GRID), - Power4("meter_active_power1", 36019, "Meter Active Power L1", Kind.GRID), - Power4("meter_active_power2", 36021, "Meter Active Power L2", Kind.GRID), - Power4("meter_active_power3", 36023, "Meter Active Power L3", Kind.GRID), - Power4("meter_active_power_total", 36025, "Meter Active Power Total", Kind.GRID), + Power4S("meter_active_power1", 36019, "Meter Active Power L1", Kind.GRID), + Power4S("meter_active_power2", 36021, "Meter Active Power L2", Kind.GRID), + Power4S("meter_active_power3", 36023, "Meter Active Power L3", Kind.GRID), + Power4S("meter_active_power_total", 36025, "Meter Active Power Total", Kind.GRID), Reactive4("meter_reactive_power1", 36027, "Meter Reactive Power L1", Kind.GRID), Reactive4("meter_reactive_power2", 36029, "Meter Reactive Power L2", Kind.GRID), Reactive4("meter_reactive_power3", 36031, "Meter Reactive Power L2", Kind.GRID), @@ -253,7 +253,7 @@ class ET(Inverter): Integer("meter_type", 36043, "Meter Type", "", Kind.GRID), # (0: Single phase, 1: 3P3W, 2: 3P4W, 3: HomeKit) Integer("meter_sw_version", 36044, "Meter Software Version", "", Kind.GRID), # Sensors added in some ARM fw update, read when flag _has_meter_extended is on - Power4("meter2_active_power", 36045, "Meter 2 Active Power", Kind.GRID), + Power4S("meter2_active_power", 36045, "Meter 2 Active Power", Kind.GRID), Float("meter2_e_total_exp", 36047, 1000, "Meter 2 Total Energy (export)", "kWh", Kind.GRID), Float("meter2_e_total_imp", 36049, 1000, "Meter 2 Total Energy (import)", "kWh", Kind.GRID), Integer("meter2_comm_status", 36051, "Meter 2 Communication Status"), diff --git a/goodwe/sensor.py b/goodwe/sensor.py index cad1db1..c23da4a 100644 --- a/goodwe/sensor.py +++ b/goodwe/sensor.py @@ -142,7 +142,7 @@ def read_value(self, data: ProtocolResponse): class Power4(Sensor): - """Sensor representing power [W] value encoded in 4 bytes""" + """Sensor representing power [W] value encoded in 4 (unsigned) bytes""" def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]): super().__init__(id_, offset, name, 4, "W", kind) @@ -151,6 +151,16 @@ def read_value(self, data: ProtocolResponse): return read_bytes4(data) +class Power4S(Sensor): + """Sensor representing power [W] value encoded in 4 (signed) bytes""" + + def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]): + super().__init__(id_, offset, name, 4, "W", kind) + + def read_value(self, data: ProtocolResponse): + return read_bytes4_signed(data) + + class Energy(Sensor): """Sensor representing energy [kWh] value encoded in 2 bytes""" @@ -172,7 +182,7 @@ def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]) super().__init__(id_, offset, name, 4, "kWh", kind) def read_value(self, data: ProtocolResponse): - value = read_bytes4(data) + value = read_bytes4_signed(data) if value == -1: return None else: @@ -196,7 +206,7 @@ def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]) super().__init__(id_, offset, name, 2, "VA", kind) def read_value(self, data: ProtocolResponse): - return read_bytes4(data) + return read_bytes4_signed(data) class Reactive(Sensor): @@ -216,7 +226,7 @@ def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]) super().__init__(id_, offset, name, 2, "var", kind) def read_value(self, data: ProtocolResponse): - return read_bytes4(data) + return read_bytes4_signed(data) class Temp(Sensor): @@ -303,7 +313,7 @@ def __init__(self, id_: str, offset: int, name: str, unit: str = "", kind: Optio super().__init__(id_, offset, name, 4, unit, kind) def read_value(self, data: ProtocolResponse): - return read_bytes4(data) + return read_bytes4_signed(data) def encode_value(self, value: Any, register_value: bytes = None) -> bytes: return int.to_bytes(int(value), length=4, byteorder="big", signed=True) @@ -403,7 +413,7 @@ def read_value(self, data: ProtocolResponse) -> Any: raise NotImplementedError() def read(self, data: ProtocolResponse): - bits = read_bytes4(data, self.offset) + bits = read_bytes4_signed(data, self.offset) return decode_bitmap(bits if bits != -1 else 0, self._labels) @@ -724,6 +734,14 @@ def read_bytes2(buffer: ProtocolResponse, offset: int = None) -> int: def read_bytes4(buffer: ProtocolResponse, offset: int = None) -> int: + """Retrieve 4 byte (unsigned int) value from buffer""" + if offset is not None: + buffer.seek(offset) + value = int.from_bytes(buffer.read(4), byteorder="big", signed=False) + return value if value != 0xffffffff else 0 + + +def read_bytes4_signed(buffer: ProtocolResponse, offset: int = None) -> int: """Retrieve 4 byte (signed int) value from buffer""" if offset is not None: buffer.seek(offset) @@ -766,7 +784,7 @@ def read_current(buffer: ProtocolResponse, offset: int = None) -> float: if offset is not None: buffer.seek(offset) value = int.from_bytes(buffer.read(2), byteorder="big", signed=False) - return float(value) / 10 + return float(value) / 10 if value != 0xffff else 0 def read_current_signed(buffer: ProtocolResponse, offset: int = None) -> float: diff --git a/tests/test_et.py b/tests/test_et.py index ddacc37..4aaf6df 100644 --- a/tests/test_et.py +++ b/tests/test_et.py @@ -469,7 +469,7 @@ def test_GW6000_EH_runtime_data(self): self.assertSensor('diagnose_result_label', 'Battery voltage low, Battery SOC low, Battery SOC in back, Discharge Driver On, Self-use load light, Battery Disconnected, Self-use off, Export power limit set, PF value set, Real power limit set', '', data) - self.assertSensor('house_consumption', 1710, 'W', data) + self.assertSensor('house_consumption', 1712, 'W', data) class GEH10_1U_10_Test(EtMock): diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 11f659f..d3c9fa5 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -95,6 +95,9 @@ def test_current(self): self.assertEqual(6543.8, testee.read(data)) self.assertEqual("ff9e", testee.encode_value(6543.8).hex()) + data = MockResponse("ffff") + self.assertEqual(0, testee.read(data)) + def test_current_signed(self): testee = CurrentS("", 0, "", None) @@ -112,6 +115,18 @@ def test_power4(self): data = MockResponse("0000069f") self.assertEqual(1695, testee.read(data)) + data = MockResponse("fffffffd") + self.assertEqual(4294967293, testee.read(data)) + + data = MockResponse("ffffffff") + self.assertEqual(0, testee.read(data)) + + def test_power4_signed(self): + testee = Power4S("", 0, "", None) + + data = MockResponse("0000069f") + self.assertEqual(1695, testee.read(data)) + data = MockResponse("fffffffd") self.assertEqual(-3, testee.read(data))