goodwe 0.4.7__py3-none-any.whl → 0.4.9__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/__init__.py CHANGED
@@ -1,9 +1,11 @@
1
+ """Goodwe solar inverter communication library."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import asyncio
4
6
  import logging
5
7
 
6
- from .const import GOODWE_TCP_PORT, GOODWE_UDP_PORT
8
+ from .const import GOODWE_UDP_PORT
7
9
  from .dt import DT
8
10
  from .es import ES
9
11
  from .et import ET
@@ -23,8 +25,15 @@ DT_FAMILY = ["DT", "MS", "NS", "XS"]
23
25
  DISCOVERY_COMMAND = Aa55ProtocolCommand("010200", "0182")
24
26
 
25
27
 
26
- async def connect(host: str, port: int = GOODWE_UDP_PORT, family: str = None, comm_addr: int = 0, timeout: int = 1,
27
- retries: int = 3, do_discover: bool = True) -> Inverter:
28
+ async def connect(
29
+ host: str,
30
+ port: int = GOODWE_UDP_PORT,
31
+ family: str = None,
32
+ comm_addr: int = 0,
33
+ timeout: int = 1,
34
+ retries: int = 3,
35
+ do_discover: bool = True,
36
+ ) -> Inverter:
28
37
  """Contact the inverter at the specified host/port and answer appropriate Inverter instance.
29
38
 
30
39
  The specific inverter family/type will be detected automatically, but it can be passed explicitly.
