Lightelligence Portal

Getting Started

The OSRAM LIGHTELLIGENCE® (OLT) API provides a set of different building blocks to allow you to create applications for the OLT platform. By using the platform, you don't have to reinvent the wheel and can focus on your application, instead of the technical details required to connect various IOT-devices.

In this guide you will learn how to:

  • Register a user and acquire an access token for the OLT-API
  • Request the creation of a new tenant for yourself or becoming a member of an already existing tenant
  • Create device types and devices
  • Update the device state via the MQTT-client mosquitto
  • Access the device state
  • Report state to and get state from time series service
  • Get aggregated data from timeseries service
  • Register attributes for devices and access them from the API
  • Querying devices with filters
  • Define more complex schema data for your devices
  • Send actions over the cloud to a device
  • Establish a streaming connection

Getting a Token

In order to use the OSRAM LIGHTELLIGENCE® API your first aim is to get a valid access token for the OLT platform. This requires you to register and activate your account so that you can access the portal. Just register on our portal, create a tenant or get assigned to a tenant, access the developer section and get your access token there.

Open the URL https://portal.lightelligence.io in your browser and click register, fill out the registration form and create a new account. You should receive an email with a link to activate your account. Enter the portal by logging in to your account.

You can take a look at your profile when clicking the icon on the left of the options button in the upper right corner. Here you can see your LIGHTELLIGENCE-ID, which is your user ID. This ID is important if you work as a team.

Tenants

In order to create devices, your user must be assigned to a tenant. You can think of a tenant as a corporation. Every corporation has an owner and a variable number of members. It is important to note that devices are registered to tenants and users can only access them if they are members of that tenant. There are two ways to become a member of a tenant:

  • Requesting your own tenant to be created
  • Getting assigned by the owner to an already existing tenant

Request your own Tenant

In order create a tenant, you need to get in touch with our engagement manager Jewgeni Horn at J.Horn@osram.com, who will make that creation happen and assign your first user(s) to the tenant. You should include who you and the other users which need to be part of that tenant are. You will be able to assign other users yourself too.

Assigning a User to a Tenant

In order to assign an existing tenant to a user you have to be owner of the tenant. Only owners can assign or unassign users from a tenant.

If you created a tenant you are already assigned to it, this way you don't need to execute this step for the owner user.

The API endpoint is /tenants/{tenantId}/users/{userId}. Just replace the placeholders with the userId you want to assign and your tenantId.

curl -X PUT \
  https://api.lightelligence.io/v1/tenants/{tenantId}/users/{userId} \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json'
var token = '{TOKEN}';
var tenantId = '{tenantId}';
var userId = '{userId}';

var apiUrl = 'https://api.lightelligence.io/v1/tenants/' + tenantId + '/users/' + userId;

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var options = {
  method: 'PUT',
  cache: 'no-cache',
  headers: headers
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

You should receive a http response with the code 204 No Content

Log in to your tenant

Every access token is only valid for one tenant or the IDP. As such if you want to access the tenant, you will have to get a token for that tenant.

To refresh your access token go to https://portal.lightelligence.io logout and login into your account again. When logging in you will be presented a tenant selection screen. You can grab your new token from the developer section.

List your Tenants

To list your currently assigned tenants make a GET request to the endpoint v1/users/{userId}/tenants to access the tenants you are assigned to. Your userId is available in the developer section of the OLT-Portal. Alternatively you can decode your access token with a jwt library in your code and take the sub property, which is your userId, from the decoded data section. Currently only one tenant per user is allowed.

curl -X GET \
  https://api.lightelligence.io/v1/users/{userId}/tenants \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json'
var token = '{TOKEN}';
var userId = '{userId}';
var apiUrl = 'https://api.lightelligence.io/v1/users/' + userId + '/tenants';

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var options = {
  method: 'GET',
  headers: headers,
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

The response should be similar to this:

{
  "meta": {
    "page": 0,
    "pageSize": 10
  },
  "data": [
    {
      "id": "546acca5-796c-4d48-9873-cd5ae261098b",
      "name": "My Corporation",
      "role": "owner"
    }
  ]
}

The Osram Lightelligence API

You can take a look at the current version of the API by opening the following link in your browser: https://api.lightelligence.io/v1/api-collection/. There you can find a swagger interface with descriptions of all available REST endpoints with examples of how to use them.

Create a Device Type

Before you can register a device, it is important to create a device type. This device type describes the shape of a device and what you can do with it. You have to call the /device-types endpoint to register a new device type. It is a POST request that expects a JSON as body. Besides some metadata like name, manufacturer, model and description, the interesting part is schema. It's a JSON schema that describes the capabilities of your device. Both are a custom list of property-names and their type. To understand JSON schema this online book is an excellent choice.

The following curl command creates a device named "OSRAM Bulb" with the configuration properties brightness and hue. These two describe the state of your device. brightness is just a number and hue is an object describing the red, green and blue part of the current hue. In general, a configuration is readable and writable.

For now, leave the attributes empty. They will be revisited in a later section.

curl -X POST \
  https://api.lightelligence.io/v1/device-types \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "OSRAM Bulb",
  "manufacturer": "OSRAM",
  "model": "V1",
  "description": "WiFi-enabled lightbulb",
  "schema": {
    "configuration": {
      "brightness": {
        "type": "number"
      },
      "hue": {
          "type": "object",
          "properties": {
            "r": { "type": "number" },
            "g": { "type": "number" },
            "b": { "type": "number" }
          }
      }
    },
    "attributes": {}
  }
}'
var token = '{TOKEN}';

var apiUrl = 'https://api.lightelligence.io/v1/device-types';

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var body = {
  'name': 'OSRAM Bulb',
  'manufacturer': 'OSRAM',
  'model': 'V1',
  'description': 'WiFi-enabled lightbulb',
  'schema': {
    'configuration': {
      'brightness': {
        'type': 'number'
      },
      'hue': {
        'type': 'object',
        'properties': {
          'r': { 'type': 'number' },
          'g': { 'type': 'number' },
          'b': { 'type': 'number' }
        }
      }
    },
    'attributes': {}
  }
}

var options = {
  method: 'POST',
  headers: headers,
  body: JSON.stringify(body)
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

A successful response contains the ID of the newly created device type.

{
  "data": {
    "id": "f5db2e0a-0347-4b75-8e7f-657d7be99b58",
    "name": "OSRAM Bulb",
    "manufacturer": "OSRAM",
    "model": "V1",
    "description": "WiFi-enabled lightbulb",
    "schema": {
      "attributes": {},
      "configuration": {
        "hue": {
          "type": "object",
          "properties": {
            "r": { "type": "number" },
            "g": { "type": "number" },
            "b": { "type": "number" }
          }
        },
        "brightness": {
          "type": "number"
        },
        "additionalProperties": false
      }
    }
  }
}

Create a Device

After having created a device type, you can now create a device. Creating a device means creating the digital twin of a real device. A digital twin is an entity that represents the real device in the cloud. Besides meta information, like name and description, you have to provide the type, tags and the initial device configuration. The deviceTypeId must match the id from the last section and the initial configuration is validated against the schema of that type. Tags are useful to query and filter devices, which is explained in a later section.

curl -X POST \
  https://api.lightelligence.io/v1/devices \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "info": {
    "name": "Bulb 1",
    "deviceTypeId": "{deviceTypeId}",
    "description": "The bulb right here",
    "installationTimestamp": "2018-06-05T08:23:10.370Z",
    "tags": [
      "light"
    ]
  },
  "configuration": {
      "brightness": 50,
      "hue": {
          "r": 255,
          "g": 0,
          "b": 0
      }
  }
}'
var token = '{TOKEN}';
var deviceTypeId = '{deviceTypeId}'

