goodwe 0.3.1__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. {goodwe-0.3.1/goodwe.egg-info → goodwe-0.3.2}/PKG-INFO +1 -1
  2. goodwe-0.3.2/VERSION +1 -0
  3. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/es.py +3 -3
  4. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/et.py +26 -26
  5. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/sensor.py +87 -31
  6. {goodwe-0.3.1 → goodwe-0.3.2/goodwe.egg-info}/PKG-INFO +1 -1
  7. {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_dt.py +9 -9
  8. {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_et.py +3 -3
  9. {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_sensor.py +33 -1
  10. goodwe-0.3.1/VERSION +0 -1
  11. {goodwe-0.3.1 → goodwe-0.3.2}/LICENSE +0 -0
  12. {goodwe-0.3.1 → goodwe-0.3.2}/README.md +0 -0
  13. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/__init__.py +0 -0
  14. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/const.py +0 -0
  15. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/dt.py +0 -0
  16. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/exceptions.py +0 -0
  17. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/inverter.py +0 -0
  18. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/modbus.py +0 -0
  19. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/model.py +0 -0
  20. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/protocol.py +0 -0
  21. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe.egg-info/SOURCES.txt +0 -0
  22. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe.egg-info/dependency_links.txt +0 -0
  23. {goodwe-0.3.1 → goodwe-0.3.2}/goodwe.egg-info/top_level.txt +0 -0
  24. {goodwe-0.3.1 → goodwe-0.3.2}/pyproject.toml +0 -0
  25. {goodwe-0.3.1 → goodwe-0.3.2}/setup.cfg +0 -0
  26. {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_es.py +0 -0
  27. {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_modbus.py +0 -0
  28. {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_protocol.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goodwe
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Read data from GoodWe inverter via local network
5
5
  Home-page: https://github.com/marcelblijleven/goodwe
6
6
  Author: Martin Letenay, Marcel Blijleven
goodwe-0.3.2/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.2
@@ -67,7 +67,7 @@ class ES(Inverter):
67
67
  Voltage("vgrid", 34, "On-grid Voltage", Kind.AC),
68
68
  Current("igrid", 36, "On-grid Current", Kind.AC),
69
69
  Calculated("pgrid",
70
- lambda data: abs(read_bytes2(data, 38)) * (-1 if read_byte(data, 80) == 2 else 1),
70
+ lambda data: abs(read_bytes2_signed(data, 38)) * (-1 if read_byte(data, 80) == 2 else 1),
71
71
  "On-grid Export Power", "W", Kind.AC),
72
72
  Frequency("fgrid", 40, "On-grid Frequency", Kind.AC),
73
73
  Byte("grid_mode", 42, "Work Mode code", "", Kind.GRID),
@@ -87,7 +87,7 @@ class ES(Inverter):
87
87
  Energy("e_day", 67, "Today's PV Generation", Kind.PV),
88
88
  Energy("e_load_day", 69, "Today's Load", Kind.AC),
89
89
  Energy4("e_load_total", 71, "Total Load", Kind.AC),
90
- Power("total_power", 75, "Total Power", Kind.AC), # modbus 0x52c
90
+ PowerS("total_power", 75, "Total Power", Kind.AC), # modbus 0x52c
91
91
  Byte("effective_work_mode", 77, "Effective Work Mode code"),
92
92
  Integer("effective_relay_control", 78, "Effective Relay Control", "", None),
93
93
  Byte("grid_in_out", 80, "On-grid Mode code", "", Kind.GRID),
@@ -121,7 +121,7 @@ class ES(Inverter):
121
121
  round(read_voltage(data, 5) * read_current(data, 7)) +
122
122
  (abs(round(read_voltage(data, 10) * read_current(data, 18))) *
123
123
  (-1 if read_byte(data, 30) == 3 else 1)) -
124
- (abs(read_bytes2(data, 38)) * (-1 if read_byte(data, 80) == 2 else 1)),
124
+ (abs(read_bytes2_signed(data, 38)) * (-1 if read_byte(data, 80) == 2 else 1)),
125
125
  "House Consumption", "W", Kind.AC),
126
126
  )
127
127
 
@@ -52,23 +52,23 @@ class ET(Inverter):
52
52
  Current("igrid", 35122, "On-grid L1 Current", Kind.AC),
53
53
  Frequency("fgrid", 35123, "On-grid L1 Frequency", Kind.AC),
54
54
  # 35124 reserved
55
- Power("pgrid", 35125, "On-grid L1 Power", Kind.AC),
55
+ PowerS("pgrid", 35125, "On-grid L1 Power", Kind.AC),
56
56
  Voltage("vgrid2", 35126, "On-grid L2 Voltage", Kind.AC),
57
57
  Current("igrid2", 35127, "On-grid L2 Current", Kind.AC),
58
58
  Frequency("fgrid2", 35128, "On-grid L2 Frequency", Kind.AC),
59
59
  # 35129 reserved
60
- Power("pgrid2", 35130, "On-grid L2 Power", Kind.AC),
60
+ PowerS("pgrid2", 35130, "On-grid L2 Power", Kind.AC),
61
61
  Voltage("vgrid3", 35131, "On-grid L3 Voltage", Kind.AC),
62
62
  Current("igrid3", 35132, "On-grid L3 Current", Kind.AC),
63
63
  Frequency("fgrid3", 35133, "On-grid L3 Frequency", Kind.AC),
64
64
  # 35134 reserved
65
- Power("pgrid3", 35135, "On-grid L3 Power", Kind.AC),
65
+ PowerS("pgrid3", 35135, "On-grid L3 Power", Kind.AC),
66
66
  Integer("grid_mode", 35136, "Grid Mode code", "", Kind.PV),
67
67
  Enum2("grid_mode_label", 35136, GRID_MODES, "Grid Mode", Kind.PV),
68
68
  # 35137 reserved
69
- Power("total_inverter_power", 35138, "Total Power", Kind.AC),
69
+ PowerS("total_inverter_power", 35138, "Total Power", Kind.AC),
70
70
  # 35139 reserved
71
- Power("active_power", 35140, "Active Power", Kind.GRID),
71
+ PowerS("active_power", 35140, "Active Power", Kind.GRID),
72
72
  Calculated("grid_in_out",
73
73
  lambda data: read_grid_mode(data, 35140),
74
74
  "On-grid Mode code", "", Kind.GRID),
@@ -84,29 +84,29 @@ class ET(Inverter):
84
84
  Frequency("backup_f1", 35147, "Back-up L1 Frequency", Kind.UPS),
85
85
  Integer("load_mode1", 35148, "Load Mode L1"),
86
86
  # 35149 reserved
87
- Power("backup_p1", 35150, "Back-up L1 Power", Kind.UPS),
87
+ PowerS("backup_p1", 35150, "Back-up L1 Power", Kind.UPS),
88
88
  Voltage("backup_v2", 35151, "Back-up L2 Voltage", Kind.UPS),
89
89
  Current("backup_i2", 35152, "Back-up L2 Current", Kind.UPS),
90
90
  Frequency("backup_f2", 35153, "Back-up L2 Frequency", Kind.UPS),
91
91
  Integer("load_mode2", 35154, "Load Mode L2"),
92
92
  # 35155 reserved
93
- Power("backup_p2", 35156, "Back-up L2 Power", Kind.UPS),
93
+ PowerS("backup_p2", 35156, "Back-up L2 Power", Kind.UPS),
94
94
  Voltage("backup_v3", 35157, "Back-up L3 Voltage", Kind.UPS),
95
95
  Current("backup_i3", 35158, "Back-up L3 Current", Kind.UPS),
96
96
  Frequency("backup_f3", 35159, "Back-up L3 Frequency", Kind.UPS),
97
97
  Integer("load_mode3", 35160, "Load Mode L3"),
98
98
  # 35161 reserved
99
- Power("backup_p3", 35162, "Back-up L3 Power", Kind.UPS),
99
+ PowerS("backup_p3", 35162, "Back-up L3 Power", Kind.UPS),
100
100
  # 35163 reserved
101
- Power("load_p1", 35164, "Load L1", Kind.AC),
101
+ PowerS("load_p1", 35164, "Load L1", Kind.AC),
102
102
  # 35165 reserved
103
- Power("load_p2", 35166, "Load L2", Kind.AC),
103
+ PowerS("load_p2", 35166, "Load L2", Kind.AC),
104
104
  # 35167 reserved
105
- Power("load_p3", 35168, "Load L3", Kind.AC),
105
+ PowerS("load_p3", 35168, "Load L3", Kind.AC),
106
106
  # 35169 reserved
107
- Power("backup_ptotal", 35170, "Back-up Load", Kind.UPS),
107
+ PowerS("backup_ptotal", 35170, "Back-up Load", Kind.UPS),
108
108
  # 35171 reserved
109
- Power("load_ptotal", 35172, "Load", Kind.AC),
109
+ PowerS("load_ptotal", 35172, "Load", Kind.AC),
110
110
  Integer("ups_load", 35173, "Ups Load", "%", Kind.UPS),
111
111
  Temp("temperature_air", 35174, "Inverter Temperature (Air)", Kind.AC),
112
112
  Temp("temperature_module", 35175, "Inverter Temperature (Module)"),
@@ -115,8 +115,8 @@ class ET(Inverter):
115
115
  Voltage("bus_voltage", 35178, "Bus Voltage", None),
116
116
  Voltage("nbus_voltage", 35179, "NBus Voltage", None),
117
117
  Voltage("vbattery1", 35180, "Battery Voltage", Kind.BAT),
118
- Current("ibattery1", 35181, "Battery Current", Kind.BAT),
119
- Power4("pbattery1", 35182, "Battery Power", Kind.BAT),
118
+ CurrentS("ibattery1", 35181, "Battery Current", Kind.BAT),
119
+ Power4S("pbattery1", 35182, "Battery Power", Kind.BAT),
120
120
  Integer("battery_mode", 35184, "Battery Mode code", "", Kind.BAT),
121
121
  Enum2("battery_mode_label", 35184, BATTERY_MODES, "Battery Mode", Kind.BAT),
122
122
  Integer("warning_code", 35185, "Warning code"),
@@ -149,8 +149,8 @@ class ET(Inverter):
149
149
  read_bytes4(data, 35109) +
150
150
  read_bytes4(data, 35113) +
151
151
  read_bytes4(data, 35117) +
152
- read_bytes4(data, 35182) -
153
- read_bytes2(data, 35140),
152
+ read_bytes4_signed(data, 35182) -
153
+ read_bytes2_signed(data, 35140),
154
154
  "House Consumption", "W", Kind.AC),
155
155
  )
156
156
 
@@ -226,10 +226,10 @@ class ET(Inverter):
226
226
  Integer("manufacture_code", 36002, "Manufacture Code"),
227
227
  Integer("meter_test_status", 36003, "Meter Test Status"), # 1: correct,2: reverse,3: incorrect,0: not checked
228
228
  Integer("meter_comm_status", 36004, "Meter Communication Status"), # 1 OK, 0 NotOK
229
- Power("active_power1", 36005, "Active Power L1", Kind.GRID),
230
- Power("active_power2", 36006, "Active Power L2", Kind.GRID),
231
- Power("active_power3", 36007, "Active Power L3", Kind.GRID),
232
- Power("active_power_total", 36008, "Active Power Total", Kind.GRID),
229
+ PowerS("active_power1", 36005, "Active Power L1", Kind.GRID),
230
+ PowerS("active_power2", 36006, "Active Power L2", Kind.GRID),
231
+ PowerS("active_power3", 36007, "Active Power L3", Kind.GRID),
232
+ PowerS("active_power_total", 36008, "Active Power Total", Kind.GRID),
233
233
  Reactive("reactive_power_total", 36009, "Reactive Power Total", Kind.GRID),
234
234
  Decimal("meter_power_factor1", 36010, 1000, "Meter Power Factor L1", "", Kind.GRID),
235
235
  Decimal("meter_power_factor2", 36011, 1000, "Meter Power Factor L2", "", Kind.GRID),
@@ -238,10 +238,10 @@ class ET(Inverter):
238
238
  Frequency("meter_freq", 36014, "Meter Frequency", Kind.GRID),
239
239
  Float("meter_e_total_exp", 36015, 1000, "Meter Total Energy (export)", "kWh", Kind.GRID),
240
240
  Float("meter_e_total_imp", 36017, 1000, "Meter Total Energy (import)", "kWh", Kind.GRID),
241
- Power4("meter_active_power1", 36019, "Meter Active Power L1", Kind.GRID),
242
- Power4("meter_active_power2", 36021, "Meter Active Power L2", Kind.GRID),
243
- Power4("meter_active_power3", 36023, "Meter Active Power L3", Kind.GRID),
244
- Power4("meter_active_power_total", 36025, "Meter Active Power Total", Kind.GRID),
241
+ Power4S("meter_active_power1", 36019, "Meter Active Power L1", Kind.GRID),
242
+ Power4S("meter_active_power2", 36021, "Meter Active Power L2", Kind.GRID),
243
+ Power4S("meter_active_power3", 36023, "Meter Active Power L3", Kind.GRID),
244
+ Power4S("meter_active_power_total", 36025, "Meter Active Power Total", Kind.GRID),
245
245
  Reactive4("meter_reactive_power1", 36027, "Meter Reactive Power L1", Kind.GRID),
246
246
  Reactive4("meter_reactive_power2", 36029, "Meter Reactive Power L2", Kind.GRID),
247
247
  Reactive4("meter_reactive_power3", 36031, "Meter Reactive Power L2", Kind.GRID),
@@ -253,7 +253,7 @@ class ET(Inverter):
253
253
  Integer("meter_type", 36043, "Meter Type", "", Kind.GRID), # (0: Single phase, 1: 3P3W, 2: 3P4W, 3: HomeKit)
254
254
  Integer("meter_sw_version", 36044, "Meter Software Version", "", Kind.GRID),
255
255
  # Sensors added in some ARM fw update, read when flag _has_meter_extended is on
256
- Power4("meter2_active_power", 36045, "Meter 2 Active Power", Kind.GRID),
256
+ Power4S("meter2_active_power", 36045, "Meter 2 Active Power", Kind.GRID),
257
257
  Float("meter2_e_total_exp", 36047, 1000, "Meter 2 Total Energy (export)", "kWh", Kind.GRID),
258
258
  Float("meter2_e_total_imp", 36049, 1000, "Meter 2 Total Energy (import)", "kWh", Kind.GRID),
259
259
  Integer("meter2_comm_status", 36051, "Meter 2 Communication Status"),
@@ -83,7 +83,7 @@ class ScheduleType(IntEnum):
83
83
 
84
84
 
85
85
  class Voltage(Sensor):
86
- """Sensor representing voltage [V] value encoded in 2 bytes"""
86
+ """Sensor representing voltage [V] value encoded in 2 (unsigned) bytes"""
87
87
 
88
88
  def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
89
89
  super().__init__(id_, offset, name, 2, "V", kind)
@@ -96,7 +96,7 @@ class Voltage(Sensor):
96
96
 
97
97
 
98
98
  class Current(Sensor):
99
- """Sensor representing current [A] value encoded in 2 bytes"""
99
+ """Sensor representing current [A] value encoded in 2 (unsigned) bytes"""
100
100
 
101
101
  def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
102
102
  super().__init__(id_, offset, name, 2, "A", kind)
@@ -108,6 +108,19 @@ class Current(Sensor):
108
108
  return encode_current(value)
109
109
 
110
110
 
111
+ class CurrentS(Sensor):
112
+ """Sensor representing current [A] value encoded in 2 (signed) bytes"""
113
+
114
+ def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
115
+ super().__init__(id_, offset, name, 2, "A", kind)
116
+
117
+ def read_value(self, data: ProtocolResponse):
118
+ return read_current_signed(data)
119
+
120
+ def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
121
+ return encode_current_signed(value)
122
+
123
+
111
124
  class Frequency(Sensor):
112
125
  """Sensor representing frequency [Hz] value encoded in 2 bytes"""
113
126
 
@@ -119,7 +132,7 @@ class Frequency(Sensor):
119
132
 
120
133
 
121
134
  class Power(Sensor):
122
- """Sensor representing power [W] value encoded in 2 bytes"""
135
+ """Sensor representing power [W] value encoded in 2 (unsigned) bytes"""
123
136
 
124
137
  def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
125
138
  super().__init__(id_, offset, name, 2, "W", kind)
@@ -128,8 +141,18 @@ class Power(Sensor):
128
141
  return read_bytes2(data)
129
142
 
130
143
 
144
+ class PowerS(Sensor):
145
+ """Sensor representing power [W] value encoded in 2 (signed) bytes"""
146
+
147
+ def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
148
+ super().__init__(id_, offset, name, 2, "W", kind)
149
+
150
+ def read_value(self, data: ProtocolResponse):
151
+ return read_bytes2_signed(data)
152
+
153
+
131
154
  class Power4(Sensor):
132
- """Sensor representing power [W] value encoded in 4 bytes"""
155
+ """Sensor representing power [W] value encoded in 4 (unsigned) bytes"""
133
156
 
134
157
  def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
135
158
  super().__init__(id_, offset, name, 4, "W", kind)
@@ -138,6 +161,16 @@ class Power4(Sensor):
138
161
  return read_bytes4(data)
139
162
 
140
163
 
164
+ class Power4S(Sensor):
165
+ """Sensor representing power [W] value encoded in 4 (signed) bytes"""
166
+
167
+ def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
168
+ super().__init__(id_, offset, name, 4, "W", kind)
169
+
170
+ def read_value(self, data: ProtocolResponse):
171
+ return read_bytes4_signed(data)
172
+
173
+
141
174
  class Energy(Sensor):
142
175
  """Sensor representing energy [kWh] value encoded in 2 bytes"""
143
176
 
@@ -146,10 +179,7 @@ class Energy(Sensor):
146
179
 
147
180
  def read_value(self, data: ProtocolResponse):
148
181
  value = read_bytes2(data)
149
- if value == -1:
150
- return None
151
- else:
152
- return float(value) / 10
182
+ return float(value) / 10
153
183
 
154
184
 
155
185
  class Energy4(Sensor):
@@ -160,10 +190,7 @@ class Energy4(Sensor):
160
190
 
161
191
  def read_value(self, data: ProtocolResponse):
162
192
  value = read_bytes4(data)
163
- if value == -1:
164
- return None
165
- else:
166
- return float(value) / 10
193
+ return float(value) / 10
167
194
 
168
195
 
169
196
  class Apparent(Sensor):
@@ -173,7 +200,7 @@ class Apparent(Sensor):
173
200
  super().__init__(id_, offset, name, 2, "VA", kind)
174
201
 
175
202
  def read_value(self, data: ProtocolResponse):
176
- return read_bytes2(data)
203
+ return read_bytes2_signed(data)
177
204
 
178
205
 
179
206
  class Apparent4(Sensor):
@@ -183,7 +210,7 @@ class Apparent4(Sensor):
183
210
  super().__init__(id_, offset, name, 2, "VA", kind)
184
211
 
185
212
  def read_value(self, data: ProtocolResponse):
186
- return read_bytes4(data)
213
+ return read_bytes4_signed(data)
187
214
 
188
215
 
189
216
  class Reactive(Sensor):
@@ -193,7 +220,7 @@ class Reactive(Sensor):
193
220
  super().__init__(id_, offset, name, 2, "var", kind)
194
221
 
195
222
  def read_value(self, data: ProtocolResponse):
196
- return read_bytes2(data)
223
+ return read_bytes2_signed(data)
197
224
 
198
225
 
199
226
  class Reactive4(Sensor):
@@ -203,7 +230,7 @@ class Reactive4(Sensor):
203
230
  super().__init__(id_, offset, name, 2, "var", kind)
204
231
 
205
232
  def read_value(self, data: ProtocolResponse):
206
- return read_bytes4(data)
233
+ return read_bytes4_signed(data)
207
234
 
208
235
 
209
236
  class Temp(Sensor):
@@ -277,7 +304,7 @@ class Integer(Sensor):
277
304
  super().__init__(id_, offset, name, 2, unit, kind)
278
305
 
279
306
  def read_value(self, data: ProtocolResponse):
280
- return read_bytes2(data)
307
+ return read_bytes2_signed(data)
281
308
 
282
309
  def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
283
310
  return int.to_bytes(int(value), length=2, byteorder="big", signed=True)
@@ -290,7 +317,7 @@ class Long(Sensor):
290
317
  super().__init__(id_, offset, name, 4, unit, kind)
291
318
 
292
319
  def read_value(self, data: ProtocolResponse):
293
- return read_bytes4(data)
320
+ return read_bytes4_signed(data)
294
321
 
295
322
  def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
296
323
  return int.to_bytes(int(value), length=4, byteorder="big", signed=True)
@@ -390,7 +417,7 @@ class EnumBitmap4(Sensor):
390
417
  raise NotImplementedError()
391
418
 
392
419
  def read(self, data: ProtocolResponse):
393
- bits = read_bytes4(data, self.offset)
420
+ bits = read_bytes4_signed(data, self.offset)
394
421
  return decode_bitmap(bits if bits != -1 else 0, self._labels)
395
422
 
396
423
 
@@ -483,7 +510,7 @@ class EcoModeV1(Sensor, EcoMode):
483
510
  self.end_m = read_byte(data)
484
511
  if self.end_m < 0 or self.end_m > 59:
485
512
  raise ValueError(f"{self.id_}: end_m value {self.end_m} out of range.")
486
- self.power = read_bytes2(data) # negative=charge, positive=discharge
513
+ self.power = read_bytes2_signed(data) # negative=charge, positive=discharge
487
514
  if self.power < -100 or self.power > 100:
488
515
  raise ValueError(f"{self.id_}: power value {self.power} out of range.")
489
516
  self.on_off = read_byte(data)
@@ -592,13 +619,13 @@ class Schedule(Sensor, EcoMode):
592
619
  self.days = decode_day_of_week(self.day_bits)
593
620
  if self.day_bits < 0:
594
621
  raise ValueError(f"{self.id_}: day_bits value {self.day_bits} out of range.")
595
- self.power = read_bytes2(data) # negative=charge, positive=discharge
622
+ self.power = read_bytes2_signed(data) # negative=charge, positive=discharge
596
623
  if not self.schedule_type.is_in_range(self.power):
597
624
  raise ValueError(f"{self.id_}: power value {self.power} out of range.")
598
- self.soc = read_bytes2(data)
625
+ self.soc = read_bytes2_signed(data)
599
626
  if self.soc < 0 or self.soc > 100:
600
627
  raise ValueError(f"{self.id_}: SoC value {self.soc} out of range.")
601
- self.month_bits = read_bytes2(data)
628
+ self.month_bits = read_bytes2_signed(data)
602
629
  self.months = decode_months(self.month_bits)
603
630
  return self
604
631
 
@@ -704,6 +731,14 @@ def read_byte(buffer: ProtocolResponse, offset: int = None) -> int:
704
731
 
705
732
 
706
733
  def read_bytes2(buffer: ProtocolResponse, offset: int = None) -> int:
734
+ """Retrieve 2 byte (unsigned int) value from buffer"""
735
+ if offset is not None:
736
+ buffer.seek(offset)
737
+ value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
738
+ return value if value != 0xffff else 0
739
+
740
+
741
+ def read_bytes2_signed(buffer: ProtocolResponse, offset: int = None) -> int:
707
742
  """Retrieve 2 byte (signed int) value from buffer"""
708
743
  if offset is not None:
709
744
  buffer.seek(offset)
@@ -711,6 +746,14 @@ def read_bytes2(buffer: ProtocolResponse, offset: int = None) -> int:
711
746
 
712
747
 
713
748
  def read_bytes4(buffer: ProtocolResponse, offset: int = None) -> int:
749
+ """Retrieve 4 byte (unsigned int) value from buffer"""
750
+ if offset is not None:
751
+ buffer.seek(offset)
752
+ value = int.from_bytes(buffer.read(4), byteorder="big", signed=False)
753
+ return value if value != 0xffffffff else 0
754
+
755
+
756
+ def read_bytes4_signed(buffer: ProtocolResponse, offset: int = None) -> int:
714
757
  """Retrieve 4 byte (signed int) value from buffer"""
715
758
  if offset is not None:
716
759
  buffer.seek(offset)
@@ -736,20 +779,28 @@ def read_float4(buffer: ProtocolResponse, offset: int = None) -> float:
736
779
 
737
780
 
738
781
  def read_voltage(buffer: ProtocolResponse, offset: int = None) -> float:
739
- """Retrieve voltage [V] value (2 bytes) from buffer"""
782
+ """Retrieve voltage [V] value (2 unsigned bytes) from buffer"""
740
783
  if offset is not None:
741
784
  buffer.seek(offset)
742
- value = int.from_bytes(buffer.read(2), byteorder="big", signed=True)
743
- return float(value) / 10
785
+ value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
786
+ return float(value) / 10 if value != 0xffff else 0
744
787
 
745
788
 
746
789
  def encode_voltage(value: Any) -> bytes:
747
- """Encode voltage value to raw (2 bytes) payload"""
748
- return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=True)
790
+ """Encode voltage value to raw (2 unsigned bytes) payload"""
791
+ return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=False)
749
792
 
