pylxpweb 0.1.0__py3-none-any.whl → 0.5.0__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.
Files changed (46) hide show
  1. pylxpweb/__init__.py +47 -2
  2. pylxpweb/api_namespace.py +241 -0
  3. pylxpweb/cli/__init__.py +3 -0
  4. pylxpweb/cli/collect_device_data.py +874 -0
  5. pylxpweb/client.py +387 -26
  6. pylxpweb/constants/__init__.py +481 -0
  7. pylxpweb/constants/api.py +48 -0
  8. pylxpweb/constants/devices.py +98 -0
  9. pylxpweb/constants/locations.py +227 -0
  10. pylxpweb/{constants.py → constants/registers.py} +72 -238
  11. pylxpweb/constants/scaling.py +479 -0
  12. pylxpweb/devices/__init__.py +32 -0
  13. pylxpweb/devices/_firmware_update_mixin.py +504 -0
  14. pylxpweb/devices/_mid_runtime_properties.py +545 -0
  15. pylxpweb/devices/base.py +122 -0
  16. pylxpweb/devices/battery.py +589 -0
  17. pylxpweb/devices/battery_bank.py +331 -0
  18. pylxpweb/devices/inverters/__init__.py +32 -0
  19. pylxpweb/devices/inverters/_features.py +378 -0
  20. pylxpweb/devices/inverters/_runtime_properties.py +596 -0
  21. pylxpweb/devices/inverters/base.py +2124 -0
  22. pylxpweb/devices/inverters/generic.py +192 -0
  23. pylxpweb/devices/inverters/hybrid.py +274 -0
  24. pylxpweb/devices/mid_device.py +183 -0
  25. pylxpweb/devices/models.py +126 -0
  26. pylxpweb/devices/parallel_group.py +351 -0
  27. pylxpweb/devices/station.py +908 -0
  28. pylxpweb/endpoints/control.py +980 -2
  29. pylxpweb/endpoints/devices.py +249 -16
  30. pylxpweb/endpoints/firmware.py +43 -10
  31. pylxpweb/endpoints/plants.py +15 -19
  32. pylxpweb/exceptions.py +4 -0
  33. pylxpweb/models.py +629 -40
  34. pylxpweb/transports/__init__.py +78 -0
  35. pylxpweb/transports/capabilities.py +101 -0
  36. pylxpweb/transports/data.py +495 -0
  37. pylxpweb/transports/exceptions.py +59 -0
  38. pylxpweb/transports/factory.py +119 -0
  39. pylxpweb/transports/http.py +329 -0
  40. pylxpweb/transports/modbus.py +557 -0
  41. pylxpweb/transports/protocol.py +217 -0
  42. {pylxpweb-0.1.0.dist-info → pylxpweb-0.5.0.dist-info}/METADATA +130 -85
  43. pylxpweb-0.5.0.dist-info/RECORD +52 -0
  44. {pylxpweb-0.1.0.dist-info → pylxpweb-0.5.0.dist-info}/WHEEL +1 -1
  45. pylxpweb-0.5.0.dist-info/entry_points.txt +3 -0
  46. pylxpweb-0.1.0.dist-info/RECORD +0 -19