var apiUrl = 'https://api.lightelligence.io/v1/devices';

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var body = {
  'info': {
    'name': 'Bulb 1',
    'deviceTypeId': deviceTypeId,
    'description': 'The bulb right here',
    'installationTimestamp': '2018-06-05T08:23:10.370Z',
    'tags': [
      'light'
    ]
  },
  'configuration': {
      'brightness': 50,
      'hue': {
          'r': 255,
          'g': 0,
          'b': 0
      }
  }
}

var options = {
  method: 'POST',
  headers: headers,
  body: JSON.stringify(body)
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

You should get the device ID as part of the JSON response.

{
  "data": {
    "id": "a939b740-011d-4181-8bb0-0f292a0a9e9b",
    "info": {
      "name": "Bulb 1",
      "description": "The bulb right here",
      "deviceTypeId": "f5db2e0a-0347-4b75-8e7f-657d7be99b58",
      "installationTimestamp": "2018-06-05T08:23:10.370Z",
      "tags": [
        "light"
      ]
    },
    "configuration": {
      "brightness": 50
    }
  }
}

Create a Device Certificate

In the next step, you change the perspective. Now you take the view of the device.

To communicate with the OSRAM LIGHTELLIGENCE® platform, your device needs a SSL/TLS client certificate. During the TLS handshake between your device and the platform, the platform will use this certificate to identify and authenticate your device. Therefore it is mandatory that every device has its own, unique client certificate.

The following example is based on the openssl command line utility, to create a self-signed device certificate for a particular device. Of course, you can also use or create your own certificate authority (CA) and have all device certificates issued by that CA.

Create a Unique Private/Private Key Pair for Your Device Certificate:

openssl ecparam -out device_key.pem -name prime256v1 -genkey

Create the Device Certificate

openssl req -new -key device_key.pem -x509 -days 365 -out device_cert.pem -subj '/O=My-Tenant/CN=My-Device'

Use the optional -subj parameter to set the certificate's subject name. To ensure that you can easily associate a certificate with a particular device, you could provide the following values:

  • "Organization Name" (O): use your tenant's name or id
  • "Common Name" (CN): use your device's name or id

That's it! You have two files now:

  • device_key.pem: the private key associated with the certificate. Do not send to or use it anywhere else than on the particular device where this certificate was created for.
  • device_cert.pem: the public key and the certificate. Use this file to register it to the OLT platform (as described in the next step)

Verify the Device Certificate

The command

openssl x509 -in device_cert.pem -noout -text

should now provide you with the contents of your new device certificate. The output looks like this:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 14092600106503687288 (0xc392f9218dc8cc78)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: O=My-Tenant, CN=My-Device
        Validity
            Not Before: Jun 13 16:59:36 2018 GMT
            Not After : Jun 13 16:59:36 2019 GMT
        Subject: O=My-Tenant, CN=My-Device
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:50:39:32:a5:c6:e8:4b:6c:95:e9:b2:9d:bd:ca:
                    6a:b9:57:48:c2:7b:2e:39:2f:d8:80:6a:38:5b:fa:
                    c0:98:15:b3:69:fa:91:9e:55:c9:b1:aa:ea:be:ef:
                    5b:bd:04:c6:11:13:1a:14:0d:b4:ba:f8:b3:07:45:
                    52:c8:df:11:fd
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                BD:70:1A:C9:E6:0C:99:D2:9D:4F:F5:EB:C2:61:33:02:E9:1E:2E:D3
            X509v3 Authority Key Identifier:
                keyid:BD:70:1A:C9:E6:0C:99:D2:9D:4F:F5:EB:C2:61:33:02:E9:1E:2E:D3

            X509v3 Basic Constraints:
                CA:TRUE
    Signature Algorithm: ecdsa-with-SHA256
         30:44:02:20:6f:f7:80:83:55:f8:4b:7f:ab:9d:27:68:f0:cd:
         02:e7:41:50:35:87:d0:dc:a2:d8:09:3a:0a:a0:6f:ca:3f:0b:
         02:20:5c:0a:03:68:68:5f:b8:a7:5e:ad:d0:bf:e9:27:12:b8:
         91:4d:c4:87:27:31:4b:d7:37:6c:d8:51:3d:05:50:a6

Register Device Certificate

The curl command below finally registers the new device certificate on the OLT platform. When copying and pasting the certificate, make sure to replace newlines with the newline escape sequence \n before executing the command or copy the output of:

sed 's/$/\\n/' device_cert.pem | tr -d '\n'

into the curl command:

curl -X POST \
  https://api.lightelligence.io/v1/devices/{deviceId}/certificates \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "cert": "-----BEGIN CERTIFICATE-----\nMIIEujCCAqICAQEwDQYJKoZIhvcNAQELBQAwNjESMBAGA1UEAwwJbG9jYWxob3N0\nMSAwHgYDVQQKDBdDbGllbnQgQ2VydGlmaWNhdGUgRGVtbzAeFw0xODA2MDcwOTI5\nMzBaFw0xOTA2MDcwOTI5MzBaMBAxDjAMBgNVBAMMBUFsaWNlMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEAxB2gmmAL6HXKDlUYjyiTJUw5hYRoC5nQ42V6\n/wyWDiMhEtFQ3Jj8Okps6Tn67Oo1uSuBP93nTev2XJAXc68NHh+ZSFce+0frXl1B\nRh4vOHEIWT+8lNF2iAsCviL0QV7zyx4vmFVCmqyM/6/C9ulZ6zIXP0s6E7iV3+Uq\n9+7YULBG5TIjeCdNtXsMorlRh81sL1bKRmtdyWxOYcUouXqvIp6ZUuMacmPBZEhc\n1qLqiQ1Wy4t3Y43e+Helx5z5D0fYJgXaTGhYS8qI3l7+1xtULvYRwESljQyKR4LX\nf9utmyXndOxE8vgX6DNv02PfolTzqt/FneEmINQI5zkJSg0DTQ0Pd4pFNUlzxKrt\nw3ug+GVwKEia9oWK5PngQ6Y8HXzyOuQ2PNkBMt9MHG5ZbTHV5GagvESfG5UNMJaT\nsS4GSi31YhqXVCUnQKNnzniLXkIq0D9FQaFvFAXasppZfPMnSdna38c0rLP3bC8u\n5ZV4E1tMhU6/FN5UBRdQ5k4g9dgeA1X/eIll+LLorz83qOQ0AsBJQTKo+JjjMpgP\nEkk8kaP47HB3BFbXjwd9IWXDhN8zH+5krmImdrkAPRg5Abv0MaO5F5SjxHHOIp4D\neatuugTZoMsmVq5zlQxHdH0M7WylgvKpaYxony+HoeQRDxN4bjzuQQAcUeqMj9KW\nRD+gMIsCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAhVqsoIRjylVdNF3ueP6Njdbv\nXQMy4Z31puN0uAApWD4v0RQ9UB2Ib/E66aTbrJWf4Sz8s1nGoKY0HfWuJLBDqBVC\nE9N+mllQ5O/TjPpOWTU0IvE3Y7Hz9zyhPsun/ZlGX0K+w/YfWQbbdTb+yc+nGB6A\nWHwPbrPgH3EWaQ5XgxByFc3XMMVjm81aN/VV1L8SA1SUooJhpXAoC+pWjUYOddJV\nq9mspv0PQ2sfHwIqmiohdeggLdEnj0WKBBrt9DlTzDcZdE0GmuExJcedf0F2fQFo\nKjoqTpOgqMYtH+zfa9d6UX8yqw1OLE5l/LFJfQ6pOLm8MF5eVQNLoKJthOQHpAoF\nC1VFExrrlO7F/GeIFb+Kq/ixyyk5pii8ehq3JXGZazY4xG2NVWb0zgs0x4HEFfHO\nYiDmX6K9v7P6y4ZSmJ9DgZP4XttxJhXBYleGxxBs3th2pdULygU1qaKQVgzL4qyw\n6ezgmdD7AoaSMoIkuVaWVggezxWo7W/ZmY7qlpxnP5n5ShyEDvlh9+p6LhjPX8xt\nvWsKkDy7onj+jDuZEgM39OshGID9lmfRsvFLSbrnVS0zIZY0VcM6ZWiAczxranHl\nITc9WuypHGPS6il5tLBv8ljWBtrn7/sNbS5BATWNNV8AgK5F+d9WznQgSc1tTtoe\ntREEnYOu1t7CCkFk5Rc=\n-----END CERTIFICATE-----\n",
  "status": "valid"
}'
var token = '{TOKEN}';
var cert = '{CERT}'; // certificate with escaped newline characters
var deviceId = '{deviceId}';