750
793
 
751
794
  def read_current(buffer: ProtocolResponse, offset: int = None) -> float:
752
- """Retrieve current [A] value (2 bytes) from buffer"""
795
+ """Retrieve current [A] value (2 unsigned bytes) from buffer"""
796
+ if offset is not None:
797
+ buffer.seek(offset)
798
+ value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
799
+ return float(value) / 10 if value != 0xffff else 0
800
+
801
+
802
+ def read_current_signed(buffer: ProtocolResponse, offset: int = None) -> float:
803
+ """Retrieve current [A] value (2 signed bytes) from buffer"""
753
804
  if offset is not None:
754
805
  buffer.seek(offset)
755
806
  value = int.from_bytes(buffer.read(2), byteorder="big", signed=True)
@@ -757,7 +808,12 @@ def read_current(buffer: ProtocolResponse, offset: int = None) -> float:
757
808
 
758
809
 
759
810
  def encode_current(value: Any) -> bytes:
760
- """Encode current value to raw (2 bytes) payload"""
811
+ """Encode current value to raw (2 unsigned bytes) payload"""
812
+ return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=False)
813
+
814
+
815
+ def encode_current_signed(value: Any) -> bytes:
816
+ """Encode current value to raw (2 signed bytes) payload"""
761
817
  return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=True)
