goodwe 0.3.5__py3-none-any.whl → 0.3.6__py3-none-any.whl

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.
goodwe/dt.py CHANGED
@@ -110,6 +110,10 @@ class DT(Inverter):
110
110
  Integer("shadow_scan", 40326, "Shadow Scan", "", Kind.PV),
111
111
  Integer("grid_export", 40327, "Grid Export Enabled", "", Kind.GRID),
112
112
  Integer("grid_export_limit", 40328, "Grid Export Limit", "%", Kind.GRID),
113
+ Integer("start", 40330, "Start / Power On", "", Kind.GRID),
114
+ Integer("stop", 40331, "Stop / Power Off", "", Kind.GRID),
115
+ Integer("restart", 40332, "Restart", "", Kind.GRID),
116
+ Integer("grid_export_hw", 40345, "Grid Export Enabled (HW)", "", Kind.GRID),
113
117
  )
114
118
 
115
119
  # Settings for single phase inverters
goodwe/es.py CHANGED
@@ -178,11 +178,11 @@ class ES(Inverter):
178
178
  def _supports_eco_mode_v2(self) -> bool:
179
179
  if self.arm_version < 14:
180
180
  return False
181
- if "EMU" in self.serial_number:
181
+ if "EMU" in self.serial_number or "EMJ" in self.serial_number:
182
182
  return self.dsp1_version >= 11
183
- if "ESU" in self.serial_number:
183
+ if "ESU" in self.serial_number or "ESA" in self.serial_number:
184
184
  return self.dsp1_version >= 22
185
- if "BPS" in self.serial_number:
185
+ if "BPS" in self.serial_number or "BPU" in self.serial_number:
186
186
  return self.dsp1_version >= 10
187
187
  return False
188
188
 
@@ -192,7 +192,7 @@ class ES(Inverter):
192
192
  self.firmware = self._decode(response[0:5]).rstrip()
193
193
  self.model_name = self._decode(response[5:15]).rstrip()
194
194
  self.serial_number = self._decode(response[31:47])
195
- self.software_version = self._decode(response[51:63])
195
+ self.arm_firmware = self._decode(response[51:63]) # AKA software_version
196
196
  try:
197
197
  if len(self.firmware) >= 2:
198
198
  self.dsp1_version = int(self.firmware[0:2])
@@ -250,10 +250,9 @@ class ES(Inverter):
250
250
  # modbus can address/store only 16 bit values, read the other 8 bytes
251
251
  if self._is_modbus_setting(setting):
252
252
  response = await self._read_from_socket(ModbusReadCommand(self.comm_addr, setting.offset, 1))
253
- raw_value = setting.encode_value(value, response.response_data()[0:2])
254
253
  else:
255
254
  response = await self._read_from_socket(Aa55ReadCommand(setting.offset, 1))
256
- raw_value = setting.encode_value(value, response.response_data()[2:4])
255
+ raw_value = setting.encode_value(value, response.response_data()[0:2])
257
256
  else:
258
257
  raw_value = setting.encode_value(value)
259
258
  if len(raw_value) <= 2:
goodwe/et.py CHANGED
@@ -252,7 +252,8 @@ class ET(Inverter):
252
252
  Apparent4("meter_apparent_power_total", 36041, "Meter Apparent Power Total", Kind.GRID),
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
- # Sensors added in some ARM fw update, read when flag _has_meter_extended is on
255
+
256
+ # Sensors added in some ARM fw update (or platform 745/753), read when flag _has_meter_extended is on
256
257
  Power4S("meter2_active_power", 36045, "Meter 2 Active Power", Kind.GRID),
257
258
  Float("meter2_e_total_exp", 36047, 1000, "Meter 2 Total Energy (export)", "kWh", Kind.GRID),
258
259
  Float("meter2_e_total_imp", 36049, 1000, "Meter 2 Total Energy (import)", "kWh", Kind.GRID),
@@ -263,6 +264,15 @@ class ET(Inverter):
263
264
  Current("meter_current1", 36055, "Meter L1 Current", Kind.GRID),
264
265
  Current("meter_current2", 36056, "Meter L2 Current", Kind.GRID),
