Disruptive Technologies Disruptive Developers

Streaming events directly to a client

In this code example, we will create a Python console application that will

  1. List all Devices in the Inventory Project
  2. Stream all events from those Devices

The streaming API should only be used for ad-hoc streams directly to a client, not for reliable server-to-server integration. See When to use Stream API.

Service Account

Before we start, we need to create a Service Account. A Service Account is the recommended way to authenticate client software which will use the API. It can have the same Project access Roles as a human user, but it provides a safe way to rotate secrets, suspending access without deleting it and more.

It is also the only way to use Basic Auth, which is a simple username and password authentication flow which we will use in this code example.

Creating a Service Account

Go to https://studio.disruptive-technologies.com, login with your user credentials and navigate to your Inventory Project.

In the menu on the left, click Service Accounts and in the new view that opens, click Create new.

Name the new Service Account “test-account” and

  1. Change Role in current project to Project user
  2. Create a new Key by clicking Create new under Active keys and save the Key Secret for later as it will not be shown again
  3. Check the box Enable Basic Auth

When you are done, it should look something like the following picture.

Service Account

Keep this tab open for the next steps.

Prerequisites

To try out this code example you need to have Python 3 installed.

Create a new folder for this example open a command line console in this folder, run the following 3 lines:

1
2
3
python3 -m venv venv
source venv/bin/activate
pip3 install requests sseclient-py

Note sseclient-py. The very similarly named sseclient package (without -py suffix) will not work.

  1. setup a standard Python 3 virtual environment (or venv),
  2. activate this environment and finally
  3. install the required packages via the built in Python package manager.

Keep this console window open as we will use it to run the example in a moment.

Code

Using your favorite editor, create a new file called sensor-stream.py with the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import requests
import json
import pprint
import sseclient

# Fill in from the Service Account and Project:
username="SERVICE_ACCOUNT_KEY"  # this is the key
password="SERVICE_ACCOUNT_SECRET" # this is the secret
projectId="PROJECT_ID"

apiUrlBase="https://api.disruptive-technologies.com/v2"
devices_list_url="{}/projects/{}/devices".format(apiUrlBase,projectId)
devices_stream_url="{}/projects/{}/devices:stream".format(apiUrlBase,projectId)

# Get list of Devices in Project via API
device_listing = requests.get(devices_list_url, auth=(username,password))

# Print list of Devices
devices = device_listing.json()['devices']
print("The Inventory Project contains {} Device(s):".format(len(devices)))
for v in devices:
  print(v['name'])
print()

# Listen to all events from all Devices in Project via API
print("Listening for events... (press CTRL-C to abort)")
response = requests.get(devices_stream_url, auth=(username,password),headers={'accept':'text/event-stream'}, stream=True)
client = sseclient.SSEClient(response)
for event in client.events():
    pprint.pprint(json.loads(event.data))

Next, open up the Service Account tab in Studio and replace

  1. SERVICE_ACCOUNT_KEY with the KEY ID
  2. SERVICE_ACCOUNT_SECRET with the Key Secret you saved when you created the Key
  3. PROJECT_ID with the part of the URL in the browser between /projects/ and /serviceaccounts/..., e.g. b8rsrqnh2nqg00c0s9bg

Using the console you used to setup the development environment, run:

python3 sensor-stream.py

Press the Sensor and you should see the raw JSON streaming in to the console output.

Example Output

The Inventory Project contains 1 Device(s):
projects/b9pn94m38fng0088gjm0/devices/b7ktsv57rihma4b9dh70

Listening for events... (press CTRL-C to abort)
{'result': {'event': {'data': {'@type': 'type.googleapis.com/dt.cloud.v2beta1.TouchEvent',
                               'touch': {'updateTime': '2018-02-05T16:09:53.280117570Z'}},
                      'eventId': 'b9s83kfh3u9st9sm2g70',
                      'eventType': 'touch',
                      'targetName': 'projects/b9pn94m38fng0088gjm0/devices/b7ktsv57rihma4b9dh70',
                      'timestamp': '2018-02-05T16:09:53.280117570Z'}}}
{'result': {'event': {'data': {'@type': 'type.googleapis.com/dt.cloud.v2beta1.NetworkStatusEvent',
                               'networkStatus': {'cloudConnectors': [{'id': 'b7nkg28uvn3g0002g78g',
                                                                      'signalStrength': 52}],
                                                 'signalStrength': 52,
                                                 'transmissionMode': 'LOW_POWER_STANDARD_MODE',
                                                 'updateTime': '2018-02-05T16:09:53.280117570Z'}},
                      'eventId': 'b9s83kja2np000eopepg',
                      'eventType': 'networkStatus',
                      'targetName': 'projects/b9pn94m38fng0088gjm0/devices/b7ktsv57rihma4b9dh70',
                      'timestamp': '2018-02-05T16:09:53.280117570Z'}}}