var apiUrl = 'https://api.lightelligence.io/v1/devices/' + deviceId + '/certificates';

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var body = {
  'cert': cert,
  'status': 'valid'
};

var options = {
  method: 'POST',
  cache: 'no-cache',
  headers: headers,
  body:JSON.stringify(body)
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

A successful response looks like this:

{
  "id": "8b7860fc-f061-4f4e-b79e-bee52f91dc49",
  "cert": "-----BEGIN CERTIFICATE-----\nMIIEujCCAqICAQEwDQYJKoZIhvcNAQELBQAwNjESMBAGA1UEAwwJbG9jYWxob3N0\nMSAwHgYDVQQKDBdDbGllbnQgQ2VydGlmaWNhdGUgRGVtbzAeFw0xODA2MDcwOTI5\nMzBaFw0xOTA2MDcwOTI5MzBaMBAxDjAMBgNVBAMMBUFsaWNlMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEAxB2gmmAL6HXKDlUYjyiTJUw5hYRoC5nQ42V6\n/wyWDiMhEtFQ3Jj8Okps6Tn67Oo1uSuBP93nTev2XJAXc68NHh+ZSFce+0frXl1B\nRh4vOHEIWT+8lNF2iAsCviL0QV7zyx4vmFVCmqyM/6/C9ulZ6zIXP0s6E7iV3+Uq\n9+7YULBG5TIjeCdNtXsMorlRh81sL1bKRmtdyWxOYcUouXqvIp6ZUuMacmPBZEhc\n1qLqiQ1Wy4t3Y43e+Helx5z5D0fYJgXaTGhYS8qI3l7+1xtULvYRwESljQyKR4LX\nf9utmyXndOxE8vgX6DNv02PfolTzqt/FneEmINQI5zkJSg0DTQ0Pd4pFNUlzxKrt\nw3ug+GVwKEia9oWK5PngQ6Y8HXzyOuQ2PNkBMt9MHG5ZbTHV5GagvESfG5UNMJaT\nsS4GSi31YhqXVCUnQKNnzniLXkIq0D9FQaFvFAXasppZfPMnSdna38c0rLP3bC8u\n5ZV4E1tMhU6/FN5UBRdQ5k4g9dgeA1X/eIll+LLorz83qOQ0AsBJQTKo+JjjMpgP\nEkk8kaP47HB3BFbXjwd9IWXDhN8zH+5krmImdrkAPRg5Abv0MaO5F5SjxHHOIp4D\neatuugTZoMsmVq5zlQxHdH0M7WylgvKpaYxony+HoeQRDxN4bjzuQQAcUeqMj9KW\nRD+gMIsCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAhVqsoIRjylVdNF3ueP6Njdbv\nXQMy4Z31puN0uAApWD4v0RQ9UB2Ib/E66aTbrJWf4Sz8s1nGoKY0HfWuJLBDqBVC\nE9N+mllQ5O/TjPpOWTU0IvE3Y7Hz9zyhPsun/ZlGX0K+w/YfWQbbdTb+yc+nGB6A\nWHwPbrPgH3EWaQ5XgxByFc3XMMVjm81aN/VV1L8SA1SUooJhpXAoC+pWjUYOddJV\nq9mspv0PQ2sfHwIqmiohdeggLdEnj0WKBBrt9DlTzDcZdE0GmuExJcedf0F2fQFo\nKjoqTpOgqMYtH+zfa9d6UX8yqw1OLE5l/LFJfQ6pOLm8MF5eVQNLoKJthOQHpAoF\nC1VFExrrlO7F/GeIFb+Kq/ixyyk5pii8ehq3JXGZazY4xG2NVWb0zgs0x4HEFfHO\nYiDmX6K9v7P6y4ZSmJ9DgZP4XttxJhXBYleGxxBs3th2pdULygU1qaKQVgzL4qyw\n6ezgmdD7AoaSMoIkuVaWVggezxWo7W/ZmY7qlpxnP5n5ShyEDvlh9+p6LhjPX8xt\nvWsKkDy7onj+jDuZEgM39OshGID9lmfRsvFLSbrnVS0zIZY0VcM6ZWiAczxranHl\nITc9WuypHGPS6il5tLBv8ljWBtrn7/sNbS5BATWNNV8AgK5F+d9WznQgSc1tTtoe\ntREEnYOu1t7CCkFk5Rc=\n-----END CERTIFICATE-----\n",
  "status": "valid"
}

Talking to the Cloud

The generated device is now able to talk to OLT platform. The protocol is MQTT (Message Queue Telemetry Transport), a publish-subscribe-based messaging protocol especially suited for IoT devices, where bandwidth and storage space are limited. A common client for MQTT is Mosquitto which you use in this section to establish the connection and send the device state to the cloud.

To install mosquitto follow the guidelines for your operation system on the mosquitto website.

Push Updates from the Device to the Server via Mosquitto

There is one last step before you can finally use mosquitto. You need the public CA certificate used by the OLT platform for the MQTT device service. Just copy and paste the certificate below into a file named olt_ca.pem and you are ready to go.

-----BEGIN CERTIFICATE-----
MIICBzCCAaygAwIBAgIBADAKBggqhkjOPQQDAjBcMQswCQYDVQQGEwJERTEOMAwG
A1UEChMFT1NSQU0xDDAKBgNVBAsTA09MVDEvMC0GA1UEAxMmT1NSQU0gT0xUIERl
dmljZVNlcnZpY2VzIFRydXN0QW5jaG9yIDEwIBcNMTgwNjEyMTU1NTMwWhgPMjA1
ODA2MTIxNTU1MzBaMFwxCzAJBgNVBAYTAkRFMQ4wDAYDVQQKEwVPU1JBTTEMMAoG
A1UECxMDT0xUMS8wLQYDVQQDEyZPU1JBTSBPTFQgRGV2aWNlU2VydmljZXMgVHJ1
c3RBbmNob3IgMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIRHefdjW8eKPEpi
RV88sqk/7nqOIDdg4v2KcIsX8LQD94YGkDEDO4Alg3EdtibTXMtztbSiRMmy/BeB
7Fmbr+KjXTBbMB0GA1UdDgQWBBQmEJ8uur+FfHaFxDYw1oeYNu1M6TAfBgNVHSME
GDAWgBQmEJ8uur+FfHaFxDYw1oeYNu1M6TAMBgNVHRMEBTADAQH/MAsGA1UdDwQE
AwIBBjAKBggqhkjOPQQDAgNJADBGAiEA1dAeBWcIDUyOzuQSzhO0cajg3mZfiHp/
NwryIKRR9fgCIQDKqKmKv1STjPEePu4NL2YEqsVauaVl4CVQIYVjEwN3cw==
-----END CERTIFICATE-----

Now you can push updates from your device to the server via the mosquitto_pub command. Make sure to use the previously created device_key.pem and device_cert.pem in this command.

  • mqtt.lightelligence.io is the address of the OLT platform you want to connect to
  • mqttv311 is the protocol to be used
  • cafile is the certificate of the Certificate Authority that has issued the TLS certificate of the OLT platform's MQTT service
  • { "type": "configuration", "value": { "brightness": 300 } } is the state change that you want to publish for your device. This is validated against the Schema that you specified for the device type.
mosquitto_pub -h mqtt.lightelligence.io \
-p 8883 --cert device_cert.pem --key device_key.pem \
-d -t data-ingest \
-m '{ "type": "configuration", "value": { "brightness": 300 } }' \
-V mqttv311 --cafile olt_ca.pem

This command sets the brightness value to 300, your output should be similar to the one below:

Client mosqpub/9566-host sending CONNECT
Client mosqpub/9566-host received CONNACK
Client mosqpub/9566-host sending PUBLISH (d0, q0, r0, m1, 'data-ingest', ... (58 bytes))
Client mosqpub/9566-host sending DISCONNECT

Accessing the Current Device State

It is time to change the perspective again. The following sections are taken from the view of the application. After pushing the updated state from the device, you can access it from the /devices/{deviceId}/state endpoint.

curl -X GET \
  https://api.lightelligence.io/v1/devices/{deviceId}/state \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json'
var token = '{TOKEN}';
var deviceId = '{deviceId}';

var apiUrl = 'https://api.lightelligence.io/v1/devices/' + deviceId + '/state';

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var options = {
  method: 'GET',
  cache: 'no-cache',
  headers: headers,
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

As you can see in the response, the brightness has been successfully updated by the device.

{
    "data": {
        "configuration": {
            "brightness": 350
        },
        "attributes": {},
        "lastSeen": "2018-08-28T08:17:50.641Z"
    }
}

Reporting Data to Timeseries

Accessing the current state is good so far. But fetching state changes over time enables even more possibilities. In order to access those changes you need to turn on reporting explicitly for the properties you want to include. The property reportingRules is part of the device type, which means you have to update the current device type to enable this.

A reporting rule consists of two properties, path and reportTo. The path is a JSON path. It begins with a $ and must be a valid path to a value in your device type schema. A JSON path points to a specific value inside of a JSON document.

For example, $.person.name points to "Alice" and $.person.likes[0] points to "apples" in this JSON document:

{
  "person" : {
    "name" : "Alice",
    "likes" : ["apples", "oranges"]
  }
}

It is important that this value is scalar. Only values of type number, boolean or string can be reported to timeseries. JSON paths pointing to objects or arrays are not allowed. reportTo can only be ["timeseries"] at this point, further options will follow.

The patch request looks like this:

curl -X PATCH \
  https://api.lightelligence.io/v1/device-types/{deviceTypeId} \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "reportingRules": [
      {
        "path": "$.configuration.brightness",
        "reportTo": [
          "timeseries"
        ]
      }
    ]
}'
var token = '{TOKEN}';
var deviceTypeId = '{deviceTypeId}';