762
818
 
763
819
 
@@ -809,7 +865,7 @@ def encode_datetime(value: Any) -> bytes:
809
865
 
810
866
  def read_grid_mode(buffer: ProtocolResponse, offset: int = None) -> int:
811
867
  """Retrieve 'grid mode' sign value from buffer"""
812
- value = read_bytes2(buffer, offset)
868
+ value = read_bytes2_signed(buffer, offset)
813
869
  if value < -90:
814
870
  return 2
815
871
  elif value >= 90:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goodwe
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Read data from GoodWe inverter via local network
5
5
  Home-page: https://github.com/marcelblijleven/goodwe
6
6
  Author: Martin Letenay, Marcel Blijleven
@@ -64,9 +64,9 @@ class GW6000_DT_Test(DtMock):
64
64
  self.assertSensor('vpv3', None, 'V', data)
65
65
  self.assertSensor('ipv3', None, 'A', data)
66
66
  self.assertSensor('ppv3', None, 'W', data)
67
- self.assertSensor('vline1', -0.1, 'V', data)
68
- self.assertSensor('vline2', -0.1, 'V', data)
69
- self.assertSensor('vline3', -0.1, 'V', data)
67
+ self.assertSensor('vline1', 0, 'V', data)
68
+ self.assertSensor('vline2', 0, 'V', data)
69
+ self.assertSensor('vline3', 0, 'V', data)
70
70
  self.assertSensor('vgrid1', 225.6, 'V', data)