@@ -55,7 +64,9 @@ async def connect(host: str, port: int = GOODWE_UDP_PORT, family: str = None, co
55
64
  return inv
56
65
 
57
66
 
58
- async def discover(host: str, port: int = GOODWE_UDP_PORT, timeout: int = 1, retries: int = 3) -> Inverter:
67
+ async def discover(
68
+ host: str, port: int = GOODWE_UDP_PORT, timeout: int = 1, retries: int = 3
69
+ ) -> Inverter:
59
70
  """Contact the inverter at the specified value and answer appropriate Inverter instance
60
71
 
61
72
  Raise InverterError if unable to contact or recognise supported inverter
@@ -66,7 +77,9 @@ async def discover(host: str, port: int = GOODWE_UDP_PORT, timeout: int = 1, ret
66
77
  # Try the common AA55C07F0102000241 command first and detect inverter type from serial_number
67
78
  try:
68
79
  logger.debug("Probing inverter at %s:%s.", host, port)
69
- response = await DISCOVERY_COMMAND.execute(UdpInverterProtocol(host, port, timeout, retries))
80
+ response = await DISCOVERY_COMMAND.execute(
81
+ UdpInverterProtocol(host, port, timeout, retries)
82
+ )
70
83
  response = response.response_data()
71
84
  model_name = response[5:15].decode("ascii").rstrip()
72
85
  serial_number = response[31:47].decode("ascii")
@@ -74,24 +87,38 @@ async def discover(host: str, port: int = GOODWE_UDP_PORT, timeout: int = 1, ret
74
87
  i: Inverter | None = None
75
88
  for model_tag in ET_MODEL_TAGS:
76
89
  if model_tag in serial_number:
77
- logger.debug("Detected ET/EH/BT/BH/GEH inverter %s, S/N:%s.", model_name, serial_number)
90
+ logger.debug(
91
+ "Detected ET/EH/BT/BH/GEH inverter %s, S/N:%s.",
92
+ model_name,
93
+ serial_number,
94
+ )
78
95
  i = ET(host, port, 0, timeout, retries)
79
96
  break
80
97
  if not i:
81
98
  for model_tag in ES_MODEL_TAGS:
82
99
  if model_tag in serial_number:
83
- logger.debug("Detected ES/EM/BP inverter %s, S/N:%s.", model_name, serial_number)
100
+ logger.debug(
101
+ "Detected ES/EM/BP inverter %s, S/N:%s.",
102
+ model_name,
103
+ serial_number,
104
+ )
84
105
  i = ES(host, port, 0, timeout, retries)
85
106
  break
86
107
  if not i:
87
108
  for model_tag in DT_MODEL_TAGS:
88
109
  if model_tag in serial_number:
89
- logger.debug("Detected DT/MS/D-NS/XS/GEP inverter %s, S/N:%s.", model_name, serial_number)
110
+ logger.debug(
111
+ "Detected DT/MS/D-NS/XS/GEP inverter %s, S/N:%s.",
112
+ model_name,
113
+ serial_number,
114
+ )
90
115
  i = DT(host, port, 0, timeout, retries)
91
116
  break
92
117
  if i:
93
118
  await i.read_device_info()
94
- logger.debug("Connected to inverter %s, S/N:%s.", i.model_name, i.serial_number)
119
+ logger.debug(
120
+ "Connected to inverter %s, S/N:%s.", i.model_name, i.serial_number
121
+ )
95
122
  return i
96
123
 
97
124
  except InverterError as ex:
@@ -104,7 +131,12 @@ async def discover(host: str, port: int = GOODWE_UDP_PORT, timeout: int = 1, ret
104
131
  logger.debug("Probing %s inverter at %s.", inv.__name__, host)
105
132
  await i.read_device_info()
106
133
  await i.read_runtime_data()
107
- logger.debug("Detected %s family inverter %s, S/N:%s.", inv.__name__, i.model_name, i.serial_number)
134
+ logger.debug(
135
+ "Detected %s family inverter %s, S/N:%s.",
136
+ inv.__name__,
137
+ i.model_name,
138
+ i.serial_number,
139
+ )
108
140
  return i
109
141
  except InverterError as ex:
110
142
  failures.append(ex)
@@ -124,10 +156,13 @@ async def search_inverters() -> bytes:
124
156
  logger.debug("Searching inverters by broadcast to port 48899")
125
157
  command = ProtocolCommand("WIFIKIT-214028-READ".encode("utf-8"), lambda r: True)
126
158
  try:
127
- result = await command.execute(UdpInverterProtocol("255.255.255.255", 48899, 1, 0))
159
+ result = await command.execute(
160
+ UdpInverterProtocol("255.255.255.255", 48899, 1, 0)
161
+ )
128
162
  if result is not None:
129
163
  return result.response_data()
130
- else:
131
- raise InverterError("No response received to broadcast request.")
164
+ raise InverterError("No response received to broadcast request.")
132
165
  except asyncio.CancelledError:
133
- raise InverterError("No valid response received to broadcast request.") from None
166
+ raise InverterError(
167
+ "No valid response received to broadcast request."
168
+ ) from None
goodwe/const.py CHANGED
@@ -1,9 +1,8 @@
1
- from typing import Dict
2
-
1
+ """Constants."""
3
2
  GOODWE_TCP_PORT = 502
4
3
  GOODWE_UDP_PORT = 8899
5
4
 
6
- BATTERY_MODES: Dict[int, str] = {
5
+ BATTERY_MODES: dict[int, str] = {
7
6
  0: "No battery",
8
7
  1: "Standby",
9
8
  2: "Discharge",
@@ -12,7 +11,7 @@ BATTERY_MODES: Dict[int, str] = {
12
11
  5: "To be discharged",
13
12
  }
14
13
 
15
- ENERGY_MODES: Dict[int, str] = {
14
+ ENERGY_MODES: dict[int, str] = {
16
15
  0: "Check Mode",
17
16
  1: "Wait Mode",
18
17
  2: "Normal (On-Grid)",
@@ -24,37 +23,37 @@ ENERGY_MODES: Dict[int, str] = {
24
23
  128: "Battery Discharging",
25
24
  }
26
25
 
27
- GRID_MODES: Dict[int, str] = {
26
+ GRID_MODES: dict[int, str] = {
28
27
  0: "Not connected to grid",
29
28
  1: "Connected to grid",
30
29
  2: "Fault",
31
30
  }
32
31
 
33
- GRID_IN_OUT_MODES: Dict[int, str] = {
32
+ GRID_IN_OUT_MODES: dict[int, str] = {
34
33
  0: "Idle",
35
34
  1: "Exporting",
36
35
  2: "Importing",
37
36
  }
38
37
 
39
- LOAD_MODES: Dict[int, str] = {
38
+ LOAD_MODES: dict[int, str] = {
40
39
  0: "Inverter and the load is disconnected",
41
40
  1: "The inverter is connected to a load",
42
41
  }
43
42
 
44
- PV_MODES: Dict[int, str] = {
43
+ PV_MODES: dict[int, str] = {
45
44
  0: "PV panels not connected",
46
45
  1: "PV panels connected, no power",
47
46
  2: "PV panels connected, producing power",
48
47
  }
49
48
 
50
- WORK_MODES: Dict[int, str] = {
49
+ WORK_MODES: dict[int, str] = {
51
50
  0: "Wait Mode",
52
51
  1: "Normal",
53
52
  2: "Error",
54
53
  4: "Check Mode",
55
54
  }
56
55
 
57
- WORK_MODES_ET: Dict[int, str] = {
56
+ WORK_MODES_ET: dict[int, str] = {
58
57
  0: "Wait Mode",
59
58
  1: "Normal (On-Grid)",
60
59
  2: "Normal (Off-Grid)",
@@ -63,14 +62,14 @@ WORK_MODES_ET: Dict[int, str] = {
63
62
  5: "Check Mode",
64
63
  }
65
64
 
66
- WORK_MODES_ES: Dict[int, str] = {
65
+ WORK_MODES_ES: dict[int, str] = {
67
66
  0: "Inverter Off - Standby",
68
67
  1: "Inverter On",
69
68
  2: "Inverter Abnormal, stopping power",
70
69
  3: "Inverter Severly Abnormal, 20 seconds to restart",
71
70
  }
72
71
 
73
- SAFETY_COUNTRIES: Dict[int, str] = {
72
+ SAFETY_COUNTRIES: dict[int, str] = {
74
73
  0: "IT CEI 0-21",
75
74
  1: "CZ-A1",
76
75
  2: "DE LV with PV",
@@ -198,7 +197,7 @@ SAFETY_COUNTRIES: Dict[int, str] = {
198
197
  149: "Brazil 254Vac",
199
198
  }
200
199
 
201
- ERROR_CODES: Dict[int, str] = {
200
+ ERROR_CODES: dict[int, str] = {
202
201
  31: 'Internal Communication Failure',
203
202
  30: 'EEPROM R/W Failure',
204
203
  29: 'Fac Failure',
@@ -233,7 +232,7 @@ ERROR_CODES: Dict[int, str] = {
233
232
  0: 'GFCI Device Check Failure',
234
233
  }
235
234
 
236
- DIAG_STATUS_CODES: Dict[int, str] = {
235
+ DIAG_STATUS_CODES: dict[int, str] = {
237
236
  0: "Battery voltage low",
238
237
  1: "Battery SOC low",
239
238
  2: "Battery SOC in back",
@@ -263,9 +262,10 @@ DIAG_STATUS_CODES: Dict[int, str] = {
263
262
  26: "Real power limit set",
264
263
  27: "DC output on",
265
264
  28: "SOC protect off",
265
+ 30: "BMS: Emergency charging",
266
266
  }
267
267
 
268
- BMS_ALARM_CODES: Dict[int, str] = {
268
+ BMS_ALARM_CODES: dict[int, str] = {
269
269
  15: 'Charging over-voltage 3',
270
270
  14: 'Discharging under-voltage 3',
271
271
  13: 'Cell temperature high 3',
@@ -284,7 +284,7 @@ BMS_ALARM_CODES: Dict[int, str] = {
284
284
  0: 'Charging over-voltage 2',
285
285
  }
286
286
 
287
- BMS_WARNING_CODES: Dict[int, str] = {
287
+ BMS_WARNING_CODES: dict[int, str] = {
288
288
  11: 'System temperature high',
289
289
  10: 'System temperature low 2',
290
290
  9: 'System temperature low 1',
@@ -299,7 +299,7 @@ BMS_WARNING_CODES: Dict[int, str] = {
299
299
  0: 'Charging over-voltage 1',
300
300
  }
301
301
 
302
- DERATING_MODE_CODES: Dict[int, str] = {
302
+ DERATING_MODE_CODES: dict[int, str] = {
303
303
  31: '',
304
304
  30: '',
305
305
  29: '',
@@ -333,3 +333,9 @@ DERATING_MODE_CODES: Dict[int, str] = {
333
333
  1: 'Active power derating',
334
334
  0: 'Overtemperature derating',
335
335
  }
336
+
337
+ METER_COMMUNICATION_STATUS: dict[int, str] = {
338
+ 0: '',
339
+ 1: 'Normal',
340
+ 2: 'Disconnected',
341
+ }