var apiUrl = 'https://api.lightelligence.io/v1/device-types/' + deviceTypeid;

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var body = {
  'reportingRules': [
    {
      'path': '$.configuration.brightness',
      'reportTo': [
        'timeseries'
      ]
    }
  ]
};

var options = {
  method: 'PATCH',
  cache: 'no-cache',
  headers: headers,
  body:JSON.stringify(body)
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

Getting Data out of Timeseries

After turning on reporting to timeseries and pushing more state changes from the device to the OLT platform, it is possible to access those values by making a GET request to the /v1/devices/{deviceId}/last-timeseries endpoint. You need to provide the query parameter path to make such a request and it must be URL encoded, as in the following curl example.

  • path should be a valid JSON path that is registered for the device type in reportingRules like $.configuration.brightness.
curl -X GET \
  "https://api.lightelligence.io/v1/devices/{deviceId}/last-timeseries?path=%24.configuration.brightness" \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json'
var token = '{TOKEN}';
var deviceId = '{deviceId}';
var path = encodeURIComponent('$.configuration.brightness');

var apiUrl = 'https://api.lightelligence.io/v1/devices/' + deviceId 
    + '/last-timeseries?path=' + path;

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
}

var options = {
  method: 'GET',
  cache: 'no-cache',
  headers: headers,
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json))