71
71
  self.assertSensor('vgrid2', 229.7, 'V', data)
72
72
  self.assertSensor('vgrid3', 231.0, 'V', data)
@@ -167,8 +167,8 @@ class GW8K_DT_Test(DtMock):
167
167
  self.assertSensor("apparent_power", 0, "VA", data),
168
168
  self.assertSensor("reactive_power", 0, "var", data),
169
169
  self.assertSensor('temperature', 45.3, 'C', data)
170
- self.assertSensor('e_day', None, 'kWh', data)
171
- self.assertSensor('e_total', None, 'kWh', data)
170
+ self.assertSensor('e_day', 0.0, 'kWh', data)
171
+ self.assertSensor('e_total', 0.0, 'kWh', data)
172
172
  self.assertSensor('h_total', -1, 'h', data)
173
173
  self.assertSensor('safety_country', 32, '', data)
174
174
  self.assertSensor('safety_country_label', '50Hz 230Vac Default', '', data)
@@ -208,7 +208,7 @@ class GW5000D_NS_Test(DtMock):
208
208
  self.assertSensor('vpv2', 291.8, 'V', data)
209
209
  self.assertSensor('ipv2', 0, 'A', data)
210
210
  self.assertSensor('ppv2', 0, 'W', data)
211
- self.assertSensor('vline1', -0.1, 'V', data)
211
+ self.assertSensor('vline1', 0, 'V', data)
212
212
  self.assertSensor('vgrid1', 240.5, 'V', data)
