You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.6 KiB
92 lines
2.6 KiB
#
|
|
# Name: ttn_storage_api.py
|
|
#
|
|
# Function:
|
|
# Fetch data from TTN, via storage API
|
|
#
|
|
# Author:
|
|
# Terry Moore, MCCI
|
|
#
|
|
# Use:
|
|
# import ttn_storage_api
|
|
# ttn_storage_api.sensor_pull_storage(...) -- see docs for args
|
|
#
|
|
# Or just cut/paste into your script.
|
|
#
|
|
|
|
import subprocess
|
|
import json
|
|
import pathlib
|
|
import re
|
|
|
|
class Error(Exception):
|
|
"""Base class for errors in this module"""
|
|
pass
|
|
|
|
class FetchError(Error):
|
|
"""Raised when sensor_pull_storage can't deal with input
|
|
|
|
Atrributes:
|
|
expression -- input expression where error occurred
|
|
message -- explanation of the error.
|
|
"""
|
|
def __init__(self, expression, message):
|
|
self.expression = expression
|
|
self.message = message
|
|
|
|
def sensor_pull_storage(appname, accesskey, timestring, *,data_folder = None, ttn_version=3):
|
|
"""
|
|
Pull data from TTN via the TTN storage API.
|
|
|
|
appname is the name of the TTN app
|
|
|
|
accesskey is the full accesskey from ttn. For TTN V3, this is is the
|
|
secret that is output when a key is created. For TTN V2, this is
|
|
the string from the console, starting with 'ttn-acount-v2.'
|
|
|
|
timestring indicates amount of data needed, e.g. '100h'.
|
|
|
|
ttn_version should be 2 or 3; 3 is default.
|
|
|
|
If data_folder is supplied, it is a string or a Path; it is taken as a directory,
|
|
and the name "sensors_lastperiod.json" is appended to form an output file name, and
|
|
the data is written to the resulting file, replacing any previous contents.
|
|
|
|
Otherwise, the data is returned as a Python array (for V3) or a string (for V2).
|
|
We've not really tested V2 extensively.
|
|
"""
|
|
args = [ "curl" ]
|
|
if ttn_version == 2:
|
|
args += [
|
|
"-X", "GET",
|
|
"--header", "Accept: application/json",
|
|
"--header", f"Authorization: key {accesskey}",
|
|
f"https://{appname}.data.thethingsnetwork.org/api/v2/query?last={timestring}"
|
|
]
|
|
elif ttn_version == 3:
|
|
args += [
|
|
"-G", f"https://nam1.cloud.thethings.network/api/v3/as/applications/{appname}/packages/storage/uplink_message",
|
|
"--header", f"Authorization: Bearer {accesskey}",
|
|
"--header", "Accept: text/event-stream",
|
|
"-d", f"last={timestring}",
|
|
"-d", "field_mask=up.uplink_message.decoded_payload",
|
|
]
|
|
else:
|
|
raise FetchError(f"Illegal ttn_version (not 2 or 3)")
|
|
|
|
|
|
# if the user supplied a data_folder, than tack on the args.
|
|
# list1 += list2 syntax means "append each element of list2 to list 1"
|
|
# pathlib.Path allows
|
|
if data_folder != None:
|
|
args += [ "-o", pathlib.Path(data_folder, "sensors_lastperiod.json") ]
|
|
|
|
result = subprocess.run(
|
|
args, shell=False, check=True, capture_output=True
|
|
)
|
|
|
|
sresult = result.stdout
|
|
if ttn_version == 3:
|
|
return list(map(json.loads, re.sub(r'\n+', '\n', sresult.decode()).splitlines()))
|
|
else:
|
|
return sresult
|
|
|