The result includes data for the last hour. If number of entries in the last hour exceed 1000, the top 1000 entries are returned sorted by time in descending order.

Timeseries Dumps

In addition to access timeseries values via the /v1/devices/{deviceId}/last-timeseries endpoint you have also the possibility to generate timeseries dumps by making a POST request to the /v1/devices/{deviceId}/timeseries-dump endpoint. This allows to reaching further into timeseries history than with the last-timeseries endpoint. Moreover, this endpoint supports getting more specific data, e.g. filtered by path, startTime and endTime, compared to the /v1/devices/{deviceId}/last-timeseries endpoint.

The general workflow looks like:

  1. Request a dump by making a POST request to the /v1/devices/{deviceId}/timeseries-dump endpoint.
  2. The reponse contains a download url where you can download the generated dump once it is ready. Make a GET request to the provided download url and save the dump.

The endpoint POST /v1/devices/{deviceId}/last-timeseries expects at least two parameters:

  • deviceId: The ID of the device for which you want to generated the dump
  • path: Path matching to a path defined in the reporting rules of the device's type. (e.g. $.attributes.brightness).
curl -XPOST \
  https://api.lightelligence.io/v1/devices/{deviceId}/timeseries-dump \
  -H "Authorization: Bearer ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -H 'Cache-Control: no-cache', \
  -d '{"path": "$.attributes.temperature"}'
