ul-data-logger-api-sdk 3.0.0__tar.gz → 3.2.0__tar.gz
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.
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/.gitignore +4 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/PKG-INFO +2 -2
- ul_data_logger_api_sdk-3.2.0/data_logger_api_sdk.py +344 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/pyproject.toml +1 -1
- ul_data_logger_api_sdk-3.2.0/types/api_base_stations.py +190 -0
- ul_data_logger_api_sdk-3.0.0/data_logger_api_sdk.py +0 -123
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/__init__.py +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/data_logger_sdk_config.py +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/py.typed +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/types/__init__.py +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/types/api_bs_traffic_stats.py +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/types/api_device_data_history.py +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/types/api_last_bs_data_by_device_macs.py +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/types/api_packet_types.py +0 -0
- {ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/types/api_protocol_types.py +0 -0
|
@@ -271,6 +271,7 @@ tags
|
|
|
271
271
|
.envs/*
|
|
272
272
|
!.envs/.local/
|
|
273
273
|
!srv/merge_dotenvs.py
|
|
274
|
+
*.env
|
|
274
275
|
|
|
275
276
|
|
|
276
277
|
.ipynb_checkpoints/
|
|
@@ -291,5 +292,8 @@ _*.ipynb
|
|
|
291
292
|
|
|
292
293
|
/srv/*.retry
|
|
293
294
|
|
|
295
|
+
# Локальный overlay для demo-стенда (пароли, адреса Patroni)
|
|
296
|
+
srv/docker_compose/docker-compose.demo.yml
|
|
297
|
+
|
|
294
298
|
# Swagger spec
|
|
295
299
|
/src/conf/*docs.yml
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
from datetime import date, datetime
|
|
4
|
+
from functools import lru_cache
|
|
5
|
+
from typing import Any, Dict, List, Type
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from ul_api_utils.internal_api.internal_api import InternalApi
|
|
9
|
+
from ul_api_utils.internal_api.internal_api_response import TPyloadType
|
|
10
|
+
from ul_api_utils.utils.api_method import ApiMethod
|
|
11
|
+
|
|
12
|
+
from data_logger_api_sdk.data_logger_sdk_config import DataLoggerApiSdkConfig
|
|
13
|
+
from data_logger_api_sdk.types.api_base_stations import (
|
|
14
|
+
ApiBaseStationDetailResponse,
|
|
15
|
+
ApiBaseStationDeviceLogsResponse,
|
|
16
|
+
ApiBaseStationDeviceLogsStatResponse,
|
|
17
|
+
ApiBaseStationDevicesResponse,
|
|
18
|
+
ApiBaseStationLogsStatForIntervalsResponse,
|
|
19
|
+
ApiBaseStationLogsStatResponse,
|
|
20
|
+
ApiBaseStationLogResponse,
|
|
21
|
+
ApiBaseStationLogsListResult,
|
|
22
|
+
ApiBaseStationsListResult,
|
|
23
|
+
ApiBaseStationResponse,
|
|
24
|
+
ApiBaseStationSystemLogResponse,
|
|
25
|
+
ApiBaseStationSystemLogsListResult,
|
|
26
|
+
)
|
|
27
|
+
from data_logger_api_sdk.types.api_bs_traffic_stats import ApiBsTrafficStatsResponse, ApiDeviceTrafficStatsQuery
|
|
28
|
+
from data_logger_api_sdk.types.api_device_data_history import ApiDeviceDataHistoryBody, ApiDeviceDataHistoryResponse
|
|
29
|
+
from data_logger_api_sdk.types.api_last_bs_data_by_device_macs import ApiDeviceLastBsDataResponse, ApiDeviceMacsListBodyModel
|
|
30
|
+
from data_logger_api_sdk.types.api_packet_types import ApiPacketTypesListResponse
|
|
31
|
+
from data_logger_api_sdk.types.api_protocol_types import ApiProtocolTypesListResponse
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DataLoggerApiSdk:
|
|
35
|
+
|
|
36
|
+
def __init__(self, config: DataLoggerApiSdkConfig) -> None:
|
|
37
|
+
self._config = config
|
|
38
|
+
self._api = InternalApi(entry_point=self._config.api_url, default_auth_token=self._config.api_token)
|
|
39
|
+
|
|
40
|
+
@lru_cache(maxsize=None) # there should not be leaks memory leaks. flake8 just scared inmemory cache ;)
|
|
41
|
+
def request_payload(
|
|
42
|
+
self,
|
|
43
|
+
_: int,
|
|
44
|
+
method: ApiMethod,
|
|
45
|
+
endpoint: str,
|
|
46
|
+
typed_as: Type[TPyloadType],
|
|
47
|
+
body: str | None,
|
|
48
|
+
query: str | None = None,
|
|
49
|
+
) -> TPyloadType:
|
|
50
|
+
return (
|
|
51
|
+
self._api.request(
|
|
52
|
+
method=method,
|
|
53
|
+
path=endpoint,
|
|
54
|
+
json=json.loads(body) if body is not None else None,
|
|
55
|
+
q=json.loads(query) if query is not None else None,
|
|
56
|
+
)
|
|
57
|
+
.typed(typed_as)
|
|
58
|
+
.check()
|
|
59
|
+
.payload
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def _get_cache_post_payload(
|
|
63
|
+
self,
|
|
64
|
+
method: ApiMethod,
|
|
65
|
+
path: str,
|
|
66
|
+
typed: Type[TPyloadType],
|
|
67
|
+
body: str | None = None,
|
|
68
|
+
query: str | None = None,
|
|
69
|
+
) -> TPyloadType:
|
|
70
|
+
ttl_status = round(time.time() / self._config.cache_ttl_s)
|
|
71
|
+
return self.request_payload(ttl_status, method, path, typed, body, query) # type: ignore # Type[TPyloadType] is hashable
|
|
72
|
+
|
|
73
|
+
def _request_payload_once(
|
|
74
|
+
self,
|
|
75
|
+
method: ApiMethod,
|
|
76
|
+
path: str,
|
|
77
|
+
typed: Type[TPyloadType],
|
|
78
|
+
query: Dict[str, Any] | None = None,
|
|
79
|
+
) -> TPyloadType:
|
|
80
|
+
response = self._api.request(
|
|
81
|
+
method=method,
|
|
82
|
+
path=path,
|
|
83
|
+
json=None,
|
|
84
|
+
q=query,
|
|
85
|
+
).typed(typed).check()
|
|
86
|
+
return response.payload
|
|
87
|
+
|
|
88
|
+
def _request_list_payload_once(
|
|
89
|
+
self,
|
|
90
|
+
method: ApiMethod,
|
|
91
|
+
path: str,
|
|
92
|
+
typed: Type[TPyloadType],
|
|
93
|
+
query: Dict[str, Any] | None = None,
|
|
94
|
+
) -> tuple[TPyloadType, int]:
|
|
95
|
+
response = self._api.request(
|
|
96
|
+
method=method,
|
|
97
|
+
path=path,
|
|
98
|
+
json=None,
|
|
99
|
+
q=query,
|
|
100
|
+
).typed(typed).check()
|
|
101
|
+
total_count = response.total_count
|
|
102
|
+
assert total_count is not None, "total_count must be present for array payloads"
|
|
103
|
+
return response.payload, total_count
|
|
104
|
+
|
|
105
|
+
def get_protocol_types_list(self, mac: int) -> List[str]:
|
|
106
|
+
return self._get_cache_post_payload(
|
|
107
|
+
ApiMethod.GET,
|
|
108
|
+
f"/devices/mac/{mac}/logs/protocol-types",
|
|
109
|
+
ApiProtocolTypesListResponse,
|
|
110
|
+
).protocol_types
|
|
111
|
+
|
|
112
|
+
def get_packet_types_list(self, mac: int) -> List[str]:
|
|
113
|
+
return self._get_cache_post_payload(
|
|
114
|
+
ApiMethod.GET,
|
|
115
|
+
f"/devices/mac/{mac}/logs/packet-types",
|
|
116
|
+
ApiPacketTypesListResponse,
|
|
117
|
+
).packet_types
|
|
118
|
+
|
|
119
|
+
def get_device_data_history(
|
|
120
|
+
self,
|
|
121
|
+
period_from: datetime,
|
|
122
|
+
period_to: datetime,
|
|
123
|
+
mac: int,
|
|
124
|
+
protocol_type: str | None = None,
|
|
125
|
+
packet_type: str | None = None,
|
|
126
|
+
) -> List[ApiDeviceDataHistoryResponse]:
|
|
127
|
+
api_device_history_body = ApiDeviceDataHistoryBody(
|
|
128
|
+
period_from=period_from,
|
|
129
|
+
period_to=period_to,
|
|
130
|
+
mac=mac,
|
|
131
|
+
protocol_type=protocol_type,
|
|
132
|
+
packet_type=packet_type,
|
|
133
|
+
).model_dump_json()
|
|
134
|
+
return self._get_cache_post_payload(
|
|
135
|
+
ApiMethod.POST,
|
|
136
|
+
"/device-data-history",
|
|
137
|
+
List[ApiDeviceDataHistoryResponse], # type: ignore
|
|
138
|
+
api_device_history_body,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def get_last_bs_data_by_device_macs(
|
|
142
|
+
self,
|
|
143
|
+
macs: set[int],
|
|
144
|
+
) -> List[ApiDeviceLastBsDataResponse]:
|
|
145
|
+
return self._get_cache_post_payload(
|
|
146
|
+
ApiMethod.POST,
|
|
147
|
+
"/devices/last-bs-data",
|
|
148
|
+
List[ApiDeviceLastBsDataResponse], # type: ignore
|
|
149
|
+
ApiDeviceMacsListBodyModel(macs=macs).model_dump_json(),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def get_bs_traffic_stats(
|
|
153
|
+
self,
|
|
154
|
+
base_station_id: UUID,
|
|
155
|
+
start_at: datetime,
|
|
156
|
+
end_at: datetime,
|
|
157
|
+
) -> List[ApiBsTrafficStatsResponse]:
|
|
158
|
+
api_bs_traffic_stats_query = ApiDeviceTrafficStatsQuery(
|
|
159
|
+
start_at=start_at,
|
|
160
|
+
end_at=end_at,
|
|
161
|
+
)
|
|
162
|
+
return self._get_cache_post_payload(
|
|
163
|
+
ApiMethod.GET,
|
|
164
|
+
f"/base-stations/{base_station_id}/traffic-stats",
|
|
165
|
+
List[ApiBsTrafficStatsResponse], # type: ignore
|
|
166
|
+
None,
|
|
167
|
+
api_bs_traffic_stats_query.model_dump_json(),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def get_base_stations(
|
|
171
|
+
self,
|
|
172
|
+
limit: int,
|
|
173
|
+
offset: int = 0,
|
|
174
|
+
serial_number: int | None = None,
|
|
175
|
+
log_stat_days: int = 0,
|
|
176
|
+
) -> ApiBaseStationsListResult:
|
|
177
|
+
"""GET /base-stations — список базовых станций Data Logger."""
|
|
178
|
+
query: Dict[str, Any] = {
|
|
179
|
+
"limit": limit,
|
|
180
|
+
"offset": offset,
|
|
181
|
+
"log_stat_days": log_stat_days,
|
|
182
|
+
}
|
|
183
|
+
if serial_number is not None:
|
|
184
|
+
query["serial_number"] = serial_number
|
|
185
|
+
items, total_count = self._request_list_payload_once(
|
|
186
|
+
ApiMethod.GET,
|
|
187
|
+
"/base-stations",
|
|
188
|
+
List[ApiBaseStationResponse], # type: ignore
|
|
189
|
+
query,
|
|
190
|
+
)
|
|
191
|
+
return ApiBaseStationsListResult(items=items, total_count=total_count)
|
|
192
|
+
|
|
193
|
+
def get_base_station(
|
|
194
|
+
self,
|
|
195
|
+
base_station_id: UUID,
|
|
196
|
+
log_stat_days: int = 0,
|
|
197
|
+
) -> ApiBaseStationDetailResponse:
|
|
198
|
+
"""GET /base-stations/<uuid> — карточка базовой станции Data Logger."""
|
|
199
|
+
return self._request_payload_once(
|
|
200
|
+
ApiMethod.GET,
|
|
201
|
+
f"/base-stations/{base_station_id}",
|
|
202
|
+
ApiBaseStationDetailResponse,
|
|
203
|
+
{"log_stat_days": log_stat_days},
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def get_base_station_logs(
|
|
207
|
+
self,
|
|
208
|
+
base_station_id: UUID,
|
|
209
|
+
start_at: datetime | None = None,
|
|
210
|
+
end_at: datetime | None = None,
|
|
211
|
+
limit: int = 100,
|
|
212
|
+
offset: int = 0,
|
|
213
|
+
exclude_log_types: List[str] | None = None,
|
|
214
|
+
sort: str | None = None,
|
|
215
|
+
) -> ApiBaseStationLogsListResult:
|
|
216
|
+
"""GET /base-stations/<uuid>/logs — журнал логов базовой станции.
|
|
217
|
+
|
|
218
|
+
exclude_log_types передаётся стандартным filter-параметром
|
|
219
|
+
(например, ['heartbit'] прячет служебные heartbeat-логи).
|
|
220
|
+
"""
|
|
221
|
+
query: Dict[str, Any] = {"limit": limit, "offset": offset}
|
|
222
|
+
if start_at is not None:
|
|
223
|
+
query["start_at"] = start_at.isoformat()
|
|
224
|
+
if end_at is not None:
|
|
225
|
+
query["end_at"] = end_at.isoformat()
|
|
226
|
+
if exclude_log_types:
|
|
227
|
+
query["filter"] = json.dumps([{"name": "log_type", "op": "not_in", "val": exclude_log_types}])
|
|
228
|
+
if sort:
|
|
229
|
+
query["sort"] = sort
|
|
230
|
+
items, total_count = self._request_list_payload_once(
|
|
231
|
+
ApiMethod.GET,
|
|
232
|
+
f"/base-stations/{base_station_id}/logs",
|
|
233
|
+
List[ApiBaseStationLogResponse], # type: ignore
|
|
234
|
+
query,
|
|
235
|
+
)
|
|
236
|
+
return ApiBaseStationLogsListResult(items=items, total_count=total_count)
|
|
237
|
+
|
|
238
|
+
def get_base_station_system_logs(
|
|
239
|
+
self,
|
|
240
|
+
base_station_id: UUID,
|
|
241
|
+
start_at: datetime | None = None,
|
|
242
|
+
end_at: datetime | None = None,
|
|
243
|
+
limit: int = 100,
|
|
244
|
+
offset: int = 0,
|
|
245
|
+
) -> ApiBaseStationSystemLogsListResult:
|
|
246
|
+
"""GET /base-stations/<uuid>/system-logs — журнал системных логов базовой станции."""
|
|
247
|
+
query: Dict[str, Any] = {"limit": limit, "offset": offset}
|
|
248
|
+
if start_at is not None:
|
|
249
|
+
query["start_at"] = start_at.isoformat()
|
|
250
|
+
if end_at is not None:
|
|
251
|
+
query["end_at"] = end_at.isoformat()
|
|
252
|
+
items, total_count = self._request_list_payload_once(
|
|
253
|
+
ApiMethod.GET,
|
|
254
|
+
f"/base-stations/{base_station_id}/system-logs",
|
|
255
|
+
List[ApiBaseStationSystemLogResponse], # type: ignore
|
|
256
|
+
query,
|
|
257
|
+
)
|
|
258
|
+
return ApiBaseStationSystemLogsListResult(items=items, total_count=total_count)
|
|
259
|
+
|
|
260
|
+
def get_base_station_logs_stat(
|
|
261
|
+
self,
|
|
262
|
+
base_station_id: UUID,
|
|
263
|
+
day: date,
|
|
264
|
+
) -> ApiBaseStationLogsStatResponse:
|
|
265
|
+
"""GET /base-stations/<uuid>/logs-stat — статистика логов базовой станции за сутки."""
|
|
266
|
+
return self._request_payload_once(
|
|
267
|
+
ApiMethod.GET,
|
|
268
|
+
f"/base-stations/{base_station_id}/logs-stat",
|
|
269
|
+
ApiBaseStationLogsStatResponse,
|
|
270
|
+
{"day": day.isoformat()},
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
def get_base_station_device_logs_stat(
|
|
274
|
+
self,
|
|
275
|
+
base_station_id: UUID,
|
|
276
|
+
start_at: datetime,
|
|
277
|
+
end_at: datetime | None = None,
|
|
278
|
+
) -> ApiBaseStationDeviceLogsStatResponse:
|
|
279
|
+
"""GET /base-stations/<uuid>/device-logs-stat — число логов устройств БС по дням."""
|
|
280
|
+
query: Dict[str, Any] = {"start_at": start_at.isoformat()}
|
|
281
|
+
if end_at is not None:
|
|
282
|
+
query["end_at"] = end_at.isoformat()
|
|
283
|
+
return self._request_payload_once(
|
|
284
|
+
ApiMethod.GET,
|
|
285
|
+
f"/base-stations/{base_station_id}/device-logs-stat",
|
|
286
|
+
ApiBaseStationDeviceLogsStatResponse,
|
|
287
|
+
query,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def get_base_station_logs_stat_for_intervals(
|
|
291
|
+
self,
|
|
292
|
+
base_station_id: UUID,
|
|
293
|
+
start_at: datetime,
|
|
294
|
+
end_at: datetime | None = None,
|
|
295
|
+
) -> ApiBaseStationLogsStatForIntervalsResponse:
|
|
296
|
+
"""GET /base-stations/<uuid>/logs-stat-for-intervals — метки времени логов за интервал."""
|
|
297
|
+
query: Dict[str, Any] = {"start_at": start_at.isoformat()}
|
|
298
|
+
if end_at is not None:
|
|
299
|
+
query["end_at"] = end_at.isoformat()
|
|
300
|
+
return self._request_payload_once(
|
|
301
|
+
ApiMethod.GET,
|
|
302
|
+
f"/base-stations/{base_station_id}/logs-stat-for-intervals",
|
|
303
|
+
ApiBaseStationLogsStatForIntervalsResponse,
|
|
304
|
+
query,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
def get_base_station_devices(
|
|
308
|
+
self,
|
|
309
|
+
base_station_id: UUID,
|
|
310
|
+
start_at: datetime,
|
|
311
|
+
end_at: datetime | None = None,
|
|
312
|
+
limit: int = 100,
|
|
313
|
+
offset: int = 0,
|
|
314
|
+
) -> ApiBaseStationDevicesResponse:
|
|
315
|
+
"""GET /base-stations/<uuid>/devices — устройства, работающие через базовую станцию."""
|
|
316
|
+
query: Dict[str, Any] = {"start_at": start_at.isoformat(), "limit": limit, "offset": offset}
|
|
317
|
+
if end_at is not None:
|
|
318
|
+
query["end_at"] = end_at.isoformat()
|
|
319
|
+
return self._request_payload_once(
|
|
320
|
+
ApiMethod.GET,
|
|
321
|
+
f"/base-stations/{base_station_id}/devices",
|
|
322
|
+
ApiBaseStationDevicesResponse,
|
|
323
|
+
query,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
def get_base_station_device_logs(
|
|
327
|
+
self,
|
|
328
|
+
base_station_id: UUID,
|
|
329
|
+
start_at: datetime,
|
|
330
|
+
end_at: datetime | None = None,
|
|
331
|
+
limit: int = 100,
|
|
332
|
+
offset: int = 0,
|
|
333
|
+
) -> ApiBaseStationDeviceLogsResponse:
|
|
334
|
+
"""GET /base-stations/<uuid>/device-logs — логи устройств базовой станции."""
|
|
335
|
+
query: Dict[str, Any] = {"start_at": start_at.isoformat(), "limit": limit, "offset": offset}
|
|
336
|
+
if end_at is not None:
|
|
337
|
+
query["end_at"] = end_at.isoformat()
|
|
338
|
+
return self._request_payload_once(
|
|
339
|
+
ApiMethod.GET,
|
|
340
|
+
f"/base-stations/{base_station_id}/device-logs",
|
|
341
|
+
ApiBaseStationDeviceLogsResponse,
|
|
342
|
+
query,
|
|
343
|
+
)
|
|
344
|
+
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
from typing import Any, Dict, List, NamedTuple, Tuple
|
|
3
|
+
|
|
4
|
+
from pydantic.types import UUID4
|
|
5
|
+
from ul_api_utils.api_resource.api_response import JsonApiResponsePayload
|
|
6
|
+
|
|
7
|
+
BS__LOG_TYPE__DEVICE_DATA = "device_data"
|
|
8
|
+
BS__LOG_TYPE__HEARTBIT = "heartbit"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ApiBaseStationsListResult(NamedTuple):
|
|
12
|
+
"""Результат спискового вызова BS-endpoint Data Logger: страница элементов и total_count."""
|
|
13
|
+
|
|
14
|
+
items: List["ApiBaseStationResponse"]
|
|
15
|
+
total_count: int
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ApiBaseStationLogsListResult(NamedTuple):
|
|
19
|
+
"""Результат вызова GET /base-stations/<uuid>/logs."""
|
|
20
|
+
|
|
21
|
+
items: List["ApiBaseStationLogResponse"]
|
|
22
|
+
total_count: int
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ApiBaseStationSystemLogsListResult(NamedTuple):
|
|
26
|
+
"""Результат вызова GET /base-stations/<uuid>/system-logs."""
|
|
27
|
+
|
|
28
|
+
items: List["ApiBaseStationSystemLogResponse"]
|
|
29
|
+
total_count: int
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ApiBaseStationResponse(JsonApiResponsePayload):
|
|
33
|
+
"""Элемент ответа GET /base-stations (BsListShortResponse на стороне Data Logger)."""
|
|
34
|
+
|
|
35
|
+
id: UUID4
|
|
36
|
+
date_created: datetime
|
|
37
|
+
date_modified: datetime
|
|
38
|
+
is_alive: bool
|
|
39
|
+
|
|
40
|
+
api_user_modified_id: UUID4 | None = None
|
|
41
|
+
note: str = ""
|
|
42
|
+
permission_id: int
|
|
43
|
+
|
|
44
|
+
type: str
|
|
45
|
+
serial_number: int
|
|
46
|
+
|
|
47
|
+
latest_log_datetime: datetime | None = None
|
|
48
|
+
latest_geo_latitude: float | None = None
|
|
49
|
+
latest_geo_longitude: float | None = None
|
|
50
|
+
latest_soft_version: str | None = None
|
|
51
|
+
latest_geo_is_actual: bool | None = None
|
|
52
|
+
latest_sdr_config_id: UUID4 | None = None
|
|
53
|
+
|
|
54
|
+
logs_stat: List[Tuple[datetime, int]] | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ApiBaseStationDetailResponse(ApiBaseStationResponse):
|
|
58
|
+
"""Ответ GET /base-stations/<uuid> (BsResponse на стороне Data Logger)."""
|
|
59
|
+
|
|
60
|
+
latest_sdr_config: Dict[str, Any] | None = None
|
|
61
|
+
device_counts: List[Tuple[datetime, int]] | None = None
|
|
62
|
+
system_logs_stat: List[Tuple[datetime, int]] | None = None
|
|
63
|
+
environment_spectrums_stat: List[Tuple[datetime, int]] | None = None
|
|
64
|
+
sdr_config_data_list: List[Dict[str, Any] | None] | None = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ApiBaseStationLogResponse(JsonApiResponsePayload):
|
|
68
|
+
"""Элемент ответа GET /base-stations/<uuid>/logs (ApiBsLogsResponse на стороне Data Logger)."""
|
|
69
|
+
|
|
70
|
+
id: UUID4
|
|
71
|
+
date_created: datetime
|
|
72
|
+
|
|
73
|
+
bs_id: UUID4 | None = None
|
|
74
|
+
protocol: str | None = None
|
|
75
|
+
log_type: str
|
|
76
|
+
|
|
77
|
+
date_sending: datetime
|
|
78
|
+
|
|
79
|
+
latitude: float | None = None
|
|
80
|
+
longitude: float | None = None
|
|
81
|
+
soft_version: str | None = None
|
|
82
|
+
uptime_s: int | None = None
|
|
83
|
+
|
|
84
|
+
external_document_id: UUID4 | None = None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ApiBaseStationSystemLogResponse(JsonApiResponsePayload):
|
|
88
|
+
"""Элемент ответа GET /base-stations/<uuid>/system-logs (ApiBsSystemLogsResponse)."""
|
|
89
|
+
|
|
90
|
+
id: UUID4
|
|
91
|
+
date_created: datetime
|
|
92
|
+
|
|
93
|
+
bs_id: UUID4 | None = None
|
|
94
|
+
bs_log_id: UUID4 | None = None
|
|
95
|
+
date: datetime
|
|
96
|
+
type: str
|
|
97
|
+
mdl: str | None = None
|
|
98
|
+
text: str | None = None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class ApiBaseStationLogsStatResponse(JsonApiResponsePayload):
|
|
102
|
+
"""Ответ GET /base-stations/<uuid>/logs-stat (ApiBsLogsStatResponse)."""
|
|
103
|
+
|
|
104
|
+
stats: List[Tuple[datetime, int]]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ApiBaseStationLogsStatForIntervalsResponse(JsonApiResponsePayload):
|
|
108
|
+
"""Ответ GET /base-stations/<uuid>/logs-stat-for-intervals (ApiBsLogsStatForIntervalsGraphResponse)."""
|
|
109
|
+
|
|
110
|
+
stats: List[datetime]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class ApiBaseStationDeviceLogsStatResponse(JsonApiResponsePayload):
|
|
114
|
+
"""Ответ GET /base-stations/<uuid>/device-logs-stat: число логов устройств по дням."""
|
|
115
|
+
|
|
116
|
+
stats: List[Tuple[date, int]]
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class ApiBaseStationDeviceResponse(JsonApiResponsePayload):
|
|
120
|
+
"""Элемент devices ответа GET /base-stations/<uuid>/devices (ApiDeviceResponse без вложенной БС)."""
|
|
121
|
+
|
|
122
|
+
id: UUID4
|
|
123
|
+
date_created: datetime
|
|
124
|
+
date_modified: datetime
|
|
125
|
+
is_alive: bool
|
|
126
|
+
|
|
127
|
+
api_user_modified_id: UUID4
|
|
128
|
+
note: str
|
|
129
|
+
|
|
130
|
+
device_id: UUID4
|
|
131
|
+
device_network_id: UUID4
|
|
132
|
+
device_network_mac: int
|
|
133
|
+
|
|
134
|
+
latest_device_gateway_id: UUID4 | None = None
|
|
135
|
+
latest_device_protocol_id: UUID4
|
|
136
|
+
latest_device_protocol_type: str | None = None
|
|
137
|
+
latest_device_network_sys_type: str | None = None
|
|
138
|
+
latest_log_datetime: datetime
|
|
139
|
+
latest_bs_id: UUID4 | None = None
|
|
140
|
+
latest_signal_rssi: int | None = None
|
|
141
|
+
latest_signal_snr: int | None = None
|
|
142
|
+
|
|
143
|
+
logs_stat: List[Tuple[datetime, int]] | None = None
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class ApiBaseStationDevicesResponse(JsonApiResponsePayload):
|
|
147
|
+
"""Ответ GET /base-stations/<uuid>/devices (ApiBsDevicesResponse)."""
|
|
148
|
+
|
|
149
|
+
devices: List[ApiBaseStationDeviceResponse]
|
|
150
|
+
device_count: int
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class ApiBaseStationDeviceLogResponse(JsonApiResponsePayload):
|
|
154
|
+
"""Элемент device_logs ответа GET /base-stations/<uuid>/device-logs (ApiDeviceLogsResponse)."""
|
|
155
|
+
|
|
156
|
+
id: UUID4
|
|
157
|
+
date_created: datetime
|
|
158
|
+
|
|
159
|
+
bs_id: UUID4 | None = None
|
|
160
|
+
device_id: UUID4
|
|
161
|
+
|
|
162
|
+
device_gateway_id: UUID4 | None = None
|
|
163
|
+
device_protocol_id: UUID4
|
|
164
|
+
|
|
165
|
+
signal_rssi: int | None = None
|
|
166
|
+
signal_snr: int | None = None
|
|
167
|
+
|
|
168
|
+
date_sending: datetime
|
|
169
|
+
|
|
170
|
+
is_verified: bool | None = None
|
|
171
|
+
protocol_type: str | None = None
|
|
172
|
+
packet_type_name: str | None = None
|
|
173
|
+
network_id: UUID4 | None = None
|
|
174
|
+
network_sys_type: str | None = None
|
|
175
|
+
decrypted_payload: str | None = None
|
|
176
|
+
raw_payload: str | None = None
|
|
177
|
+
|
|
178
|
+
error_message: str | None = None
|
|
179
|
+
error_type: str | None = None
|
|
180
|
+
|
|
181
|
+
device: Dict[str, Any] | None = None
|
|
182
|
+
external_document_id: UUID4 | None = None
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class ApiBaseStationDeviceLogsResponse(JsonApiResponsePayload):
|
|
186
|
+
"""Ответ GET /base-stations/<uuid>/device-logs (ApiBsDeviceLogsResponse)."""
|
|
187
|
+
|
|
188
|
+
device_logs: List[ApiBaseStationDeviceLogResponse]
|
|
189
|
+
device_logs_count: int
|
|
190
|
+
device_count: int
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import time
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from functools import lru_cache
|
|
5
|
-
from typing import List, Type
|
|
6
|
-
from uuid import UUID
|
|
7
|
-
|
|
8
|
-
from ul_api_utils.internal_api.internal_api import InternalApi
|
|
9
|
-
from ul_api_utils.internal_api.internal_api_response import TPyloadType
|
|
10
|
-
from ul_api_utils.utils.api_method import ApiMethod
|
|
11
|
-
|
|
12
|
-
from data_logger_api_sdk.data_logger_sdk_config import DataLoggerApiSdkConfig
|
|
13
|
-
from data_logger_api_sdk.types.api_bs_traffic_stats import ApiBsTrafficStatsResponse, ApiDeviceTrafficStatsQuery
|
|
14
|
-
from data_logger_api_sdk.types.api_device_data_history import ApiDeviceDataHistoryBody, ApiDeviceDataHistoryResponse
|
|
15
|
-
from data_logger_api_sdk.types.api_last_bs_data_by_device_macs import ApiDeviceLastBsDataResponse, ApiDeviceMacsListBodyModel
|
|
16
|
-
from data_logger_api_sdk.types.api_packet_types import ApiPacketTypesListResponse
|
|
17
|
-
from data_logger_api_sdk.types.api_protocol_types import ApiProtocolTypesListResponse
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class DataLoggerApiSdk:
|
|
21
|
-
|
|
22
|
-
def __init__(self, config: DataLoggerApiSdkConfig) -> None:
|
|
23
|
-
self._config = config
|
|
24
|
-
self._api = InternalApi(entry_point=self._config.api_url, default_auth_token=self._config.api_token)
|
|
25
|
-
|
|
26
|
-
@lru_cache(maxsize=None) # there should not be leaks memory leaks. flake8 just scared inmemory cache ;)
|
|
27
|
-
def request_payload(
|
|
28
|
-
self,
|
|
29
|
-
_: int,
|
|
30
|
-
method: ApiMethod,
|
|
31
|
-
endpoint: str,
|
|
32
|
-
typed_as: Type[TPyloadType],
|
|
33
|
-
body: str | None,
|
|
34
|
-
query: str | None = None,
|
|
35
|
-
) -> TPyloadType:
|
|
36
|
-
return (
|
|
37
|
-
self._api.request(
|
|
38
|
-
method=method,
|
|
39
|
-
path=endpoint,
|
|
40
|
-
json=json.loads(body) if body is not None else None,
|
|
41
|
-
q=json.loads(query) if query is not None else None,
|
|
42
|
-
)
|
|
43
|
-
.typed(typed_as)
|
|
44
|
-
.check()
|
|
45
|
-
.payload
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
def _get_cache_post_payload(
|
|
49
|
-
self,
|
|
50
|
-
method: ApiMethod,
|
|
51
|
-
path: str,
|
|
52
|
-
typed: Type[TPyloadType],
|
|
53
|
-
body: str | None = None,
|
|
54
|
-
query: str | None = None,
|
|
55
|
-
) -> TPyloadType:
|
|
56
|
-
ttl_status = round(time.time() / self._config.cache_ttl_s)
|
|
57
|
-
return self.request_payload(ttl_status, method, path, typed, body, query) # type: ignore # Type[TPyloadType] is hashable
|
|
58
|
-
|
|
59
|
-
def get_protocol_types_list(self, mac: int) -> List[str]:
|
|
60
|
-
return self._get_cache_post_payload(
|
|
61
|
-
ApiMethod.GET,
|
|
62
|
-
f"/devices/mac/{mac}/logs/protocol-types",
|
|
63
|
-
ApiProtocolTypesListResponse,
|
|
64
|
-
).protocol_types
|
|
65
|
-
|
|
66
|
-
def get_packet_types_list(self, mac: int) -> List[str]:
|
|
67
|
-
return self._get_cache_post_payload(
|
|
68
|
-
ApiMethod.GET,
|
|
69
|
-
f"/devices/mac/{mac}/logs/packet-types",
|
|
70
|
-
ApiPacketTypesListResponse,
|
|
71
|
-
).packet_types
|
|
72
|
-
|
|
73
|
-
def get_device_data_history(
|
|
74
|
-
self,
|
|
75
|
-
period_from: datetime,
|
|
76
|
-
period_to: datetime,
|
|
77
|
-
mac: int,
|
|
78
|
-
protocol_type: str | None = None,
|
|
79
|
-
packet_type: str | None = None,
|
|
80
|
-
) -> List[ApiDeviceDataHistoryResponse]:
|
|
81
|
-
api_device_history_body = ApiDeviceDataHistoryBody(
|
|
82
|
-
period_from=period_from,
|
|
83
|
-
period_to=period_to,
|
|
84
|
-
mac=mac,
|
|
85
|
-
protocol_type=protocol_type,
|
|
86
|
-
packet_type=packet_type,
|
|
87
|
-
).model_dump_json()
|
|
88
|
-
return self._get_cache_post_payload(
|
|
89
|
-
ApiMethod.POST,
|
|
90
|
-
"/device-data-history",
|
|
91
|
-
List[ApiDeviceDataHistoryResponse], # type: ignore
|
|
92
|
-
api_device_history_body,
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
def get_last_bs_data_by_device_macs(
|
|
96
|
-
self,
|
|
97
|
-
macs: set[int],
|
|
98
|
-
) -> List[ApiDeviceLastBsDataResponse]:
|
|
99
|
-
return self._get_cache_post_payload(
|
|
100
|
-
ApiMethod.POST,
|
|
101
|
-
"/devices/last-bs-data",
|
|
102
|
-
List[ApiDeviceLastBsDataResponse], # type: ignore
|
|
103
|
-
ApiDeviceMacsListBodyModel(macs=macs).model_dump_json(),
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
def get_bs_traffic_stats(
|
|
107
|
-
self,
|
|
108
|
-
base_station_id: UUID,
|
|
109
|
-
start_at: datetime,
|
|
110
|
-
end_at: datetime,
|
|
111
|
-
) -> List[ApiBsTrafficStatsResponse]:
|
|
112
|
-
api_bs_traffic_stats_query = ApiDeviceTrafficStatsQuery(
|
|
113
|
-
start_at=start_at,
|
|
114
|
-
end_at=end_at,
|
|
115
|
-
)
|
|
116
|
-
return self._get_cache_post_payload(
|
|
117
|
-
ApiMethod.GET,
|
|
118
|
-
f"/base-stations/{base_station_id}/traffic-stats",
|
|
119
|
-
List[ApiBsTrafficStatsResponse], # type: ignore
|
|
120
|
-
None,
|
|
121
|
-
api_bs_traffic_stats_query.model_dump_json(),
|
|
122
|
-
)
|
|
123
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ul_data_logger_api_sdk-3.0.0 → ul_data_logger_api_sdk-3.2.0}/types/api_device_data_history.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|