213
213
  self.assertSensor('igrid1', 0.0, 'A', data)
214
214
  self.assertSensor('fgrid1', 49.97, 'Hz', data)
@@ -228,7 +228,7 @@ class GW5000D_NS_Test(DtMock):
228
228
  self.assertSensor('safety_country_label', 'Australia Victoria', '', data)
229
229
  self.assertSensor('funbit', 2400, '', data)
230
230
  self.assertSensor('vbus', 291.7, 'V', data)
231
- self.assertSensor('vnbus', -0.1, 'V', data)
231
+ self.assertSensor('vnbus', 0, 'V', data)
232
232
  self.assertSensor('derating_mode', -1, '', data)
233
233
  self.assertSensor('derating_mode_label', '', '', data)
234
234
 
@@ -274,7 +274,7 @@ class GW5000_MS_Test(DtMock):
274
274
  self.assertSensor('vpv3', 143.2, 'V', data)
275
275
  self.assertSensor('ipv3', 0.4, 'A', data)
276
276
  self.assertSensor('ppv3', 57, 'W', data)
277
- self.assertSensor('vline1', -0.1, 'V', data)
277
+ self.assertSensor('vline1', 0, 'V', data)
278
278
  self.assertSensor('vgrid1', 240.1, 'V', data)
279
279
  self.assertSensor('igrid1', 0.9, 'A', data)
