Cloud providers show you how to provision devices and set up your IoT environment from a portal.
It's the best way to get started. But it doesn't scale. If your organisation sells many devices, the process should be automated. Safely.
To enable that, many (at least AWS and Azure) have a scriptable interface too. Usually a REST API.
I'm investigating the Avnet IoTConnect REST API - a solution that is hosted on Azure.
I use their example application. This example can provision a new device automatically, without user involvement.
I'm going to do 3 of these steps, to learn and prove that I can use the API:
- open a session
- authenticate
- execute one call that requires being authenticated
Open a Session and Authenticate
This is the Python code snippet from that Avnet example to get a valid session:
def get_auth(username, password, solution_key): try: access_token = None data = None authToken = service_call("GET", AUTH_BASEURL + "/auth/basic-token") if authToken != None: data = str(authToken["data"]) if data != None: body = {} body["username"] = username body["password"] = password header = { "Content-type": "application/json", "Accept": "*/*", "Authorization": 'Basic %s' % data, "Solution-key": solution_key } data = service_call("POST", AUTH_BASEURL + "/auth/login", header, body) if data != None: access_token = str('Bearer %s' % data["access_token"]) return access_token except: return None
The first step is to get a basic token. Then use that, with your account and environment details, to get access (and an access token).
These are constants used in the exercise
http_auth_token = https://auth.iotconnect.io/api/v1.1 http_auth_login = https://auth.iotconnect.io/api/v1.1 http_device_create = https://device.iotconnect.io/api/v1.1 http_device_template = https://device.iotconnect.io/api/v1.1 http_rule_template = https://device.iotconnect.io/api/v1.1 http_event_template = https://event.iotconnect.io/api/v1.1 http_user_template = https://user.iotconnect.io/api/v1.1 http_device_firmware = https://firmware.iotconnect.io/api/v2
I'm using the online REST client REQBIN to interactively run the activities:
Start Session
First I'm retrieving a basic token.
I used the AUTH_BASEURL with /auth/basic-token appended, GET.
After pressing Send, I got this reply:
{ "data": "cHJvZDp2aXVnZG1mdHplcWRuaWdlY3lqbHlhbnFiaWV3amJ4cWZsYnhtcWtmdmRneGNmYWpxY2d1bHVrdnZkZnVpamp4Z2F4Y2hpcm1uZHF1dXBudml1Z2d2ZGVsYWdjamtweGx0anFj", "status": 200, "message": "Basic token has been generated successfully" }
The data is the basis token that we'll use to get authenticated. Status 200 means: OK.
Authenticate
With that info, we go to step 2: authenticate.
The data received in the previous step is our authentication token.
The JSON payload is username and password.
The solution key, a value that is shared by Avnet (I used the one from a sample application) has to be set as a raw header (no quotes).
The image below shows the summary of all data to be posted, and the reply.
The reply, in JSON format:
{ "token_type": "bearer", "access_token": "e********o", "expires_in": 86400, "refresh_token": "m**********************t", "status": 200 }
The status 200 means we have a successful, authenticated session. We can now use it to retrieve info, and use the REST API to provision devices.
Because all of this runs with structured calls and structured replies, this can be automated with scripts or a program.
Perform an API call.
A good proof of concept is to execute an REST API call that needs an active and authenticated session.
I'm going to query the IoTConnect template for my device.
Python code of the Avnet sample:
def get_template(searchText): global ACCESS_TOKEN try: header = { "Content-type": "application/json", "Accept": "*/*", "Authorization": ACCESS_TOKEN } templates = [] response = service_call("GET", TEMPLATE_BASEURL + "/device-template?searchText=%s" % searchText, header) if response != None and response["data"] != None and len(response["data"]) > 0: templates = response["data"] if len(templates) > 0: return templates[0] else: return None except: return None
I'm using a different url, because this is part of the device API, not the authentication API.
I'm querying to see if the template that my device should be assigned to, exists.
For the curious reader, I'm reviewing IoTCloud's RSL10 demo. Here I try to retrieve the template for that example.
When I authenticated, I got a bearer token. That's now used to proceed:
This is the result of executing that query:
{ "data": [{ "guid": "2***-****4", "code": "RSL10Final", "name": "RSL10Final", "description": "For ON Semi RSL10 Beacon Demo", "firmwareGuid": "9*-*-*-*-6", "createdDate": "2021-02-11T15:47:19.720Z", "updatedDate": "2021-04-01T14:51:55.913Z", "attributeCount": 2, "settingCount": 0, "commandCount": 0, "deviceCount": 73, "ruleCount": 7, "isValidateTemplate": true, "isValidEdgeSupport": true, "isValidType2Support": true, "tag": null, "authType": 1, "isEdgeSupport": false, "gatewaySupport": false, "isLowBandwidth": false, "isIotEdgeEnable": false, "isSolutionTemplate": false, "solutionName": null }, { "guid": "***-****-****", "code": "RSL10Spher", "name": "RSL10FinalSphere", "description": "For ON Semi RSL10 Beacon Demo", "firmwareGuid": null, "createdDate": "2021-04-06T17:06:57.890Z", "updatedDate": "2021-04-06T17:06:57.890Z", "attributeCount": 2, "settingCount": 0, "commandCount": 0, "deviceCount": 43, "ruleCount": 0, "isValidateTemplate": true, "isValidEdgeSupport": true, "isValidType2Support": true, "tag": null, "authType": 2, "isEdgeSupport": false, "gatewaySupport": false, "isLowBandwidth": false, "isIotEdgeEnable": false, "isSolutionTemplate": false, "solutionName": null }], "status": 200, "message": "Device template list loaded successfully", "count": 2 }
This cycle of 3 calls confirms the proof of concept, from session initiation, over authentication, up to talking to the IoTConnect Cloud solution.
The approach is similar for other providers. It's a skill you can reuse.