@@ -0,0 +1,481 @@
1
+ """Constants and mappings for Luxpower/EG4 API.
2
+
3
+ This package contains constants, mappings, and helper functions for working
4
+ with the Luxpower/EG4 inverter API. The constants are organized into modules
5
+ for maintainability:
6
+
7
+ - locations: Timezone, country, continent, region mappings
8
+ - registers: Hold/input register definitions and bit manipulation
9
+ - scaling: Data scaling factors and conversion functions
10
+ - api: HTTP constants, backoff/retry configuration
11
+ - devices: Device types, limits, and parsing helpers
12
+
13
+ All symbols are re-exported from this package for backward compatibility,
14
+ so you can import from pylxpweb.constants directly:
15
+
16
+ from pylxpweb.constants import HOLD_AC_CHARGE_POWER_CMD, ScaleFactor
17
+
18
+ Note: This package was refactored from a single large file (v0.3.x) into
19
+ a modular structure (v0.4.0+) for better maintainability.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ # ============================================================================
25
+ # API MODULE
26
+ # ============================================================================
27
+ from .api import (
28
+ # Backoff and retry
29
+ BACKOFF_BASE_DELAY_SECONDS,
30
+ BACKOFF_MAX_DELAY_SECONDS,
31
+ DEVICE_TYPE_GRIDBOSS,
32
+ # Device type constants
33
+ DEVICE_TYPE_INVERTER,
34
+ HTTP_FORBIDDEN,
35
+ # HTTP status codes
36
+ HTTP_OK,
37
+ HTTP_UNAUTHORIZED,
38
+ MAX_LOGIN_RETRIES,
39
+ MAX_TRANSIENT_ERROR_RETRIES,
40
+ TRANSIENT_ERROR_MESSAGES,
41
+ )
42
+
43
+ # ============================================================================
44
+ # DEVICES MODULE
45
+ # ============================================================================
46
+ from .devices import (
47
+ # Register limits
48
+ MAX_REGISTERS_PER_READ,
49
+ SCALE_MID_FREQUENCY,
50
+ # MID device scaling
51
+ SCALE_MID_VOLTAGE,
52
+ SOC_MAX_PERCENT,
53
+ # SOC limits
54
+ SOC_MIN_PERCENT,
55
+ # Timezone parsing
56
+ TIMEZONE_HHMM_HOURS_FACTOR,
57
+ TIMEZONE_HHMM_MINUTES_FACTOR,
58
+ parse_hhmm_timezone,
59
+ scale_mid_frequency,
60
+ scale_mid_voltage,
61
+ )
62
+
63
+ # Re-export all symbols from submodules for backward compatibility
64
+ # This ensures that existing code using `from pylxpweb.constants import X` continues to work
65
+ # ============================================================================
66
+ # LOCATIONS MODULE
67
+ # ============================================================================
68
+ from .locations import (
69
+ # Continent mappings
70
+ CONTINENT_MAP,
71
+ CONTINENT_REVERSE_MAP,
72
+ # Country mappings
73
+ COUNTRY_MAP,
74
+ COUNTRY_REVERSE_MAP,
75
+ # Static country-to-location mapping
76
+ COUNTRY_TO_LOCATION_STATIC,
77
+ # Region mappings
78
+ REGION_MAP,
79
+ REGION_REVERSE_MAP,
80
+ # Timezone mappings
81
+ TIMEZONE_MAP,
82
+ TIMEZONE_REVERSE_MAP,
83
+ get_continent_enum,
84
+ get_continent_region_from_country,
85
+ get_country_enum,
86
+ get_region_enum,
87
+ # Helper functions
88
+ get_timezone_enum,
89
+ )
90
+
91
+ # ============================================================================
92
+ # REGISTERS MODULE
93
+ # ============================================================================
94
+ from .registers import (
95
+ DEVICE_TYPE_CODE_LXP_EU,
96
+ DEVICE_TYPE_CODE_PV_SERIES,
97
+ DEVICE_TYPE_CODE_SNA,
98
+ FUNC_EN_BIT_AC_CHARGE_EN,
99
+ FUNC_EN_BIT_EPS_EN,
100
+ FUNC_EN_BIT_FORCED_CHG_EN,
101
+ FUNC_EN_BIT_FORCED_DISCHG_EN,
102
+ FUNC_EN_BIT_SET_TO_STANDBY,
103
+ # Critical control register
104
+ FUNC_EN_REGISTER,
105
+ # GridBOSS parameters
106
+ GRIDBOSS_PARAMETERS,
107
+ GRIDBOSS_STATS,
108
+ HOLD_AC_CHARGE_ENABLE_1,
109
+ HOLD_AC_CHARGE_ENABLE_2,
110
+ HOLD_AC_CHARGE_END_HOUR_1,
111
+ HOLD_AC_CHARGE_END_MIN_1,
112
+ # AC charge parameters
113
+ HOLD_AC_CHARGE_POWER_CMD,
114
+ HOLD_AC_CHARGE_SOC_LIMIT,
115
+ HOLD_AC_CHARGE_START_HOUR_1,
116
+ HOLD_AC_CHARGE_START_MIN_1,
117
+ # Battery protection parameters
118
+ HOLD_BAT_VOLT_MAX_CHG,
119
+ HOLD_BAT_VOLT_MAX_DISCHG,
120
+ HOLD_BAT_VOLT_MIN_CHG,
121
+ HOLD_BAT_VOLT_MIN_DISCHG,
122
+ HOLD_BAUD_RATE,
123
+ HOLD_DAY,
124
+ HOLD_DISCHG_CUT_OFF_SOC_EOD,
125
+ HOLD_DISCHG_ENABLE_1,
126
+ HOLD_DISCHG_END_HOUR_1,
127
+ HOLD_DISCHG_END_MIN_1,
128
+ # Discharge parameters
129
+ HOLD_DISCHG_POWER_CMD,
130
+ HOLD_DISCHG_START_HOUR_1,
131
+ HOLD_DISCHG_START_MIN_1,
132
+ HOLD_GRID_FREQ_HIGH_1,
133
+ HOLD_GRID_FREQ_LOW_1,
134
+ # Grid protection parameters
135
+ HOLD_GRID_VOLT_HIGH_1,
136
+ HOLD_GRID_VOLT_LOW_1,
137
+ HOLD_HOUR,
138
+ HOLD_LANGUAGE,
139
+ HOLD_MAX_CHG_CURR,
140
+ HOLD_MAX_DISCHG_CURR,
141
+ HOLD_MINUTE,
142
+ HOLD_MODBUS_ADDRESS,
143
+ HOLD_MONTH,
144
+ # Reactive power control
145
+ HOLD_Q_MODE,
146
+ HOLD_Q_POWER,
147
+ HOLD_Q_PV_MODE,
148
+ HOLD_Q_PV_POWER,
149
+ # Register groups
150
+ HOLD_REGISTER_GROUPS,
151
+ HOLD_SECOND,
152
+ # System configuration
153
+ HOLD_SERIAL_NUMBER_H,
154
+ HOLD_SERIAL_NUMBER_L,
155
+ HOLD_SOC_LOW_LIMIT_EPS_DISCHG,
156
+ HOLD_YEAR,
157
+ INPUT_BMS_FAULT,
158
+ INPUT_BMS_WARNING,
159
+ INPUT_CHARGE_VOLT_REF,
160
+ INPUT_DISCHARGE_VOLT_REF,
161
+ INPUT_E_CHG_ALL,
162
+ INPUT_E_CHG_DAY,
163
+ INPUT_E_DISCHG_ALL,
164
+ INPUT_E_DISCHG_DAY,
165
+ INPUT_E_EPS_ALL,
166
+ INPUT_E_EPS_DAY,
167
+ INPUT_E_INV_ALL,
168
+ INPUT_E_INV_DAY,
169
+ INPUT_E_PV1_ALL,
170
+ INPUT_E_PV1_DAY,
171
+ INPUT_E_PV2_ALL,
172
+ INPUT_E_PV2_DAY,
173
+ INPUT_E_PV3_ALL,
174
+ INPUT_E_PV3_DAY,
175
+ INPUT_E_REC_ALL,
176
+ INPUT_E_REC_DAY,
177
+ INPUT_E_TO_GRID_ALL,
178
+ INPUT_E_TO_GRID_DAY,
179
+ INPUT_E_TO_USER_ALL,
180
+ INPUT_E_TO_USER_DAY,
181
+ INPUT_F_AC,
182
+ INPUT_F_EPS,
183
+ INPUT_FAULT_HISTORY_1,
184
+ INPUT_FAULT_HISTORY_2,
185
+ INPUT_FAULT_HISTORY_3,
186
+ INPUT_FAULT_HISTORY_4,
187
+ INPUT_FAULT_HISTORY_5,
188
+ INPUT_I_BAT,
189
+ INPUT_I_BAT_LIMIT,
190
+ INPUT_I_INV_R,
191
+ INPUT_I_INV_S,
192
+ INPUT_I_INV_T,
193
+ INPUT_I_PV1,
194
+ INPUT_I_PV2,
195
+ INPUT_I_PV3,
196
+ INPUT_I_REC_R,
197
+ INPUT_I_REC_S,
198
+ INPUT_I_REC_T,
199
+ INPUT_INTERNAL_FAULT,
200
+ INPUT_MAX_CHG_CURR,
201
+ INPUT_MAX_DISCHG_CURR,
202
+ INPUT_P_CHARGE,
203
+ INPUT_P_DISCHARGE,
204
+ INPUT_P_EPS,
205
+ INPUT_P_INV,
206
+ INPUT_P_PV1,
207
+ INPUT_P_PV2,
208
+ INPUT_P_PV3,
209
+ INPUT_P_REC,
210
+ INPUT_P_TO_GRID,
211
+ INPUT_P_TO_USER,
212
+ INPUT_PF,
213
+ INPUT_REGISTER_GROUPS,
214
+ INPUT_S_EPS,
215
+ INPUT_SOC,
216
+ INPUT_SOH,
217
+ # Input registers (runtime data)
218
+ INPUT_STATUS,
219
+ INPUT_T_BAT,
220
+ INPUT_T_BAT_CONTROL,
221
+ INPUT_T_INNER,
222
+ INPUT_T_RADIATOR_1,
223
+ INPUT_T_RADIATOR_2,
224
+ INPUT_V_AC_R,
225
+ INPUT_V_AC_S,
226
+ INPUT_V_AC_T,
227
+ INPUT_V_BAT,
228
+ INPUT_V_BAT_LIMIT,
229
+ INPUT_V_BUS1,
230
+ INPUT_V_BUS2,
231
+ INPUT_V_EPS_R,
232
+ INPUT_V_EPS_S,
233
+ INPUT_V_EPS_T,
234
+ INPUT_V_PV1,
235
+ INPUT_V_PV2,
236
+ INPUT_V_PV3,
237
+ LXP_EU_PARAMETERS,
238
+ PARAM_KEY_TO_REGISTER_18KPV,
239
+ PV_SERIES_PARAMETERS,
240
+ REGISTER_STATS_18KPV,
241
+ # Verified register mappings
242
+ REGISTER_TO_PARAM_KEYS_18KPV,
243
+ # Model-specific parameters
244
+ SNA_PARAMETERS,
245
+ # Web parameter mappings
246
+ WEB_PARAM_TO_HOLD_REGISTER,
247
+ get_func_en_bit,
248
+ # Bit manipulation functions
249
+ get_func_en_bit_mask,
250
+ set_func_en_bit,
251
+ )
252
+
253
+ # ============================================================================
254
+ # SCALING MODULE
255
+ # ============================================================================
256
+ from .scaling import (
257
+ BATTERY_BANK_SCALING,
258
+ BATTERY_MODULE_SCALING,
259
+ ENERGY_INFO_SCALING,
260
+ GRIDBOSS_RUNTIME_SCALING,
261
+ INVERTER_OVERVIEW_SCALING,
262
+ # Scaling dictionaries
263
+ INVERTER_RUNTIME_SCALING,
264
+ PARAMETER_SCALING,
265
+ # Scaling factor enum
266
+ ScaleFactor,
267
+ # Private but tested function (exported for backward compatibility)
268
+ _get_scaling_for_field,
269
+ # Scaling functions
270
+ apply_scale,
271
+ get_battery_field_precision,
272
+ get_precision,
273
+ scale_battery_value,
274
+ scale_energy_value,
275
+ scale_runtime_value,
276
+ )
277
+
278
+ # ============================================================================
279
+ # __all__ DEFINITION
280
+ # ============================================================================
281
+ # Explicitly list all exported symbols for better IDE support and documentation
282
+
283
+ __all__ = [
284
+ # Locations
285
+ "TIMEZONE_MAP",
286
+ "TIMEZONE_REVERSE_MAP",
287
+ "COUNTRY_MAP",
288
+ "COUNTRY_REVERSE_MAP",
289
+ "CONTINENT_MAP",
290
+ "CONTINENT_REVERSE_MAP",
291
+ "REGION_MAP",
292
+ "REGION_REVERSE_MAP",
293
+ "COUNTRY_TO_LOCATION_STATIC",
294
+ "get_timezone_enum",
295
+ "get_country_enum",
296
+ "get_region_enum",
297
+ "get_continent_enum",
298
+ "get_continent_region_from_country",
299
+ # Registers
300
+ "FUNC_EN_REGISTER",
301
+ "FUNC_EN_BIT_EPS_EN",
302
+ "FUNC_EN_BIT_AC_CHARGE_EN",
303
+ "FUNC_EN_BIT_SET_TO_STANDBY",
304
+ "FUNC_EN_BIT_FORCED_DISCHG_EN",
305
+ "FUNC_EN_BIT_FORCED_CHG_EN",
306
+ "HOLD_AC_CHARGE_POWER_CMD",
307
+ "HOLD_AC_CHARGE_SOC_LIMIT",
308
+ "HOLD_AC_CHARGE_START_HOUR_1",
309
+ "HOLD_AC_CHARGE_START_MIN_1",
310
+ "HOLD_AC_CHARGE_END_HOUR_1",
311
+ "HOLD_AC_CHARGE_END_MIN_1",
312
+ "HOLD_AC_CHARGE_ENABLE_1",
313
+ "HOLD_AC_CHARGE_ENABLE_2",
314
+ "HOLD_DISCHG_POWER_CMD",
315
+ "HOLD_DISCHG_START_HOUR_1",
316
+ "HOLD_DISCHG_START_MIN_1",
317
+ "HOLD_DISCHG_END_HOUR_1",
318
+ "HOLD_DISCHG_END_MIN_1",
319
+ "HOLD_DISCHG_ENABLE_1",
320
+ "HOLD_BAT_VOLT_MAX_CHG",
321
+ "HOLD_BAT_VOLT_MIN_CHG",
322
+ "HOLD_BAT_VOLT_MAX_DISCHG",
323
+ "HOLD_BAT_VOLT_MIN_DISCHG",
324
+ "HOLD_MAX_CHG_CURR",
325
+ "HOLD_MAX_DISCHG_CURR",
326
+ "HOLD_DISCHG_CUT_OFF_SOC_EOD",
327
+ "HOLD_SOC_LOW_LIMIT_EPS_DISCHG",
328
+ "HOLD_GRID_VOLT_HIGH_1",
329
+ "HOLD_GRID_VOLT_LOW_1",
330
+ "HOLD_GRID_FREQ_HIGH_1",
331
+ "HOLD_GRID_FREQ_LOW_1",
332
+ "HOLD_Q_MODE",
333
+ "HOLD_Q_PV_MODE",
334
+ "HOLD_Q_POWER",
335
+ "HOLD_Q_PV_POWER",
336
+ "HOLD_SERIAL_NUMBER_H",
337
+ "HOLD_SERIAL_NUMBER_L",
338
+ "HOLD_YEAR",
339
+ "HOLD_MONTH",
340
+ "HOLD_DAY",
341
+ "HOLD_HOUR",
342
+ "HOLD_MINUTE",
343
+ "HOLD_SECOND",
344
+ "HOLD_LANGUAGE",
345
+ "HOLD_MODBUS_ADDRESS",
346
+ "HOLD_BAUD_RATE",
347
+ "INPUT_STATUS",
348
+ "INPUT_V_PV1",
349
+ "INPUT_V_PV2",
350
+ "INPUT_V_PV3",
351
+ "INPUT_V_BAT",
352
+ "INPUT_SOC",
353
+ "INPUT_P_PV1",
354
+ "INPUT_P_PV2",
355
+ "INPUT_P_PV3",
356
+ "INPUT_P_CHARGE",
357
+ "INPUT_P_DISCHARGE",
358
+ "INPUT_V_AC_R",
359
+ "INPUT_V_AC_S",
360
+ "INPUT_V_AC_T",
361
+ "INPUT_F_AC",
362
+ "INPUT_P_INV",
363
+ "INPUT_P_REC",
364
+ "INPUT_PF",
365
+ "INPUT_V_EPS_R",
366
+ "INPUT_V_EPS_S",
367
+ "INPUT_V_EPS_T",
368
+ "INPUT_F_EPS",
369
+ "INPUT_P_EPS",
370
+ "INPUT_S_EPS",
371
+ "INPUT_P_TO_GRID",
372
+ "INPUT_P_TO_USER",
373
+ "INPUT_E_INV_ALL",
374
+ "INPUT_E_REC_ALL",
375
+ "INPUT_E_CHG_ALL",
376
+ "INPUT_E_DISCHG_ALL",
377
+ "INPUT_E_EPS_ALL",
378
+ "INPUT_E_TO_GRID_ALL",
379
+ "INPUT_E_TO_USER_ALL",
380
+ "INPUT_V_BUS1",
381
+ "INPUT_V_BUS2",
382
+ "INPUT_E_INV_DAY",
383
+ "INPUT_E_REC_DAY",
384
+ "INPUT_E_CHG_DAY",
385
+ "INPUT_E_DISCHG_DAY",
386
+ "INPUT_E_EPS_DAY",
387
+ "INPUT_E_TO_GRID_DAY",
388
+ "INPUT_E_TO_USER_DAY",
389
+ "INPUT_V_BAT_LIMIT",
390
+ "INPUT_I_BAT_LIMIT",
391
+ "INPUT_T_INNER",
392
+ "INPUT_T_RADIATOR_1",
393
+ "INPUT_T_RADIATOR_2",
394
+ "INPUT_T_BAT",
395
+ "INPUT_T_BAT_CONTROL",
396
+ "INPUT_I_REC_R",
397
+ "INPUT_I_REC_S",
398
+ "INPUT_I_REC_T",
399
+ "INPUT_I_INV_R",
400
+ "INPUT_I_INV_S",
401
+ "INPUT_I_INV_T",
402
+ "INPUT_I_PV1",
403
+ "INPUT_I_PV2",
404
+ "INPUT_I_PV3",
405
+ "INPUT_I_BAT",
406
+ "INPUT_INTERNAL_FAULT",
407
+ "INPUT_FAULT_HISTORY_1",
408
+ "INPUT_FAULT_HISTORY_2",
409
+ "INPUT_FAULT_HISTORY_3",
410
+ "INPUT_FAULT_HISTORY_4",
411
+ "INPUT_FAULT_HISTORY_5",
412
+ "INPUT_SOH",
413
+ "INPUT_BMS_FAULT",
414
+ "INPUT_BMS_WARNING",
415
+ "INPUT_E_PV1_ALL",
416
+ "INPUT_E_PV2_ALL",
417
+ "INPUT_E_PV3_ALL",
418
+ "INPUT_E_PV1_DAY",
419
+ "INPUT_E_PV2_DAY",
420
+ "INPUT_E_PV3_DAY",
421
+ "INPUT_MAX_CHG_CURR",
422
+ "INPUT_MAX_DISCHG_CURR",
423
+ "INPUT_CHARGE_VOLT_REF",
424
+ "INPUT_DISCHARGE_VOLT_REF",
425
+ "HOLD_REGISTER_GROUPS",
426
+ "INPUT_REGISTER_GROUPS",
427
+ "WEB_PARAM_TO_HOLD_REGISTER",
428
+ "REGISTER_TO_PARAM_KEYS_18KPV",
429
+ "PARAM_KEY_TO_REGISTER_18KPV",
430
+ "REGISTER_STATS_18KPV",
431
+ "GRIDBOSS_PARAMETERS",
432
+ "GRIDBOSS_STATS",
433
+ # Model-specific parameters
434
+ "SNA_PARAMETERS",
435
+ "PV_SERIES_PARAMETERS",
436
+ "LXP_EU_PARAMETERS",
437
+ "DEVICE_TYPE_CODE_SNA",
438
+ "DEVICE_TYPE_CODE_PV_SERIES",
439
+ "DEVICE_TYPE_CODE_LXP_EU",
440
+ "get_func_en_bit_mask",
441
+ "set_func_en_bit",
442
+ "get_func_en_bit",
443
+ # Scaling
444
+ "ScaleFactor",
445
+ "INVERTER_RUNTIME_SCALING",
446
+ "ENERGY_INFO_SCALING",
447
+ "BATTERY_BANK_SCALING",
448
+ "BATTERY_MODULE_SCALING",
449
+ "GRIDBOSS_RUNTIME_SCALING",
450
+ "INVERTER_OVERVIEW_SCALING",
451
+ "PARAMETER_SCALING",
452
+ "apply_scale",
453
+ "get_precision",
454
+ "get_battery_field_precision",
455
+ "scale_runtime_value",
456
+ "scale_battery_value",
457
+ "scale_energy_value",
458
+ "_get_scaling_for_field",
459
+ # API
460
+ "HTTP_OK",
461
+ "HTTP_UNAUTHORIZED",
462
+ "HTTP_FORBIDDEN",
463
+ "BACKOFF_BASE_DELAY_SECONDS",
464
+ "BACKOFF_MAX_DELAY_SECONDS",
465
+ "MAX_LOGIN_RETRIES",
466
+ "MAX_TRANSIENT_ERROR_RETRIES",
467
+ "TRANSIENT_ERROR_MESSAGES",
468
+ # Devices
469
+ "DEVICE_TYPE_INVERTER",
470
+ "DEVICE_TYPE_GRIDBOSS",
471
+ "TIMEZONE_HHMM_HOURS_FACTOR",
472
+ "TIMEZONE_HHMM_MINUTES_FACTOR",
473
+ "parse_hhmm_timezone",
474
+ "SCALE_MID_VOLTAGE",
475
+ "SCALE_MID_FREQUENCY",
476
+ "scale_mid_voltage",
477
+ "scale_mid_frequency",
478
+ "SOC_MIN_PERCENT",
479
+ "SOC_MAX_PERCENT",
480
+ "MAX_REGISTERS_PER_READ",
481
+ ]
@@ -0,0 +1,48 @@
1
+ """API-related constants for HTTP communication and error handling.
2
+
3
+ This module contains HTTP status codes, backoff/retry configuration,
4
+ and transient error detection for API communication.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ # HTTP Status Codes
10
+ # ==============================================================================
11
+ # Standard HTTP status codes used throughout the library
12
+ HTTP_OK = 200
13
+ HTTP_UNAUTHORIZED = 401
14
+ HTTP_FORBIDDEN = 403
15
+
16
+ # ==============================================================================
17
+ # Device Type Constants
18
+ # ==============================================================================
19
+ # Device type identifiers from the Luxpower API
20
+ DEVICE_TYPE_INVERTER = 6 # Standard inverter
21
+ DEVICE_TYPE_GRIDBOSS = 9 # GridBOSS/MID device (parallel group controller)
22
+
23
+ # ==============================================================================
24
+ # Backoff and Retry Constants
25
+ # ==============================================================================
26
+ # Base delay (in seconds) for exponential backoff on API errors
27
+ BACKOFF_BASE_DELAY_SECONDS = 1.0
28
+
29
+ # Maximum delay (in seconds) for exponential backoff
30
+ BACKOFF_MAX_DELAY_SECONDS = 60.0
31
+
32
+ # Maximum number of retry attempts for transient errors
33
+ MAX_TRANSIENT_ERROR_RETRIES = 3
34
+
35
+ # Maximum number of retry attempts for login (re-authentication)
36
+ # This allows recovery from transient network issues during re-auth
37
+ # without requiring manual user intervention (fixes issue #70)
38
+ MAX_LOGIN_RETRIES = 3
39
+
40
+ # Known transient error messages that should trigger automatic retry
41
+ # These are hardware/network communication errors that may succeed on retry
42
+ TRANSIENT_ERROR_MESSAGES = {
43
+ "DATAFRAME_TIMEOUT", # Inverter dataframe communication timeout
44
+ "TIMEOUT", # Generic timeout error
45
+ "BUSY", # Device busy, try again
46
+ "COMMUNICATION_ERROR", # Communication failure with device
47
+ "DEVICE_BUSY", # Device is busy processing another request
48
+ }
@@ -0,0 +1,98 @@
1
+ """Device-related constants and helper functions.
2
+
3
+ This module contains device type identifiers, limits, timezone parsing,
4
+ and other device-specific utility functions.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ # ==============================================================================
10
+ # Timezone Parsing Constants
11
+ # ==============================================================================
12
+ # Factor to convert HHMM format timezone offset to hours/minutes
13
+ # Example: timezone offset 800 → 8 hours, 0 minutes (800 // 100 = 8, 800 % 100 = 0)
14
+ TIMEZONE_HHMM_HOURS_FACTOR = 100
15
+ TIMEZONE_HHMM_MINUTES_FACTOR = 100
16
+
17
+ # ==============================================================================
18
+ # MID Device Scaling Constants
19
+ # ==============================================================================
20
+ # Scaling factors for MID device (GridBOSS) values
21
+ # Note: These differ from standard inverter scaling factors
22
+ SCALE_MID_VOLTAGE = 10 # MID device voltages are scaled by 10
23
+ SCALE_MID_FREQUENCY = 100 # Frequency values are scaled by 100
24
+
25
+ # ==============================================================================
26
+ # SOC (State of Charge) Limits
27
+ # ==============================================================================
28
+ # Minimum and maximum allowed SOC percentage values
29
+ SOC_MIN_PERCENT = 0
30
+ SOC_MAX_PERCENT = 100
31
+
32
+ # ==============================================================================
33
+ # Register Reading Limits
34
+ # ==============================================================================
35
+ # Maximum number of registers that can be read in a single API call
36
+ # API limitation: Cannot read more than 127 registers at once
37
+ MAX_REGISTERS_PER_READ = 127
38
+
39
+
40
+ # ==============================================================================
41
+ # Helper Functions
42
+ # ==============================================================================
43
+
44
+
45
+ def parse_hhmm_timezone(value: int) -> tuple[int, int]:
46
+ """Parse HHMM format timezone offset into hours and minutes.
47
+
48
+ Args:
49
+ value: Timezone offset in HHMM format (e.g., 800 for +8:00, -530 for -5:30)
50
+
51
+ Returns:
52
+ Tuple of (hours, minutes) with appropriate sign
53
+
54
+ Examples:
55
+ >>> parse_hhmm_timezone(800)
56
+ (8, 0)
57
+ >>> parse_hhmm_timezone(-530)
58
+ (-5, 30)
59
+ >>> parse_hhmm_timezone(-800)
60
+ (-8, 0)
61
+ """
62
+ hours = abs(value) // TIMEZONE_HHMM_HOURS_FACTOR
63
+ minutes = abs(value) % TIMEZONE_HHMM_MINUTES_FACTOR
64
+ if value < 0:
65
+ hours = -hours
66
+ return hours, minutes
67
+
68
+
69
+ def scale_mid_voltage(raw_value: int | float) -> float:
70
+ """Scale MID device voltage value from API format to volts.
71
+
72
+ Args:
73
+ raw_value: Raw voltage value from MID device API (scaled by 10)
74
+
75
+ Returns:
76
+ Voltage in volts (V)
77
+
78
+ Example:
79
+ >>> scale_mid_voltage(2400)
80
+ 240.0
81
+ """
82
+ return float(raw_value) / SCALE_MID_VOLTAGE
83
+
84
+
85
+ def scale_mid_frequency(raw_value: int | float) -> float:
86
+ """Scale MID device frequency value from API format to Hz.
87
+
88
+ Args:
89
+ raw_value: Raw frequency value from MID device API (scaled by 100)
90
+
91
+ Returns:
92
+ Frequency in Hz
93
+
94
+ Example:
95
+ >>> scale_mid_frequency(5998)
96
+ 59.98
97
+ """
98
+ return float(raw_value) / SCALE_MID_FREQUENCY