265
266
  Current("meter_current3", 36057, "Meter L3 Current", Kind.GRID),
267
+
268
+ Energy8("meter_e_total_exp1", 36092, "Meter Total Energy (export) L1", Kind.GRID),
269
+ Energy8("meter_e_total_exp2", 36096, "Meter Total Energy (export) L2", Kind.GRID),
270
+ Energy8("meter_e_total_exp3", 36100, "Meter Total Energy (export) L3", Kind.GRID),
271
+ Energy8("meter_e_total_exp", 36104, "Meter Total Energy (export)", Kind.GRID),
272
+ Energy8("meter_e_total_imp1", 36108, "Meter Total Energy (import) L1", Kind.GRID),
273
+ Energy8("meter_e_total_imp2", 36112, "Meter Total Energy (import) L2", Kind.GRID),
274
+ Energy8("meter_e_total_imp3", 36116, "Meter Total Energy (import) L3", Kind.GRID),
275
+ Energy8("meter_e_total_imp", 36120, "Meter Total Energy (import)", Kind.GRID),
266
276
  )
267
277
 
268
278
  # Inverter's MPPT data
@@ -414,6 +424,7 @@ class ET(Inverter):
414
424
  self._READ_RUNNING_DATA: ProtocolCommand = ModbusReadCommand(self.comm_addr, 0x891c, 0x007d)
415
425
  self._READ_METER_DATA: ProtocolCommand = ModbusReadCommand(self.comm_addr, 0x8ca0, 0x2d)
416
426
  self._READ_METER_DATA_EXTENDED: ProtocolCommand = ModbusReadCommand(self.comm_addr, 0x8ca0, 0x3a)
427
+ self._READ_METER_DATA_EXTENDED2: ProtocolCommand = ModbusReadCommand(self.comm_addr, 0x8ca0, 0x7d)
417
428
  self._READ_BATTERY_INFO: ProtocolCommand = ModbusReadCommand(self.comm_addr, 0x9088, 0x0018)
418
429
  self._READ_BATTERY2_INFO: ProtocolCommand = ModbusReadCommand(self.comm_addr, 0x9858, 0x0016)
419
430
  self._READ_MPPT_DATA: ProtocolCommand = ModbusReadCommand(self.comm_addr, 0x89e5, 0x3d)
@@ -422,6 +433,7 @@ class ET(Inverter):
422
433
  self._has_battery: bool = True
423
434
  self._has_battery2: bool = False
424
435
  self._has_meter_extended: bool = False
436
+ self._has_meter_extended2: bool = False
425
437
  self._has_mppt: bool = False
426
438
  self._sensors = self.__all_sensors
427
439
  self._sensors_battery = self.__all_sensors_battery
@@ -440,6 +452,11 @@ class ET(Inverter):
440
452
  """Filter to exclude extended meter sensors"""
441
453
  return s.offset < 36045
442
454
 
455
+ @staticmethod
456
+ def _not_extended_meter2(s: Sensor) -> bool:
457
+ """Filter to exclude extended meter sensors"""
458
+ return s.offset < 36058
459
+
443
460
  async def read_device_info(self):
444
461
  response = await self._read_from_socket(self._READ_DEVICE_VERSION_INFO)
445
462
  response = response.response_data()
@@ -470,9 +487,10 @@ class ET(Inverter):
470
487
  if is_2_battery(self) or self.rated_power >= 25000:
471
488
  self._has_battery2 = True
472
489
 
473
- if self.rated_power >= 15000:
490
+ if is_745_platform(self) or self.rated_power >= 15000:
474
491
  self._has_mppt = True
475
492
  self._has_meter_extended = True
493
+ self._has_meter_extended2 = True
476
494
  else:
477
495
  self._sensors_meter = tuple(filter(self._not_extended_meter, self._sensors_meter))
478
496
 
@@ -527,7 +545,21 @@ class ET(Inverter):
527
545
  else:
528
546
  raise ex
529
547
 
