DT Developer Docs
REST APIDT StudioStatus Page
  • Getting Started
  • Overview
  • Concepts
    • Devices
    • Events
    • Topics
      • Temperature Measurement Interval
      • Motion Sensor Activity Timer
  • Data Connectors
    • Introduction to Data Connectors
    • Creating a Data Connector
    • Configuring a Data Connector
    • Receiving Events
    • Best Practices
    • Example Integrations
      • Heroku
      • Google Cloud Functions
      • AWS Lambda
      • Azure HTTP Triggers
      • IBM Cloud Actions
    • Development Guides
      • Local Development with ngrok
  • REST API
  • Introduction to REST API
  • Explore Our Endpoints
    • with cURL
    • with Python API
    • with Postman
  • Authentication
    • OAuth2
    • Basic Auth
  • Error Codes
  • Emulator API
  • Examples
    • Pagination
    • Streaming Events
    • Touch to Identify
    • Refreshing Access Token
  • Reference
  • Status Page
  • Service Accounts
    • Introduction to Service Accounts
    • Creating a Service Account
    • Managing Access Rights
    • Permissions
    • Organizational Structures
  • Other
    • Application Notes
      • Generating a Room Temperature Heatmap
      • Modeling Fridge Content Temperatures
      • Outlier Detection on Multiple Temperature Sensors
      • Simple Temperature Forecasting for Substation Transformers
      • Sensor Data Insight with Power BI and Azure
      • Third-Party Sensor Data in DT Cloud
    • Frequently Asked Question
Powered by GitBook
On this page
  • Overview
  • Preliminaries
  • Example Code
  • Environment Setup
  • Source
  • Expected Output

Was this helpful?

  1. Examples

Touch to Identify

An example of how to use the REST API with a simple script that identifies devices by touch.

Last updated 1 year ago

Was this helpful?

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 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 , 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
pip install --upgrade disruptive

The following modules are required by the example code and must be installed.

npm install eventsource@2.0.2
npm install jsonwebtoken@9.0.1
npm install axios@1.4.0

Add the following environment variables as they will be used to authenticate the API.

export DT_SERVICE_ACCOUNT_KEY_ID=<YOUR_SERVICE_ACCOUNT_KEY_ID>
export DT_SERVICE_ACCOUNT_SECRET=<YOUR_SERVICE_ACCOUNT_SECRET>
export DT_SERVICE_ACCOUNT_EMAIL=<YOUR_SERVICE_ACCOUNT_EMAIL>
export DT_PROJECT_ID=<YOUR_PROJECT_ID>

Source

The following code snippet implements the touch-to-identify listening loop.

import os
import json

import 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' not in 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 os

import 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
const EventSource = require("eventsource") // npm install eventsource@1.0.7
const jwt = require('jsonwebtoken')        // npm install jsonwebtoken@8.5.1
const axios = require('axios').default     // npm install axios@0.21.1

// Service Account credentials
const serviceAccountKeyID  = process.env.DT_SERVICE_ACCOUNT_KEY_ID
const serviceAccountSecret = process.env.DT_SERVICE_ACCOUNT_SECRET
const serviceAccountEmail  = process.env.DT_SERVICE_ACCOUNT_EMAIL

// Construct API URL
const projectID = process.env.DT_PROJECT_ID
const apiBase = 'https://api.d21s.com/v2/'
const devicesStreamUrl = apiBase + `projects/${projectID}/devices:stream`

async function main() {

    let retryCount = 0
    let stream
    setupStream()

    async function setupStream() {
        // 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.
        const accessToken = await getAccessToken(
            serviceAccountKeyID, 
            serviceAccountEmail, 
            serviceAccountSecret,
        )
        
        // Add query parameters to the URL
        let 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 messages
        console.log('Waiting for touch event...')
        stream = new EventSource(url)
        stream.onmessage = handleStreamMessage
    }
    
    async function handleStreamMessage(message) {
        // Parse the payload as JSON
        const data = JSON.parse(message.data)
        if (!data || !data.result) {
            return
        }

        // Parse the event object
        const event = data.result.event

        // Close stream as we've found a device
        stream.close()

        // Send GET request to fetch device information.
        const response = await axios({
            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/oauth2
async function getAccessToken(keyID, email, secret) {
    // Construct the JWT header
    let jwtHeaders = {
        'alg': 'HS256',
        'kid': keyID,
    }
    
    // Construct the JWT payload
    let 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 secret
    const jwtEncoded = jwt.sign(
        jwtPayload,
        secret,
        {
            header: jwtHeaders,
            algorithm: 'HS256',
        },
    )

    // Prepare POST request data
    const requestObject = {
        'assertion': jwtEncoded,
        'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    }

    // Converts the requestObject to a Form URL-Encoded string
    const requestData = Object.keys(requestObject).map(function(key) {
        return encodeURIComponent(key)+'='+encodeURIComponent(requestObject[key])
    }).join('&')
    
    // Exchange JWT for access token
    const accessTokenResponse = await axios({
        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 request
    return accessTokenResponse.data.access_token
}

Expected Output

Once a touch event has been received, the device information is printed and stream terminated.

Waiting for touch event...

Touch event received:
{
    "name": "projects/c0md3mm0c7bet3vico8g/devices/emuc0uc989qdqebrvv29so0",
    "type": "touch",
    "labels": {
        "name": "my-favorite-sensor",
        "virtual-sensor": ""
    },
    "reported": {
        "networkStatus": {
            "signalStrength": 99,
            "rssi": 0,
            "updateTime": "2021-03-03T17:21:53.080314Z",
            "cloudConnectors": [
                {
                    "id": "emulated-ccon",
                    "signalStrength": 99,
                    "rssi": 0
                }
            ],
            "transmissionMode": "LOW_POWER_STANDARD_MODE"
        },
        "batteryStatus": null,
        "touch": {
            "updateTime": "2021-03-03T17:22:51.059514Z"
        }
    }
}

Terminating stream.

The latest version of our can be installed through pip.

OAuth2 flow
Streaming Events
Python API