An example of how to use the REST API with a simple script that identifies devices by touch.
Overview
A feature in DT Studio popular with our customers is the ability to locate a sensor by simply touching it. Like all functions in DT Studio, the implementation is based on our REST API. We will in this example show how simple it is to recreate using the stream endpoint.
Preliminaries
Basic Auth
For simplicity, we here use Basic Auth for authentication. We recommend replacing this with an OAuth2 flow for integrations more complex than local experimentation.
Service Account Credentials
You must create and know the credentials of a Service Account. Any role will suffice.
Streaming Best Practices
While this example is based on our other example for Streaming Events, it does not implement the same retry policy or other best practices as it is not the focus here. You are, however, free to combine the two examples for a more robust touch-event-listening loop.
Example Code
The following points summarize the provided example code.
Sends a GET request to the REST API to initialize an event stream.
Keep the TCP connection open while receiving events.
When receiving a Touch Event, fetch and print the source device information.
Break the stream.
Environment Setup
If you wish to run the code locally, make sure you have a working runtime environment.
The following packages are required by the example code and must be installed.
pip install requests==2.31.0
The latest version of our Python API can be installed through pip.
pip install --upgrade disruptive
The following modules are required by the example code and must be installed.
The following code snippet implements the touch-to-identify listening loop.
import osimport jsonimport requests# Service Account credentials.SERVICE_ACCOUNT_KEY_ID = os.getenv('DT_SERVICE_ACCOUNT_KEY_ID')SERVICE_ACCOUNT_SECRET = os.getenv('DT_SERVICE_ACCOUNT_SECRET')# Construct API URL.PROJECT_ID = os.getenv('DT_PROJECT_ID')API_BASE ='https://api.d21s.com/v2/'DEVICES_STREAM_URL ='{}projects/{}/devices:stream'.format( API_BASE, PROJECT_ID)if__name__=='__main__':# Set up a stream connection.print('Waiting for touch event...') stream = requests.get( url=DEVICES_STREAM_URL, auth=(SERVICE_ACCOUNT_KEY_ID, SERVICE_ACCOUNT_SECRET), stream=True, params={'event_types': ['touch'], }, )# Iterate through the events as they come in (one event per line).for line in stream.iter_lines():# Decode the response payload and isolate event dictionary. payload = json.loads(line.decode('ascii'))# Halt at missing key.if'result'notin payload.keys():print(payload)break# Fetch touched device blob for more detailed information. event = payload['result']['event'] device = requests.get( url=API_BASE + event['targetName'], auth=(SERVICE_ACCOUNT_KEY_ID, SERVICE_ACCOUNT_SECRET), ).json()# Print some device information.print('\nTouch event received:')print(json.dumps(device, indent=4))# Stop stream as we've found a device.break
import osimport disruptive as dt# Environment variables for target project.PROJECT_ID = os.getenv('DT_PROJECT_ID', '')if__name__=='__main__':# Enable logging to see what's happening under the hood. dt.log_level ='debug'# Set up a stream for all touch events in a project.for e in dt.Stream.event_stream(PROJECT_ID, event_types=['touch']):# When a touch event is received, fetch the source device. touched_device = dt.Device.get_device(e.device_id)# Print information about the touched device.print(touched_device)# Stop the stream as we've found a device.break
constEventSource=require("eventsource") // npm install eventsource@1.0.7constjwt=require('jsonwebtoken') // npm install jsonwebtoken@8.5.1constaxios=require('axios').default // npm install axios@0.21.1// Service Account credentialsconstserviceAccountKeyID=process.env.DT_SERVICE_ACCOUNT_KEY_IDconstserviceAccountSecret=process.env.DT_SERVICE_ACCOUNT_SECRETconstserviceAccountEmail=process.env.DT_SERVICE_ACCOUNT_EMAIL// Construct API URLconstprojectID=process.env.DT_PROJECT_IDconstapiBase='https://api.d21s.com/v2/'constdevicesStreamUrl= apiBase +`projects/${projectID}/devices:stream`asyncfunctionmain() {let retryCount =0let streamsetupStream()asyncfunctionsetupStream() {// Since EventSource does not support setting HTTP headers, we need to use// OAuth for authentication. The received access token will be set as a// `token` query parameter when setting up the stream in the next step.constaccessToken=awaitgetAccessToken( serviceAccountKeyID, serviceAccountEmail, serviceAccountSecret, )// Add query parameters to the URLlet url = devicesStreamUrl url +=`?eventTypes=touch`// Filters out all events except touch url +=`&token=${accessToken}`// The access token for authentication// Set up a new stream with callback functions for messagesconsole.log('Waiting for touch event...') stream =newEventSource(url)stream.onmessage = handleStreamMessage }asyncfunctionhandleStreamMessage(message) {// Parse the payload as JSONconstdata=JSON.parse(message.data)if (!data ||!data.result) {return }// Parse the event objectconstevent=data.result.event// Close stream as we've found a devicestream.close()// Send GET request to fetch device information.constresponse=awaitaxios({ method:'GET', url: apiBase +event.targetName, auth: { username:process.env.DT_SERVICE_ACCOUNT_KEY_ID, password:process.env.DT_SERVICE_ACCOUNT_SECRET, } })// Print response contents.console.log('\nTouch event received:')console.log(JSON.stringify(response.data,null,2)) }}main().catch((err) => {console.log(err)})// Fetches an access token. See the following guide for documentation:// https://developer.d12s.com/docs/authentication/oauth2asyncfunctiongetAccessToken(keyID, email, secret) {// Construct the JWT headerlet jwtHeaders = {'alg':'HS256','kid': keyID, }// Construct the JWT payloadlet jwtPayload = {'iat':Math.floor(Date.now() /1000),// current unixtime'exp':Math.floor(Date.now() /1000) +3600,// expiration unixtime'aud':'https://identity.disruptive-technologies.com/oauth2/token','iss': email, }// Sign and encode JWT with the secretconstjwtEncoded=jwt.sign( jwtPayload, secret, { header: jwtHeaders, algorithm:'HS256', }, )// Prepare POST request dataconstrequestObject= {'assertion': jwtEncoded,'grant_type':'urn:ietf:params:oauth:grant-type:jwt-bearer', }// Converts the requestObject to a Form URL-Encoded stringconstrequestData=Object.keys(requestObject).map(function(key) {returnencodeURIComponent(key)+'='+encodeURIComponent(requestObject[key]) }).join('&')// Exchange JWT for access tokenconstaccessTokenResponse=awaitaxios({ method:'POST', url:'https://identity.disruptive-technologies.com/oauth2/token', headers: { 'Content-Type':'application/x-www-form-urlencoded' }, data: requestData, }).catch(function (error) {if (error.response) {console.log(error.response.data) }throw error })// Return the access token in the requestreturnaccessTokenResponse.data.access_token}
Expected Output
Once a touch event has been received, the device information is printed and stream terminated.