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 +4 -0
- goodwe/es.py +5 -6
- goodwe/et.py +35 -3
- goodwe/model.py +4 -0
- goodwe/sensor.py +21 -2
- {goodwe-0.3.5.dist-info → goodwe-0.3.6.dist-info}/METADATA +1 -1
- goodwe-0.3.6.dist-info/RECORD +16 -0
- goodwe-0.3.5.dist-info/RECORD +0 -16
- {goodwe-0.3.5.dist-info → goodwe-0.3.6.dist-info}/LICENSE +0 -0
- {goodwe-0.3.5.dist-info → goodwe-0.3.6.dist-info}/WHEEL +0 -0
- {goodwe-0.3.5.dist-info → goodwe-0.3.6.dist-info}/top_level.txt +0 -0
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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:
|
|
@@ -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,,
|
goodwe-0.3.5.dist-info/RECORD
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|