Skip to content

Commit

Permalink
Fix decoding of current values
Browse files Browse the repository at this point in the history
Current sensors are encoded as both signed and unsigned values.
Former Current sensor is now U16, new CurrentS is for S16 values.
  • Loading branch information
mletenay committed Apr 8, 2024
1 parent c2f1de0 commit 895500a
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 7 deletions.
2 changes: 1 addition & 1 deletion goodwe/et.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class ET(Inverter):
Voltage("bus_voltage", 35178, "Bus Voltage", None),
Voltage("nbus_voltage", 35179, "NBus Voltage", None),
Voltage("vbattery1", 35180, "Battery Voltage", Kind.BAT),
Current("ibattery1", 35181, "Battery Current", Kind.BAT),
CurrentS("ibattery1", 35181, "Battery Current", Kind.BAT),
Power4("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),
Expand Down
38 changes: 32 additions & 6 deletions goodwe/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def is_in_range(self, value: int) -> bool:


class Voltage(Sensor):
"""Sensor representing voltage [V] value encoded in 2 bytes"""
"""Sensor representing voltage [V] value encoded in 2 (unsigned) bytes"""

def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
super().__init__(id_, offset, name, 2, "V", kind)
Expand All @@ -96,7 +96,7 @@ def encode_value(self, value: Any, register_value: bytes = None) -> bytes:


class Current(Sensor):
"""Sensor representing current [A] value encoded in 2 bytes"""
"""Sensor representing current [A] value encoded in 2 (unsigned) bytes"""

def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
super().__init__(id_, offset, name, 2, "A", kind)
Expand All @@ -108,6 +108,19 @@ def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
return encode_current(value)


class CurrentS(Sensor):
"""Sensor representing current [A] value encoded in 2 (signed) bytes"""

def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
super().__init__(id_, offset, name, 2, "A", kind)

def read_value(self, data: ProtocolResponse):
return read_current_signed(data)

def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
return encode_current_signed(value)


class Frequency(Sensor):
"""Sensor representing frequency [Hz] value encoded in 2 bytes"""

Expand Down Expand Up @@ -736,28 +749,41 @@ def read_float4(buffer: ProtocolResponse, offset: int = None) -> float:


def read_voltage(buffer: ProtocolResponse, offset: int = None) -> float:
"""Retrieve voltage [V] value (2 bytes) from buffer"""
"""Retrieve voltage [V] value (2 unsigned bytes) from buffer"""
if offset is not None:
buffer.seek(offset)
value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
return float(value) / 10 if value != 0xffff else 0


def encode_voltage(value: Any) -> bytes:
"""Encode voltage value to raw (2 bytes) payload"""
"""Encode voltage value to raw (2 unsigned bytes) payload"""
return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=False)


def read_current(buffer: ProtocolResponse, offset: int = None) -> float:
"""Retrieve current [A] value (2 bytes) from buffer"""
"""Retrieve current [A] value (2 unsigned bytes) from buffer"""
if offset is not None:
buffer.seek(offset)
value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
return float(value) / 10


def read_current_signed(buffer: ProtocolResponse, offset: int = None) -> float:
"""Retrieve current [A] value (2 signed bytes) from buffer"""
if offset is not None:
buffer.seek(offset)
value = int.from_bytes(buffer.read(2), byteorder="big", signed=True)
return float(value) / 10


def encode_current(value: Any) -> bytes:
"""Encode current value to raw (2 bytes) payload"""
"""Encode current value to raw (2 unsigned bytes) payload"""
return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=False)


def encode_current_signed(value: Any) -> bytes:
"""Encode current value to raw (2 signed bytes) payload"""
return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=True)


Expand Down
17 changes: 17 additions & 0 deletions tests/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,30 @@ def test_voltage(self):
self.assertEqual(803.6, testee.read(data))
self.assertEqual("1f64", testee.encode_value(803.6).hex())

data = MockResponse("a000")
self.assertEqual(4096.0, testee.read(data))

data = MockResponse("ffff")
self.assertEqual(0, testee.read(data))

def test_current(self):
testee = Current("", 0, "", None)

data = MockResponse("0031")
self.assertEqual(4.9, testee.read(data))
self.assertEqual("0031", testee.encode_value(4.9).hex())

data = MockResponse("ff9e")
self.assertEqual(6543.8, testee.read(data))
self.assertEqual("ff9e", testee.encode_value(6543.8).hex())

def test_current_signed(self):
testee = CurrentS("", 0, "", None)

data = MockResponse("0031")
self.assertEqual(4.9, testee.read(data))
self.assertEqual("0031", testee.encode_value(4.9).hex())

data = MockResponse("ff9e")
self.assertEqual(-9.8, testee.read(data))
self.assertEqual("ff9e", testee.encode_value(-9.8).hex())
Expand Down

0 comments on commit 895500a

Please sign in to comment.