pylxpweb 0.1.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.
- pylxpweb/__init__.py +39 -0
- pylxpweb/client.py +417 -0
- pylxpweb/constants.py +1183 -0
- pylxpweb/endpoints/__init__.py +27 -0
- pylxpweb/endpoints/analytics.py +446 -0
- pylxpweb/endpoints/base.py +43 -0
- pylxpweb/endpoints/control.py +306 -0
- pylxpweb/endpoints/devices.py +250 -0
- pylxpweb/endpoints/export.py +86 -0
- pylxpweb/endpoints/firmware.py +235 -0
- pylxpweb/endpoints/forecasting.py +109 -0
- pylxpweb/endpoints/plants.py +470 -0
- pylxpweb/exceptions.py +23 -0
- pylxpweb/models.py +765 -0
- pylxpweb/py.typed +0 -0
- pylxpweb/registers.py +511 -0
- pylxpweb-0.1.0.dist-info/METADATA +433 -0
- pylxpweb-0.1.0.dist-info/RECORD +19 -0
- pylxpweb-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Endpoint-specific modules for the Luxpower API client.
|
|
2
|
+
|
|
3
|
+
This package organizes API endpoints into logical modules following the strategy pattern.
|
|
4
|
+
Each module handles a specific category of endpoints (analytics, plants, devices, etc.).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pylxpweb.endpoints.analytics import AnalyticsEndpoints
|
|
10
|
+
from pylxpweb.endpoints.base import BaseEndpoint
|
|
11
|
+
from pylxpweb.endpoints.control import ControlEndpoints
|
|
12
|
+
from pylxpweb.endpoints.devices import DeviceEndpoints
|
|
13
|
+
from pylxpweb.endpoints.export import ExportEndpoints
|
|
14
|
+
from pylxpweb.endpoints.firmware import FirmwareEndpoints
|
|
15
|
+
from pylxpweb.endpoints.forecasting import ForecastingEndpoints
|
|
16
|
+
from pylxpweb.endpoints.plants import PlantEndpoints
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"BaseEndpoint",
|
|
20
|
+
"PlantEndpoints",
|
|
21
|
+
"DeviceEndpoints",
|
|
22
|
+
"ControlEndpoints",
|
|
23
|
+
"AnalyticsEndpoints",
|
|
24
|
+
"ExportEndpoints",
|
|
25
|
+
"ForecastingEndpoints",
|
|
26
|
+
"FirmwareEndpoints",
|
|
27
|
+
]
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
"""Analytics endpoints for the Luxpower API.
|
|
2
|
+
|
|
3
|
+
This module provides analytics functionality including:
|
|
4
|
+
- Time-series chart data for sensors
|
|
5
|
+
- Energy breakdowns (hourly, daily, monthly, yearly, lifetime)
|
|
6
|
+
- Event/fault/warning logs
|
|
7
|
+
- Battery and inverter information
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
14
|
+
|
|
15
|
+
from pylxpweb.endpoints.base import BaseEndpoint
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from pylxpweb.client import LuxpowerClient
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AnalyticsEndpoints(BaseEndpoint):
|
|
22
|
+
"""Analytics endpoints for charts, energy breakdowns, and event logs."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, client: LuxpowerClient) -> None:
|
|
25
|
+
"""Initialize analytics endpoints.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
client: The parent LuxpowerClient instance
|
|
29
|
+
"""
|
|
30
|
+
super().__init__(client)
|
|
31
|
+
|
|
32
|
+
async def get_chart_data(
|
|
33
|
+
self,
|
|
34
|
+
serial_num: str,
|
|
35
|
+
attribute: str,
|
|
36
|
+
date: str,
|
|
37
|
+
) -> dict[str, Any]:
|
|
38
|
+
"""Get time-series data for specific sensor attribute.
|
|
39
|
+
|
|
40
|
+
This endpoint retrieves hourly time-series data for any sensor attribute
|
|
41
|
+
over a specific date. Very flexible - supports all InverterRuntime fields.
|
|
42
|
+
|
|
43
|
+
Available attributes: vpv1, vpv2, ppv, ppv1, ppv2, vBat, soc, pCharge,
|
|
44
|
+
pDisCharge, pToGrid, pToUser, pInv, pRec, pEps, vacr, vacs, vact, fac,
|
|
45
|
+
tinner, tradiator1, tradiator2, tBat, and more.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
serial_num: Device serial number
|
|
49
|
+
attribute: Sensor attribute name (from InverterRuntime fields)
|
|
50
|
+
date: Date in YYYY-MM-DD format
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Dict containing:
|
|
54
|
+
- success: Boolean
|
|
55
|
+
- dataPoints: List of {time: str, value: number} objects
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
# Get PV voltage over time
|
|
59
|
+
data = await client.analytics.get_chart_data("1234567890", "vpv1", "2025-11-19")
|
|
60
|
+
for point in data["dataPoints"]:
|
|
61
|
+
print(f"{point['time']}: {point['value']/100}V") # Scale voltage
|
|
62
|
+
|
|
63
|
+
Note:
|
|
64
|
+
Data points are typically hourly (24 entries for full day).
|
|
65
|
+
Remember to apply scaling factors (voltage ÷100, etc.)
|
|
66
|
+
"""
|
|
67
|
+
await self.client._ensure_authenticated()
|
|
68
|
+
|
|
69
|
+
data = {
|
|
70
|
+
"serialNum": serial_num,
|
|
71
|
+
"attr": attribute,
|
|
72
|
+
"dateText": date,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
response = await self.client._request(
|
|
76
|
+
"POST",
|
|
77
|
+
"/WManage/api/analyze/chart/dayLine",
|
|
78
|
+
data=data,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return dict(response)
|
|
82
|
+
|
|
83
|
+
async def get_energy_day_breakdown(
|
|
84
|
+
self,
|
|
85
|
+
serial_num: str,
|
|
86
|
+
date: str,
|
|
87
|
+
energy_type: str = "eInvDay",
|
|
88
|
+
*,
|
|
89
|
+
parallel: bool = False,
|
|
90
|
+
) -> dict[str, Any]:
|
|
91
|
+
"""Get hourly energy breakdown for specific day.
|
|
92
|
+
|
|
93
|
+
Returns 24 hourly energy values for the specified date and energy type.
|
|
94
|
+
|
|
95
|
+
Energy Types:
|
|
96
|
+
- eInvDay: Inverter daily energy production
|
|
97
|
+
- eToUserDay: Load consumption
|
|
98
|
+
- eToGridDay: Grid export
|
|
99
|
+
- eAcChargeDay: AC charging
|
|
100
|
+
- eBatChargeDay: Battery charging
|
|
101
|
+
- eBatDischargeDay: Battery discharging
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
serial_num: Device serial number
|
|
105
|
+
date: Date in YYYY-MM-DD format
|
|
106
|
+
energy_type: Energy type to query (default: eInvDay)
|
|
107
|
+
parallel: Query parallel group data (default: False)
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Dict containing:
|
|
111
|
+
- success: Boolean
|
|
112
|
+
- dataPoints: List of {period: str, value: number} hourly energy values
|
|
113
|
+
|
|
114
|
+
Example:
|
|
115
|
+
# Get hourly solar production
|
|
116
|
+
breakdown = await client.analytics.get_energy_day_breakdown(
|
|
117
|
+
"1234567890",
|
|
118
|
+
"2025-11-19",
|
|
119
|
+
"eInvDay"
|
|
120
|
+
)
|
|
121
|
+
total = sum(p["value"] for p in breakdown["dataPoints"])
|
|
122
|
+
print(f"Total production: {total/1000}kWh")
|
|
123
|
+
"""
|
|
124
|
+
await self.client._ensure_authenticated()
|
|
125
|
+
|
|
126
|
+
# Parse date to extract year, month, day
|
|
127
|
+
date_obj = datetime.strptime(date, "%Y-%m-%d")
|
|
128
|
+
|
|
129
|
+
data = {
|
|
130
|
+
"serialNum": serial_num,
|
|
131
|
+
"parallel": str(parallel).lower(),
|
|
132
|
+
"year": date_obj.year,
|
|
133
|
+
"month": date_obj.month,
|
|
134
|
+
"day": date_obj.day,
|
|
135
|
+
"energyType": energy_type,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
response = await self.client._request(
|
|
139
|
+
"POST",
|
|
140
|
+
"/WManage/api/analyze/energy/dayColumn",
|
|
141
|
+
data=data,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
return dict(response)
|
|
145
|
+
|
|
146
|
+
async def get_energy_month_breakdown(
|
|
147
|
+
self,
|
|
148
|
+
serial_num: str,
|
|
149
|
+
year: int,
|
|
150
|
+
month: int,
|
|
151
|
+
energy_type: str = "eInvDay",
|
|
152
|
+
*,
|
|
153
|
+
parallel: bool = False,
|
|
154
|
+
) -> dict[str, Any]:
|
|
155
|
+
"""Get daily energy breakdown for specific month.
|
|
156
|
+
|
|
157
|
+
Returns daily energy values for each day in the specified month.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
serial_num: Device serial number
|
|
161
|
+
year: Year (e.g., 2025)
|
|
162
|
+
month: Month (1-12)
|
|
163
|
+
energy_type: Energy type to query (default: eInvDay)
|
|
164
|
+
parallel: Query parallel group data (default: False)
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Dict containing:
|
|
168
|
+
- success: Boolean
|
|
169
|
+
- dataPoints: List of {period: str, value: number} daily energy values
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
# Get November 2025 daily production
|
|
173
|
+
breakdown = await client.analytics.get_energy_month_breakdown(
|
|
174
|
+
"1234567890",
|
|
175
|
+
2025,
|
|
176
|
+
11,
|
|
177
|
+
"eInvDay"
|
|
178
|
+
)
|
|
179
|
+
"""
|
|
180
|
+
await self.client._ensure_authenticated()
|
|
181
|
+
|
|
182
|
+
data = {
|
|
183
|
+
"serialNum": serial_num,
|
|
184
|
+
"parallel": str(parallel).lower(),
|
|
185
|
+
"year": year,
|
|
186
|
+
"month": month,
|
|
187
|
+
"energyType": energy_type,
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
response = await self.client._request(
|
|
191
|
+
"POST",
|
|
192
|
+
"/WManage/api/analyze/energy/monthColumn",
|
|
193
|
+
data=data,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
return dict(response)
|
|
197
|
+
|
|
198
|
+
async def get_energy_year_breakdown(
|
|
199
|
+
self,
|
|
200
|
+
serial_num: str,
|
|
201
|
+
year: int,
|
|
202
|
+
energy_type: str = "eInvDay",
|
|
203
|
+
*,
|
|
204
|
+
parallel: bool = False,
|
|
205
|
+
) -> dict[str, Any]:
|
|
206
|
+
"""Get monthly energy breakdown for specific year.
|
|
207
|
+
|
|
208
|
+
Returns monthly energy values for the specified year (12 months).
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
serial_num: Device serial number
|
|
212
|
+
year: Year (e.g., 2025)
|
|
213
|
+
energy_type: Energy type to query (default: eInvDay)
|
|
214
|
+
parallel: Query parallel group data (default: False)
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Dict containing:
|
|
218
|
+
- success: Boolean
|
|
219
|
+
- dataPoints: List of {period: str, value: number} monthly energy values
|
|
220
|
+
|
|
221
|
+
Example:
|
|
222
|
+
# Get 2025 monthly production
|
|
223
|
+
breakdown = await client.analytics.get_energy_year_breakdown(
|
|
224
|
+
"1234567890",
|
|
225
|
+
2025,
|
|
226
|
+
"eInvDay"
|
|
227
|
+
)
|
|
228
|
+
"""
|
|
229
|
+
await self.client._ensure_authenticated()
|
|
230
|
+
|
|
231
|
+
data = {
|
|
232
|
+
"serialNum": serial_num,
|
|
233
|
+
"parallel": str(parallel).lower(),
|
|
234
|
+
"year": year,
|
|
235
|
+
"energyType": energy_type,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
response = await self.client._request(
|
|
239
|
+
"POST",
|
|
240
|
+
"/WManage/api/analyze/energy/yearColumn",
|
|
241
|
+
data=data,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
return dict(response)
|
|
245
|
+
|
|
246
|
+
async def get_energy_total_breakdown(
|
|
247
|
+
self,
|
|
248
|
+
serial_num: str,
|
|
249
|
+
energy_type: str = "eInvDay",
|
|
250
|
+
*,
|
|
251
|
+
parallel: bool = False,
|
|
252
|
+
) -> dict[str, Any]:
|
|
253
|
+
"""Get yearly energy breakdown for device lifetime.
|
|
254
|
+
|
|
255
|
+
Returns energy data broken down by year for the device's entire lifetime.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
serial_num: Device serial number
|
|
259
|
+
energy_type: Energy type to query (default: eInvDay)
|
|
260
|
+
parallel: Query parallel group data (default: False)
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Dict containing:
|
|
264
|
+
- success: Boolean
|
|
265
|
+
- dataPoints: List of {period: str, value: number} yearly energy values
|
|
266
|
+
|
|
267
|
+
Example:
|
|
268
|
+
# Get lifetime yearly production
|
|
269
|
+
breakdown = await client.analytics.get_energy_total_breakdown(
|
|
270
|
+
"1234567890",
|
|
271
|
+
"eInvDay"
|
|
272
|
+
)
|
|
273
|
+
"""
|
|
274
|
+
await self.client._ensure_authenticated()
|
|
275
|
+
|
|
276
|
+
data = {
|
|
277
|
+
"serialNum": serial_num,
|
|
278
|
+
"parallel": str(parallel).lower(),
|
|
279
|
+
"energyType": energy_type,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
response = await self.client._request(
|
|
283
|
+
"POST",
|
|
284
|
+
"/WManage/api/analyze/energy/totalColumn",
|
|
285
|
+
data=data,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
return dict(response)
|
|
289
|
+
|
|
290
|
+
async def get_event_list(
|
|
291
|
+
self,
|
|
292
|
+
serial_num: str,
|
|
293
|
+
*,
|
|
294
|
+
page: int = 1,
|
|
295
|
+
rows: int = 30,
|
|
296
|
+
plant_id: int = -1,
|
|
297
|
+
event_filter: str = "_all",
|
|
298
|
+
) -> dict[str, Any]:
|
|
299
|
+
"""Get fault/warning/event log with pagination.
|
|
300
|
+
|
|
301
|
+
Retrieves system events including faults, warnings, and informational messages.
|
|
302
|
+
Critical for monitoring system health and tracking issues over time.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
serial_num: Device serial number
|
|
306
|
+
page: Page number (default: 1)
|
|
307
|
+
rows: Rows per page (default: 30)
|
|
308
|
+
plant_id: Plant ID filter (-1 for all plants)
|
|
309
|
+
event_filter: Event type filter ("_all", or specific fault/warning code)
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
Dict containing:
|
|
313
|
+
- success: Boolean
|
|
314
|
+
- total: Total number of events
|
|
315
|
+
- rows: List of event objects with:
|
|
316
|
+
- eventId: Event identifier
|
|
317
|
+
- eventCode: Fault/warning code
|
|
318
|
+
- eventType: FAULT/WARNING/INFO
|
|
319
|
+
- eventText: Human-readable description
|
|
320
|
+
- startTime: Event start timestamp
|
|
321
|
+
- endTime: Event end timestamp (empty if ongoing)
|
|
322
|
+
- statusText: ACTIVE/RESOLVED
|
|
323
|
+
|
|
324
|
+
Example:
|
|
325
|
+
# Get all events
|
|
326
|
+
events = await client.analytics.get_event_list("1234567890")
|
|
327
|
+
for event in events["rows"]:
|
|
328
|
+
if event["statusText"] == "ACTIVE":
|
|
329
|
+
print(f"Active {event['eventType']}: {event['eventText']}")
|
|
330
|
+
|
|
331
|
+
# Get only faults
|
|
332
|
+
faults = await client.analytics.get_event_list(
|
|
333
|
+
"1234567890",
|
|
334
|
+
event_filter="FAULT"
|
|
335
|
+
)
|
|
336
|
+
"""
|
|
337
|
+
await self.client._ensure_authenticated()
|
|
338
|
+
|
|
339
|
+
data = {
|
|
340
|
+
"page": page,
|
|
341
|
+
"rows": rows,
|
|
342
|
+
"plantId": plant_id,
|
|
343
|
+
"serialNum": serial_num,
|
|
344
|
+
"eventText": event_filter,
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
response = await self.client._request(
|
|
348
|
+
"POST",
|
|
349
|
+
"/WManage/api/analyze/event/list",
|
|
350
|
+
data=data,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
return dict(response)
|
|
354
|
+
|
|
355
|
+
async def get_battery_list(self, serial_num: str) -> dict[str, Any]:
|
|
356
|
+
"""Get simplified battery list for UI selection.
|
|
357
|
+
|
|
358
|
+
Retrieves lightweight battery enumeration without full metrics.
|
|
359
|
+
Useful for populating dropdown menus or battery selection UI.
|
|
360
|
+
|
|
361
|
+
Difference from devices.get_battery_info():
|
|
362
|
+
- This endpoint: Only batteryKey, SN, index, online status
|
|
363
|
+
- Full endpoint: Complete metrics (voltage, current, SOC, SoH, temps, etc.)
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
serial_num: Inverter serial number
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
Dict containing:
|
|
370
|
+
- success: Boolean
|
|
371
|
+
- serialNum: Inverter serial number
|
|
372
|
+
- totalNumber: Total battery count
|
|
373
|
+
- batteryArray: List of battery objects with:
|
|
374
|
+
- batteryKey: Unique identifier
|
|
375
|
+
- batterySn: Battery serial number
|
|
376
|
+
- batIndex: Position in array (0-indexed)
|
|
377
|
+
- lost: Whether battery is offline
|
|
378
|
+
|
|
379
|
+
Example:
|
|
380
|
+
batteries = await client.analytics.get_battery_list("1234567890")
|
|
381
|
+
print(f"Found {batteries['totalNumber']} batteries")
|
|
382
|
+
for bat in batteries["batteryArray"]:
|
|
383
|
+
status = "Offline" if bat["lost"] else "Online"
|
|
384
|
+
print(f" {bat['batterySn']}: {status}")
|
|
385
|
+
"""
|
|
386
|
+
await self.client._ensure_authenticated()
|
|
387
|
+
|
|
388
|
+
data = {"serialNum": serial_num}
|
|
389
|
+
|
|
390
|
+
cache_key = self._get_cache_key("battery_list", serialNum=serial_num)
|
|
391
|
+
response = await self.client._request(
|
|
392
|
+
"POST",
|
|
393
|
+
"/WManage/api/battery/getBatteryInfoForSet",
|
|
394
|
+
data=data,
|
|
395
|
+
cache_key=cache_key,
|
|
396
|
+
cache_endpoint="battery_info",
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
return dict(response)
|
|
400
|
+
|
|
401
|
+
async def get_inverter_info(self, serial_num: str) -> dict[str, Any]:
|
|
402
|
+
"""Get inverter static information.
|
|
403
|
+
|
|
404
|
+
Retrieves inverter configuration and static details (model, firmware, capacity).
|
|
405
|
+
|
|
406
|
+
Complements devices.get_inverter_runtime():
|
|
407
|
+
- This endpoint: Static configuration data
|
|
408
|
+
- Runtime endpoint: Dynamic operational metrics
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
serial_num: Inverter serial number
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
Dict containing:
|
|
415
|
+
- success: Boolean
|
|
416
|
+
- serialNum: Inverter serial number
|
|
417
|
+
- deviceType: Device type code
|
|
418
|
+
- deviceTypeText: Model name (e.g., "18KPV")
|
|
419
|
+
- powerRating: Power rating code
|
|
420
|
+
- powerRatingText: Power rating (e.g., "12kW")
|
|
421
|
+
- fwCode: Firmware version
|
|
422
|
+
- batteryType: LITHIUM/LEAD_ACID
|
|
423
|
+
- nominalCapacity: Battery capacity (Ah)
|
|
424
|
+
- installedCapacity: PV capacity (W)
|
|
425
|
+
- phase: 1=single phase, 3=three phase
|
|
426
|
+
|
|
427
|
+
Example:
|
|
428
|
+
info = await client.analytics.get_inverter_info("1234567890")
|
|
429
|
+
print(f"Model: {info['deviceTypeText']}")
|
|
430
|
+
print(f"Firmware: {info['fwCode']}")
|
|
431
|
+
print(f"PV Capacity: {info['installedCapacity']}W")
|
|
432
|
+
"""
|
|
433
|
+
await self.client._ensure_authenticated()
|
|
434
|
+
|
|
435
|
+
data = {"serialNum": serial_num}
|
|
436
|
+
|
|
437
|
+
cache_key = self._get_cache_key("inverter_info", serialNum=serial_num)
|
|
438
|
+
response = await self.client._request(
|
|
439
|
+
"POST",
|
|
440
|
+
"/WManage/api/inverter/getInverterInfo",
|
|
441
|
+
data=data,
|
|
442
|
+
cache_key=cache_key,
|
|
443
|
+
cache_endpoint="device_discovery",
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
return dict(response)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Base endpoint class for all endpoint-specific modules.
|
|
2
|
+
|
|
3
|
+
This module provides the BaseEndpoint class that all endpoint modules inherit from.
|
|
4
|
+
It provides access to the parent client's session and request method.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pylxpweb.client import LuxpowerClient
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BaseEndpoint:
|
|
16
|
+
"""Base class for endpoint-specific functionality.
|
|
17
|
+
|
|
18
|
+
All endpoint modules (analytics, plants, devices, etc.) inherit from this class
|
|
19
|
+
to gain access to the parent client's session and request method.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
client: Reference to the parent LuxpowerClient instance
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, client: LuxpowerClient) -> None:
|
|
26
|
+
"""Initialize the endpoint with a reference to the parent client.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
client: The parent LuxpowerClient instance
|
|
30
|
+
"""
|
|
31
|
+
self.client = client
|
|
32
|
+
|
|
33
|
+
def _get_cache_key(self, endpoint: str, **kwargs: Any) -> str:
|
|
34
|
+
"""Generate cache key for request.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
endpoint: The endpoint name
|
|
38
|
+
**kwargs: Parameters to include in cache key
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Cache key string
|
|
42
|
+
"""
|
|
43
|
+
return self.client._get_cache_key(endpoint, **kwargs)
|