280
280
  self.assertSensor('fgrid1', 49.98, 'Hz', data)
@@ -294,7 +294,7 @@ class GW5000_MS_Test(DtMock):
294
294
  self.assertSensor('safety_country_label', 'Australia Victoria', '', data)
295
295
  self.assertSensor('funbit', 2384, '', data)
296
296
  self.assertSensor('vbus', 393.9, 'V', data)
297
- self.assertSensor('vnbus', -0.1, 'V', data)
297
+ self.assertSensor('vnbus', 0, 'V', data)
298
298
  self.assertSensor('derating_mode', -1, '', data)
299
299
  self.assertSensor('derating_mode_label', '', '', data)
300
300
 
@@ -438,7 +438,7 @@ class GW6000_EH_Test(EtMock):
438
438
  self.assertSensor('temperature', 38.6, 'C', data)
439
439
  self.assertSensor('function_bit', 256, '', data)
440
440
  self.assertSensor('bus_voltage', 380.6, 'V', data)
441
- self.assertSensor('nbus_voltage', -0.1, 'V', data)
441
+ self.assertSensor('nbus_voltage', 0, 'V', data)
442
442
  self.assertSensor('vbattery1', 0.0, 'V', data)
443
443
  self.assertSensor('ibattery1', 0.1, 'A', data)