var token = '{TOKEN}';
var deviceId = '{deviceId}';

var apiUrl = 'https://api.lightelligence.io/v1/devices/' + deviceId
    + '/timeseries-dump';

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
}

var data = {
  path: '$.attributes.temperature'
};

var options = {
  method: 'POST',
  cache: 'no-cache',
  headers: headers,
  body: JSON.stringify(data)
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json))

The provided download URL is of the following form /v1/devices/{deviceId}/timeseries-dump/{dumpId}. You need to provide two path parameters:

  • deviceId: The devices UUID
  • dumpId: The UUID of the dump
curl http://api.lightelligence.io/v1/devices/{deviceId}/timeseries-dump/{dumpId} \
  -H "Authorization: Bearer ${TOKEN}"
var token = '{TOKEN}';
var deviceId = '{deviceId}';
var dumpId = '{dumpId}';

var apiUrl = 'https://api.lightelligence.io/v1/devices/' + deviceId
    + '/timeseries-dump/' + dumpId;

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
}

var options = {
  method: 'GET',
  cache: 'no-cache',
  headers: headers
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json))

Get aggregated Data out of Timeseries

Sometimes it is useful to get aggregated data for a specific timespan. In this case, you only get one value from the API. This value is an aggregation of all values of this timespan. The aggregation query parameter specifies the aggregation type.

The different aggregation types for the timespan are:

  • min minimum value
  • max maximum value
  • mean average value
  • sum sum of all values
  • count count of all values
  • first first value
  • last last value
  • diff calculates the difference of the last and first value last - first

In contrast to the timeseries example from the last section, you have to provide a startTime and an endTime. Here we aggregate the $.configuration.brightness values of one hour between 2015-08-04T19:05:30Z and 2015-08-04T20:05:30Z with the function mean:

curl -X GET \
  "https://api.lightelligence.io/v1/devices/{deviceId}/aggregated-timeseries?startTime=2015-08-04T19%3A05%3A30Z&endTime=2015-08-04T20%3A05%3A30Z&path=%24.configuration.brightness&aggregation=mean" \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json'
var token = '{TOKEN}';
var deviceId = '{deviceId}';
var aggregation = 'mean';
var path = encodeURIComponent('$.configuration.brightness');
var startTime = encodeURIComponent('2015-08-04T19:05:30Z');
var endTime = encodeURIComponent('2015-08-04T20:05:30Z');

var apiUrl = 'https://api.lightelligence.io/v1/devices/'
    + deviceId + '/aggregated-timeseries?startTime=' + startTime 
    + '&endTime=' + endTime + '&path=' + path + '&aggregation=' + aggregation;

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var options = {
  method: 'GET',
  cache: 'no-cache',
  headers: headers,
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

Attributes

Besides configuration attributes can be defined for your device type. Think about attributes as collected sensor data values at a certain point in time. Like temperature or humidity. Sensor data is read-only and can only be pushed from the device to the cloud.

Add Attributes to Device Types

To add attributes to your device type, you need to make a PATCH-request to update it. In the following example, we will add ambientLight as an attribute to our device type. In contrast to brightness, it is a complex value, an object of three separate values r, g and b. Your new device type is now a light bulb that can report the ambient light value of its environment to the cloud. Your application could, for example, dim the brightness as a response to those values.

curl -X PATCH \
  https://api.lightelligence.io/v1/device-types/{deviceTypeId} \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "schema": {
    "configuration": {
      "brightness": {
        "type": "number"
      },
    },
    "attributes": {
      "ambientLight": {
        "type": "object",
        "properties": {
          "r" : { "type" : "number" },
          "g" : { "type" : "number" },
          "b" : { "type" : "number" }
        }
      }
    }
  }
}'
var token = '{TOKEN}';
var deviceTypeId = '{deviceTypeId}';
var apiUrl = 'https://api.lightelligence.io/v1/device-types/' + deviceTypeid;

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var body = {
  'schema': {
    'configuration': {
      'brightness': {
        'type': 'number'
      },
    },
    'attributes': {
      'ambientLight': {
        'type': 'object',
        'properties': {
          'r' : { 'type' : 'number' },
          'g' : { 'type' : 'number' },
          'b' : { 'type' : 'number' }
        }
      }
    }
  }
};