530
- if self._has_meter_extended:
548
+ if self._has_meter_extended2:
549
+ try:
550
+ response = await self._read_from_socket(self._READ_METER_DATA_EXTENDED2)
551
+ data.update(self._map_response(response, self._sensors_meter))
552
+ except RequestRejectedException as ex:
553
+ if ex.message == 'ILLEGAL DATA ADDRESS':
554
+ logger.info("Extended meter values not supported, disabling further attempts.")
555
+ self._has_meter_extended2 = False
556
+ self._sensors_meter = tuple(filter(self._not_extended_meter2, self._sensors_meter))
557
+ response = await self._read_from_socket(self._READ_METER_DATA_EXTENDED)
558
+ data.update(
559
+ self._map_response(response, self._sensors_meter))
560
+ else:
561
+ raise ex
562
+ elif self._has_meter_extended:
531
563
  try:
532
564
  response = await self._read_from_socket(self._READ_METER_DATA_EXTENDED)
533
565
  data.update(self._map_response(response, self._sensors_meter))
goodwe/model.py CHANGED
@@ -48,3 +48,7 @@ def is_2_battery(inverter: Inverter) -> bool:
48
48
  def is_745_platform(inverter: Inverter) -> bool:
49
49
  return any(model in inverter.serial_number for model in PLATFORM_745_LV_MODELS) or any(
50
50
  model in inverter.serial_number for model in PLATFORM_745_HV_MODELS)
51
+
52
+
53
+ def is_753_platform(inverter: Inverter) -> bool:
54
+ return any(model in inverter.serial_number for model in PLATFORM_753_MODELS)
goodwe/sensor.py CHANGED
@@ -183,7 +183,7 @@ class Energy(Sensor):
183
183
 
184
184
  def read_value(self, data: ProtocolResponse):
185
185
  value = read_bytes2(data)
186
- return float(value) / 10 if value else None
186
+ return float(value) / 10 if value is not None else None
187
187
 
188
188
 
189
189
  class Energy4(Sensor):
@@ -194,7 +194,18 @@ class Energy4(Sensor):
194
194
 
195
195
  def read_value(self, data: ProtocolResponse):
196
196
  value = read_bytes4(data)
197
- return float(value) / 10 if value else None
197
+ return float(value) / 10 if value is not None else None
198
+
199
+
200
+ class Energy8(Sensor):
201
+ """Sensor representing energy [kWh] value encoded in 8 bytes"""
202
+
203
+ def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
204
+ super().__init__(id_, offset, name, 8, "kWh", kind)
205
+
206
+ def read_value(self, data: ProtocolResponse):
207
+ value = read_bytes8(data)
208
+ return float(value) / 100 if value is not None else None
198
209
 
199
210
 
200
211
  class Apparent(Sensor):
@@ -816,6 +827,14 @@ def read_bytes4_signed(buffer: ProtocolResponse, offset: int = None) -> int:
816
827
  return int.from_bytes(buffer.read(4), byteorder="big", signed=True)
817
828
 
818
829
 
830
+ def read_bytes8(buffer: ProtocolResponse, offset: int = None, undef: int = None) -> int:
831
+ """Retrieve 8 byte (unsigned int) value from buffer"""
832
+ if offset is not None:
833
+ buffer.seek(offset)
834
+ value = int.from_bytes(buffer.read(8), byteorder="big", signed=False)
835
+ return undef if value == 0xffffffffffffffff else value
836
+
837
+
819
838
  def read_decimal2(buffer: ProtocolResponse, scale: int, offset: int = None) -> float:
820
839
  """Retrieve 2 byte (signed float) value from buffer"""
821
840
  if offset is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goodwe