444
444
  self.assertSensor('pbattery1', 0, 'W', data)
@@ -469,7 +469,7 @@ class GW6000_EH_Test(EtMock):
469
469
  self.assertSensor('diagnose_result_label',
470
470
  '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',
471
471
  '', data)
472
- self.assertSensor('house_consumption', 1710, 'W', data)
472
+ self.assertSensor('house_consumption', 1712, 'W', data)
473
473
 
474
474
 
475
475
  class GEH10_1U_10_Test(EtMock):
@@ -539,7 +539,7 @@ class GEH10_1U_10_Test(EtMock):
539
539
  self.assertSensor('temperature', 67.0, 'C', data)
540
540
  self.assertSensor('function_bit', 257, '', data)
541
541
  self.assertSensor('bus_voltage', 458.4, 'V', data)
542
- self.assertSensor('nbus_voltage', -0.1, 'V', data)
542
+ self.assertSensor('nbus_voltage', 0, 'V', data)
543
543
  self.assertSensor('vbattery1', 406.1, 'V', data)
544
544
  self.assertSensor('ibattery1', -3.8, 'A', data)
545
545
  self.assertSensor('pbattery1', -1566, 'W', data)
@@ -78,6 +78,12 @@ class TestUtils(TestCase):
78
78
  self.assertEqual(803.6, testee.read(data))