var options = {
  method: 'PATCH',
  cache: 'no-cache',
  headers: headers,
  body:JSON.stringify(body)
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

You should get the patched device type back; it contains all the things you added in the last sections.

{
  "data": {
    "id": "f5db2e0a-0347-4b75-8e7f-657d7be99b58",
    "name": "Osram Bulb",
    "manufacturer": "Osram",
    "model": "V1",
    "description": "WiFi-enabled lightbulb",
    "reportingRules": [
      {
        "path": "$.configuration.brightness",
        "reportTo": [
          "timeseries"
        ]
      }
    ],
    "schema": {
      "configuration": {
        "brightness": {
          "type": "number"
        },
      },
      "attributes": {
        "ambientLight": {
          "type": "object",
          "properties": {
            "r" : { "type" : "number" },
            "g" : { "type" : "number" },
            "b" : { "type" : "number" }
          }
        }
      }
    }
  }
}

Sending Attributes

Sending attributes from your device gateway works exactly the same way as updating configuration properties. The only difference is the type, which has to be attributes.

This is how you push a new value for ambientLight to the cloud:

mosquitto_pub -h mqtt.lightelligence.io \
  -p 8883 --cert device_cert.pem --key device_key.pem \
  -d -t data-ingest \
  -m '{ "type": "attributes", "value": { "ambientLight": { "r" : 230, "g": 210, "b": 190 } } }' \
  -V mqttv311 --cafile olt_ca.pem

Getting Attributes

Attribute values are accessed in the same way as configuration values. The last value can be accessed via the device state and specific ranges through the timeseries endpoint.

Query and Filter Devices

The devices endpoint lets you access all devices that your user has access to. For example you can filter by tags, a comma separated list of strings, and deviceTypeId like this:

curl -X GET \
  "https://api.lightelligence.io/v1/devices?tags=light&deviceTypeId={deviceTypeId}" \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json'
var token = '{TOKEN}';
var deviceTypeId = '{deviceTypeId}';
var tags = ['light'];

var apiUrl = 'https://api.lightelligence.io/v1/devices?tags=' 
    + tags.join(',') + '&deviceTypeId=' + deviceTypeId;

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var options = {
  method: 'GET',
  cache: 'no-cache',
  headers: headers,
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

Take a look at the swagger documentation for a description of all API endpoints and their parameters.

Complex Schema Data

You have already used two different kinds of schema data types, numbers and objects. JSON schema also allows strings, booleans and arrays. The following command creates a device type that has an array of booleans as an attribute. The array must contain 2 up to 5 items defined by minItems and maxItems. While you cannot report an array to timeseries, your reportingRules can contain a rule to report an item with a specified index. In this case the first array element, a boolean, is reported to timeseries.

curl -X POST \
  https://api.lightelligence.io/v1/device-types \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Switches",
  "manufacturer": "MyManufacturer",
  "model": "V1",
  "description": "Custom Device",
  "schema": {
    "reportingRules": [
      {
        "path": "$.attributes.states[0]",
        "reportTo": [
          "timeseries"
        ]
      }
    ],
    "attributes": {
      "states": {
        "type": "array",
        "items": {
          "minItems": 2,
          "maxItems": 5,
          "type": "boolean"
        }
      }
    }
  }
}'
var token = '{TOKEN}';

var apiUrl = 'https://api.lightelligence.io/v1/device-types';

var headers = {
  'Authorization': 'Bearer ' + token,
  'Cache-Control': 'no-cache',
  'Content-Type': 'application/json'
};

var body = {
  "name": "Switches",
  "manufacturer": "MyManufacturer",
  "model": "V1",
  "description": "Custom Device",
  "schema": {
    "reportingRules": [
      {
        "path": "$.attributes.states[0]",
        "reportTo": [
          "timeseries"
        ]
      }
    ],
    "attributes": {
      "states": {
        "type": "array",
        "items": {
          "minItems": 2,
          "maxItems": 5,
          "type": "boolean"
        }
      }
    }
  }
};

var options = {
  method: 'POST',
  cache: 'no-cache',
  headers: headers,
  body:JSON.stringify(body)
};

fetch(apiUrl, options)
  .then(res => res.json())
  .then(json => console.log(json));

Pushing new values with mosquitto is as easy as:

mosquitto_pub -h mqtt.lightelligence.io \
-p 8883 --cert device_cert.pem --key device_key.pem \
-d -t data-ingest \
-m '{ "type": "attributes", "value": { "states": [true, false, true] } }' \
-V mqttv311 --cafile olt_ca.pem

Talking to a device

Up until this point, we have seen both how to push data generated by a device to the OLT platform and how to retrieve this data. Now we will explore another form of communication: how to send actions over the cloud to a device. A device action is defined as a command that can be executed by a device. Here the device is no longer data producing but the consuming component of the system.

Prerequisite for receiving actions

Before triggering a specific action on a device, this action has to be defined in the device's type. You already know how to create a device type from section 03. To define an action, you add the actions attribute to the schema. This attribute contains a map of action objects which takes the action name as the key and defines the value as a JSON schema describing what can be sent in the action's payload.

The following example Device Type as JSON could be used in the POST request to the /device-types endpoint and creates a device named "OSRAM Bulb" with the actions property brightnessIncrease. This property describes that the device is allowed to receive actions conforming to the given type.

{
    "name": "OSRAM Bulb",
    "manufacturer": "OSRAM",
    "model": "V1",
    "description": "WiFi-enabled lightbulb",
    "schema": {
      "attributes": {},
      "configuration": {
        "brightness": {
          "type": "number"
        }
      },
      "actions": {
          "brightnessIncrease" : {
              "brightness": {
                  "type": "number"
              },
              "description": {
                  "type": "string"
              }
          }
      }
    }
}

Connecting to the MQTT endpoint and subscribing to a topic

Once you have created a device with an actions field in its schema, you can connect your device to the MQTT endpoint (either directly or through a gateway) and listen to the actions being sent to your device. In order to achieve this, you simply have to subscribe to the topic devices/{deviceId}/actions.

As described in section 07, you can use the MQTT client Mosquitto. While any other MQTT client would also work, you can find instructions on how to install this specific one on the mosquitto website.

With this client you can connect to the MQTT endpoint and subscribe to a topic via the mosquitto_sub command. Use the certificates previously created in this command.

  • mqtt.lightelligence.io is the address of the OLT platform you want to connect to
  • mqttv311 is the protocol to be used
  • olt_ca.pem is the certificate of the Certificate Authority that has issued the TLS certificate of the OLT platform's MQTT service
  • device_key.pem and device_cert.pem are the previously created certificates
  • devices/{deviceId}/actions is the topic you want to subscribe to
mosquitto_sub -h mqtt.lightelligence.io \
-p 8883 --cafile olt_ca.pem --cert device_cert.pem --key device_key.pem \
-V "mqttv311" -t 'devices/{deviceId}/actions' -d

Triggering an action on a device

In order to push an action to your now connected and subscribed device, you can send a POST request to the endpoint /devices/{deviceId}/actions. This request contains the action name and its payload in the request body:

curl -X POST \
  https://api.lightelligence.io/v1/devices/{deviceId}/actions \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "action": "brightnessIncrease",
  "payload": {
      "brightness": 500,
      "description": "increase brightness"
  }
}'