3
- Version: 0.3.5
3
+ Version: 0.3.6
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
@@ -0,0 +1,16 @@
1
+ goodwe/__init__.py,sha256=PInrrZEpTmMOQKk494vIz8EKSaw_qLBNz-6t9eLIUcg,5642
2
+ goodwe/const.py,sha256=Nw-nd4UJuqUOLfbmOrxTHEdS1AuaTDSpZzQqR6tBb8w,7912
3
+ goodwe/dt.py,sha256=0nwEAaRstwyZpeDAoSIq4spETXD77ctoGWEnuyezm_E,10862
4
+ goodwe/es.py,sha256=ej4vBgXI2dGarbO3rle2itMukmY85_8as6Wsab_6ms8,22672
5
+ goodwe/et.py,sha256=perDcodUdVBmn6bRhHfYgdFihjDwuNE5DyaiTU0adgw,42050
6
+ goodwe/exceptions.py,sha256=I6PHG0GTWgxNrDVZwJZBnyzItRq5eiM6ci23-EEsn1I,1012
7
+ goodwe/inverter.py,sha256=7DgIzSHimkVAfNyIkzALeukHOHkOuYjVyUIvuT0LHdE,10342
8
+ goodwe/modbus.py,sha256=ZPib-zKnOVE5zc0RNnhlf0w_26QBees1ScWGo6bAj0o,4685
9
+ goodwe/model.py,sha256=OAKfw6ggClgLR9JIdNd7tQ4pnh_7o_UqVdm1KOVsm-Y,2200
10
+ goodwe/protocol.py,sha256=pUkXTP2DqpKXGO7rbRfHq1x82Y1QM6OiRVx8cAtS0sM,13162
11
+ goodwe/sensor.py,sha256=P3-FeiaxVmzxY0UTpa-Mhlt5ZC9rUdNjjTu3EpYz9BE,37742
12
+ goodwe-0.3.6.dist-info/LICENSE,sha256=aZAhk3lRdYT1YZV-IKRHISEcc_KNUmgfuNO3QhRamNM,1073
13
+ goodwe-0.3.6.dist-info/METADATA,sha256=Ahjq6cttZ-9ouqlgsx7b-XPo_kIzQVt9TNdATXjCCyg,3050
14
+ goodwe-0.3.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
15
+ goodwe-0.3.6.dist-info/top_level.txt,sha256=kKoiqiVvAxDaDJYMZZQLgHQj9cuWT1MXLfXElTDuf8s,7
16
+ goodwe-0.3.6.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- goodwe/__init__.py,sha256=PInrrZEpTmMOQKk494vIz8EKSaw_qLBNz-6t9eLIUcg,5642
2
- goodwe/const.py,sha256=Nw-nd4UJuqUOLfbmOrxTHEdS1AuaTDSpZzQqR6tBb8w,7912
3
- goodwe/dt.py,sha256=bI53MVdZjtxTYU2qJLO8icsvF6UiXrkgH95V3iUwXT0,10581
4
- goodwe/es.py,sha256=XBP7txg9d4tMsFmHWs8LB4wdJmspKVD9ALfS9mePiJk,22650
5
- goodwe/et.py,sha256=0XFwRMZeUdKZ4dhGANpw2o1EKsfgJGdGYsN95zhxV1s,40084
6
- goodwe/exceptions.py,sha256=I6PHG0GTWgxNrDVZwJZBnyzItRq5eiM6ci23-EEsn1I,1012
7
- goodwe/inverter.py,sha256=7DgIzSHimkVAfNyIkzALeukHOHkOuYjVyUIvuT0LHdE,10342
8
- goodwe/modbus.py,sha256=ZPib-zKnOVE5zc0RNnhlf0w_26QBees1ScWGo6bAj0o,4685
9
- goodwe/model.py,sha256=dWBjMFJMnhZoUdDd9fGT54DERDANz4TirK0Wy8kWMbk,2068
10
- goodwe/protocol.py,sha256=pUkXTP2DqpKXGO7rbRfHq1x82Y1QM6OiRVx8cAtS0sM,13162
11
- goodwe/sensor.py,sha256=vFbsz4Dp0yw0rBNdKqzkMUupuBJWC17YcxvBrjvFAjU,36990
12
- goodwe-0.3.5.dist-info/LICENSE,sha256=aZAhk3lRdYT1YZV-IKRHISEcc_KNUmgfuNO3QhRamNM,1073
13
- goodwe-0.3.5.dist-info/METADATA,sha256=aITPWNoquftA7VYNraUZqMoO8Bu-DXQ98ZAJxhsHtZM,3050
14
- goodwe-0.3.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
15
- goodwe-0.3.5.dist-info/top_level.txt,sha256=kKoiqiVvAxDaDJYMZZQLgHQj9cuWT1MXLfXElTDuf8s,7
16
- goodwe-0.3.5.dist-info/RECORD,,
File without changes