Я хочу экспортировать телеметрию как необработанные данные для устройства. Так как я должен указать limit
в API телеметрии , я разбиваю запросы на страницы. В противном случае система иногда зависала. Так как значения возвращаются начиная с самых последних, я сужаю конец запрошенного периода дальше. Эта процедура работает только в том случае, если, например, в телеметрии нет старых ключей. Когда появляются старые ключи (например, если я не определяю параметр keys
), моя логика потерпит неудачу.
Существует ли более простой способ получения данных телеметрии через API (без экспорта в csv) определенного интервала времени?
#!/usr/bin/env python
import datetime
import requests
TB_USERNAME = "<user>"
TB_PASSWORD = "***"
THINGSBOARD_URL = "<url>"
TB_API_AUTH_LOGIN = THINGSBOARD_URL + '/api/auth/login'
TB_API_TELEMETRY_CONTROLLER_getTimeseries = THINGSBOARD_URL + '/api/plugins/telemetry/%(entityType)s/%(deviceId)s/values/timeseries'
TB_API_DC_getDeviceCredentialsByDeviceId = THINGSBOARD_URL + '/api/device/%(deviceId)s/credentials'
TB_API_DEVICE_CONTROLLER_getDeviceById = THINGSBOARD_URL + '/api/device/%(deviceId)s'
DEVICES = ("<uid>", )
def datetime_from_millis(millis, epoch=datetime.datetime(1970, 1, 1)):
"""Return UTC time that corresponds to milliseconds since Epoch."""
return epoch + datetime.timedelta(milliseconds=millis)
def timestamp_millis(utc_time, epoch=datetime.datetime(1970, 1, 1)):
"""Return milliseconds since Epoch as integer."""
td = utc_time - epoch
return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) // 10**3
# retrieve Bearer token
auth_token = requests.post(TB_API_AUTH_LOGIN,
json={"username": TB_USERNAME,
"password": TB_PASSWORD},
verify=False).json()
f = open("thingsboard.csv", "w")
f.write("device;date;attr;value\n")
START_TS = datetime.datetime(2019,10,10)
END_TS = datetime.datetime(2019,10,17)
for deviceId in DEVICES:
print("Query device %s" % deviceId)
jwt_header = {"X-Authorization": "Bearer %s" % auth_token["token"]}
api_response_device = requests.get(TB_API_DEVICE_CONTROLLER_getDeviceById % {"deviceId": deviceId},
headers=jwt_header,
verify=False).json()
device_name = api_response_device["name"]
print("Found %s" % device_name)
ts_end = END_TS
while START_TS < ts_end:
print("%s from %s to %s" % (device_name, START_TS, ts_end))
api_response_ts = requests.get(TB_API_TELEMETRY_CONTROLLER_getTimeseries % {"entityType": "DEVICE",
"deviceId": deviceId},
headers=jwt_header,
params={#"keys": "***",
"limit": 2000,
#"agg": "NONE",
"startTs": str(timestamp_millis(START_TS)),
"endTs": str(timestamp_millis(ts_end))},
verify=False).json()
ts_end = START_TS
finished = True
for telemetry_attr, attr_ts in api_response_ts.items():
for data in attr_ts:
# ugly but works for now, round float strings to .2
val = data["value"]
if "." in val:
try:
val = "%.2f" % float(val)
except:
pass
f.write("%s;%s;%s;%s\n" % (device_name, datetime_from_millis(data["ts"]).strftime("%Y-%m-%d %H:%M:%S"), telemetry_attr, val))
# substract a fraction of a second in order to have no overlapping entries
ts_end_value = datetime_from_millis(data["ts"] - 1)
# search the maximum minima of all keys and start with this next round
if ts_end < ts_end_value:
ts_end = ts_end_value
f.close()
Так что мой принцип запросов разбит на страницы в зависимости от значений телеметрии и статического предела.
DEVICE from 2019-10-10 00:00:00 to 2019-10-17 00:00:00
DEVICE from 2019-10-10 00:00:00 to 2019-10-15 14:28:24.497000
DEVICE from 2019-10-10 00:00:00 to 2019-10-14 05:04:25.393000
DEVICE from 2019-10-10 00:00:00 to 2019-10-12 19:32:26.380000
DEVICE from 2019-10-10 00:00:00 to 2019-10-11 10:09:27.350000
DEVICE from 2019-10-10 00:00:00 to 2019-10-10 00:41:28.331000
DEVICE from 2019-10-10 00:00:00 to 2019-10-10 00:00:28.419000