79
79
  self.assertEqual("1f64", testee.encode_value(803.6).hex())
80
80
 
81
+ data = MockResponse("a000")
82
+ self.assertEqual(4096.0, testee.read(data))
83
+
84
+ data = MockResponse("ffff")
85
+ self.assertEqual(0, testee.read(data))
86
+
81
87
  def test_current(self):
82
88
  testee = Current("", 0, "", None)
83
89
 
@@ -85,6 +91,20 @@ class TestUtils(TestCase):
85
91
  self.assertEqual(4.9, testee.read(data))
86
92
  self.assertEqual("0031", testee.encode_value(4.9).hex())
87
93
 
94
+ data = MockResponse("ff9e")
95
+ self.assertEqual(6543.8, testee.read(data))
96
+ self.assertEqual("ff9e", testee.encode_value(6543.8).hex())
97
+
98
+ data = MockResponse("ffff")
99
+ self.assertEqual(0, testee.read(data))
100
+
101
+ def test_current_signed(self):
102
+ testee = CurrentS("", 0, "", None)
103
+
104
+ data = MockResponse("0031")
105
+ self.assertEqual(4.9, testee.read(data))
106
+ self.assertEqual("0031", testee.encode_value(4.9).hex())
107
+
88
108
  data = MockResponse("ff9e")
89
109
  self.assertEqual(-9.8, testee.read(data))
90
110
  self.assertEqual("ff9e", testee.encode_value(-9.8).hex())
@@ -95,6 +115,18 @@ class TestUtils(TestCase):
95
115
  data = MockResponse("0000069f")
96
116
  self.assertEqual(1695, testee.read(data))
97
117
 
118
+ data = MockResponse("fffffffd")
119
+ self.assertEqual(4294967293, testee.read(data))
120
+
121
+ data = MockResponse("ffffffff")
122
+ self.assertEqual(0, testee.read(data))
123
+
124
+ def test_power4_signed(self):
125
+ testee = Power4S("", 0, "", None)
126
+
127
+ data = MockResponse("0000069f")
128
+ self.assertEqual(1695, testee.read(data))
129
+
98
130
  data = MockResponse("fffffffd")
99
131
  self.assertEqual(-3, testee.read(data))
100
132
 
@@ -110,7 +142,7 @@ class TestUtils(TestCase):
110
142
  data = MockResponse("00020972")
111
143
  self.assertEqual(13349.0, testee.read(data))
112
144
  data = MockResponse("ffffffff")
113
- self.assertIsNone(testee.read(data))
145
+ self.assertEqual(0.0, testee.read(data))
114
146
 
115
147
  def test_timestamp(self):
116
148
  testee = Timestamp("", 0, "", None)
goodwe-0.3.1/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.3.1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes