TSD REST API 使用 JSON 有效负载,可以从任何能够使用 REST API 的编程语言或工具中使用。 本教程提供 Python 示例,当然也可以使用其他语言或工具。
以下教程展示了检索和更新令牌的示例,还展示了查询数据的不同可能性!
#In this Python example we will use the requests library:
import requests
import json
url = "https://tsd.proficloud.io/epts/token"
username = "demohmi2020@phoenixcontact-sb.io"
password = "GoDigital2020!"
uuid = '355f6856-e9a4-469f-8f22-3f8b037d064a'
metrics = "auto~pressure,auto~temperature,auto~watt"
验证
首先,我们需要以用户身份在 REST API 上进行身份验证。 访问令牌用于对每个 REST 调用的用户进行身份验证,刷新令牌可用于更新令牌而无需用户名和密码。
Initial token retrieval / username & password
Initially, tokens can be retrieved with the username and password:
#Headers:
header = {
"Content-Type": "application/json"
}
#Payload:
data = {
"username": username,
"password": password
}
#Send post request
token_response = requests.post(url, json=data, headers=header)
if token_response.ok:
access_token = token_response.json().get("access_token")
expires_in = token_response.json().get("expires_in")
refresh_token = token_response.json().get("refresh_token")
refresh_expires_in = token_response.json().get("refresh_expires_in")
print("Access token: ...{}...(length: {}, expires in {}s)".format(access_token[500:600], len(access_token), expires_in))
print("Refresh token: ...{}... (length: {}, expires in {}s, 0 means infinite)".format(refresh_token[500:600], len(refresh_token), refresh_expires_in))
Access token: ...MzQtODljYWYzMDE2MmZmIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwczovL3Byb2ZpY2xvdWQuaW8iLCJodHRw...(length: 1726, expires in 86400s)
Refresh token: ...mF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjJhMjFhZmRhLTRmMDUtNDA5Ny1hZTM0LTg5Y2FmMzAxNjJmZiIsInJlYWxtX... (length: 1079, expires in 0s, 0 means infinite)
Token renewal
The refresh token can be used to obtain new tokens, without the need for a username and password. In [3]:
#Headers:
header = {
"Content-Type": "application/json"
}
#Payload:
data = {
"refresh_token": refresh_token
}
#Send post request
token_response = requests.post(url, json=data, headers=header)
if token_response.ok:
access_token = token_response.json().get("access_token")
expires_in = token_response.json().get("expires_in")
refresh_token = token_response.json().get("refresh_token")
refresh_expires_in = token_response.json().get("refresh_expires_in")
print("Access token: ...{}...(length: {}, expires in {}s)".format(access_token[500:600], len(access_token), expires_in))
print("Refresh token: ...{}... (length: {}, expires in {}s, 0 means infinite)".format(refresh_token[500:600], len(refresh_token), refresh_expires_in))
Access token: ...MzQtODljYWYzMDE2MmZmIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwczovL3Byb2ZpY2xvdWQuaW8iLCJodHRw...(length: 1726, expires in 86400s)
Refresh token: ...mF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjJhMjFhZmRhLTRmMDUtNDA5Ny1hZTM0LTg5Y2FmMzAxNjJmZiIsInJlYWxtX... (length: 1079, expires in 0s, 0 means infinite)
Querying data
There are three options when it comes to querying data from the TSD REST API:
Query last data points
Query historical raw data
Query historical data using database queries (advanced users)
Query last data points
The endpoint /epts/last returns the most recent time series data. (EPTS stands for “endpoint time-series”)
The base url is https://tsd.proficloud.io/epts/last with the following possible parameters. The request method is “GET”.
Authentication happens via header “Authorization” with value “Bearer ACCESS_TOKEN“.
Parameters:
uuid: One or more UUIDs, comma separated without spaces
timeSeriesName: One or more metrics, comma separated without spaces
The response yields in status code 200 and contains a JSON object containing the time series. Possible errors are:
401 – Unauthorized.
500 – e.g. wrong input parameters, content-type, etc. Error message given in response body.
Query historical data using database queries (advanced users)
For advanced users, we also offer the ability to formulate custom queries to read data through the endpoint /query.
The base url is https://tsd.proficloud.io/query with the following possible parameters. The request method is “GET”.
Authentication happens via header “Authorization” with value “Bearer ACCESS_TOKEN“.
Parameters:
q: Query for reading tsd data InfluxDB-Style. An example is shown below, detailed information on the queries can be found here
The response yields in status code 200 and contains a JSON object containing the time series. Possible errors are:
401 – Unauthorized.
500 – e.g. wrong input parameters, content-type, etc. Error message given in response body.
query = "SELECT mean(\"value\") FROM \"auto~watt\" WHERE (\"uuid\" = '355f6856-e9a4-469f-8f22-3f8b037d064a') AND time >= now() - 30s GROUP BY time(10s) fill(none)"
header = {
"Content-Type": "application/json",
"Authorization": "Bearer {}".format(access_token)
}
url = "https://tsd.proficloud.io/query?q={}".format(query)
result = requests.get(url, headers=header)
if result.ok:
print(json.dumps(result.json(), indent=4))
Path where the device certificate is stored (per formatted)
AC_KeyPath
Path where the private key is stored
AC_CaPath
Path where the Ca-Certificate is stored
AC_DeviceID
Identifier of the device (choose your own one)
After this configuration and a restart of the device, it will send its Time Series Data (TSD) to AWS. You can check this by opening the Test page in the IoT Core and subscribing to the following topic:1 dt/proficloud-v1/dcx/<<device identifier>>/json
You can import the following flow as a reference implementation.
[{"id":"e73dae77.7b465","type":"tab","label":"Proficloud Reference","disabled":false,"info":""},{"id":"c386f827.16eb38","type":"ProficloudDevice","z":"e73dae77.7b465","uuid":"","deviceType":"NodeRED-Node","env":"Production","autostart":true,"autodelay":0,"meta_by_payload":false,"serialnumber":"","hardwareVersion":"","x":650,"y":500,"wires":[[]]},{"id":"2f7723f2.906d24","type":"function","z":"e73dae77.7b465","name":"","func":"msg = {};\nmsg.payload = {\"data\" : {\"humidity\": 12.0, \"temp\": 2.0}};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":440,"y":280,"wires":[["c386f827.16eb38"]]},{"id":"788d6d09.2e35ec","type":"inject","z":"e73dae77.7b465","name":"","props":[],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":220,"y":280,"wires":[["2f7723f2.906d24"]]},{"id":"60b2ef0a.8aed9","type":"comment","z":"e73dae77.7b465","name":"TimeSeriesData","info":"","x":180,"y":240,"wires":[]},{"id":"ee768abb.14ce08","type":"function","z":"e73dae77.7b465","name":"","func":"msg = {};\nmsg.payload = {\"trafficlight\": {\"color\": 0, \"msg\": \"Everything is okay\"}};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":440,"y":420,"wires":[["c386f827.16eb38"]]},{"id":"11d12be5.0a1a34","type":"inject","z":"e73dae77.7b465","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":420,"wires":[["ee768abb.14ce08"]]},{"id":"ded8d7ba.28c2f","type":"comment","z":"e73dae77.7b465","name":"TrafficLight - Green","info":"","x":190,"y":380,"wires":[]},{"id":"c17f2af0.f833b8","type":"function","z":"e73dae77.7b465","name":"","func":"msg = {};\nmsg.payload = {\"log\": {\"level\": 2, \"tag\":\"Node-RED\",\"msg\": \"System started\"}};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":440,"y":720,"wires":[["c386f827.16eb38"]]},{"id":"8a321346.644d7","type":"inject","z":"e73dae77.7b465","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":720,"wires":[["c17f2af0.f833b8"]]},{"id":"6f96f6c8.4315f8","type":"comment","z":"e73dae77.7b465","name":"Log","info":"","x":150,"y":680,"wires":[]},{"id":"726085a2.7b897c","type":"function","z":"e73dae77.7b465","name":"","func":"msg = {};\nmsg.payload = {\"trafficlight\": {\"color\": 1, \"msg\": \"Some warning\"}};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":440,"y":500,"wires":[["c386f827.16eb38"]]},{"id":"36dbfce5.50a28c","type":"inject","z":"e73dae77.7b465","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":500,"wires":[["726085a2.7b897c"]]},{"id":"b2e339a0.6f9588","type":"comment","z":"e73dae77.7b465","name":"TrafficLight - Orange","info":"","x":190,"y":460,"wires":[]},{"id":"a86c7275.a4358","type":"function","z":"e73dae77.7b465","name":"","func":"msg = {};\nmsg.payload = {\"trafficlight\": {\"color\": 2, \"msg\": \"Fatal error\"}};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":440,"y":580,"wires":[["c386f827.16eb38"]]},{"id":"2f33ea50.4da396","type":"inject","z":"e73dae77.7b465","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":580,"wires":[["a86c7275.a4358"]]},{"id":"4a0ad995.ab5d6","type":"comment","z":"e73dae77.7b465","name":"TrafficLight - Red","info":"","x":180,"y":540,"wires":[]},{"id":"6a408571.4f517c","type":"comment","z":"e73dae77.7b465","name":"Reference implementation","info":"This is an example flow to show the capabilities of the ProficloudDevice-Node.\nThe inject->function combination can be replaced by the way you like to connect your application. You can also use one of the pre configured Nodes for PxC devices. Just install [this](https://www.npmjs.com/package/node-red-contrib-phoenix-contact).","x":150,"y":180,"wires":[]}]