If this request complies with the device type and the device is allowed to receive the described actions, you should now see a MQTT message in your device which should look similar to the following:

{
    "actionId": "6acfb2d1-7997-4a7f-b43f-a81a1dddb210",
    "deviceId": "{deviceId}",
    "action": "brightnessIncrease",
    "payload": {
        "brightness": 500,
        "description": "increase brightness"
    },
    "time": "2018-08-04T19:05:14.318570484Z"
}

You have now successfully forwarded an action to your device.

Conclusion

You should now have a good understanding of how to develop applications for the OLT platform. Take a look at the API documentation for further information on the platform features.

Streaming Connections

It is also possible to establish a streaming connection in order to get instant updates about new data or events of your devices. Thus, you can easily keep your application up to date via WebSocket. In order to achieve this, two steps are necessary:

  • Requesting a connection URL via a POST request
  • Establishing the WebSocket connection

Requesting WebSocket connection URL

In order to request a WebSocket connection URL, you have to specify a filter on which updates should be streamed and for which specific devices you want to receive this data. Both type and deviceId are described in an array. The following curl command requests the URL for a streaming connection for two specific devices which forwards attribute, event as well as configuration updates.

curl -X POST \
  https://api.lightelligence.io/v1/devices/streaming-connections \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "filter": {
      "type": [
          "attributeUpdate",
          "eventUpdate",
          "configurationUpdate",
      ],
      "deviceId": [
          "a939b740-011d-4181-8bb0-0f292a0a9e9b",
          "ecef434a-ad1d-41ac-8b3b-2b4b777dbc6e"
      ]
  }
}'

As a response you will get the URL needed in order to establish the connection as well as the validity of this same URL.

{
  "data": {
    "url": "wss://api.lightelligence.io/v1/devices/streaming-connections/bfaa8c93de8042da5cc28dffda6dd37c5767e5db6298ece078ddb74f6cdf8fbb/ws",
    "validUntil": "2018-12-10T08:05:15.830Z"
  }
}

Note that the URL is only valid for 15 seconds. Afterwards, it expires and you will have to request a new URL in case you still wish to establish the connection.

Establish WebSocket connection

Using the URL from the received response, you can now easily establish your WebSocket connection in order to stream the requested updates.

new WebSocket('{URL}').onmessage = function (event) {
 console.log(event.data);
}

Whenever an update which conforms to the filter specified in your POST request, is pushed to LIGHTELLIGENCE, your application will now log this data. You can verify that by pushing data to OLT as described in section 07.

Conclusion

You should now have a good understanding of how to develop applications for the OLT platform. Take a look at the API documentation for further information on the platform features.

This website uses cookies to offer you certain services and to enhance your user experience. By continuing to use our website, you consent to the usage of cookies as described in our Cookie Policy.