Accessing the 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.

Assigning 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

Create your own Tenant and Billing Information

On the entrance page, you have the possibility to create your tenant, which leads you to the pricing

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 (called "Lightelligence-ID" in the developer section of the portal) 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.

Developing Custom Applications

Develop custom applications to access the OLT API endpoints (https://api.lightelligence.io/v1/api-collection) and manage them.

Authenticating to the OLT Platform with OAuth2

To be able to actually use applications, perform two basic steps:

  • Register your applications to the OLT platform.

    By registering your application to the OLT platform, you turn your application into an OAuth2 client authenticating via OpenID Connect.

  • Implement OAuth2 in your application.

Restrictions

For security reasons, custom applications are not allowed to use API endpoints related to tenant management and user management.

For more information, see Troubleshooting Application Management.

Getting Started

Choose an applications type depending on your use case, and off you go:

  • Creating and Implementing Applications with User Interaction

    To retrieve an OAuth2 access token, you can implement an OAuth2 client with or without OAuth2 client secret, depending on the application type:

    • Web application running on a web server (in which the application source code is protected): Implement a confidential OAuth2 client with OAuth2 client secret.
    • User agent application running in a browser (in which the application source code may be viewed), a JavaScript application, for example: Implement a public OAuth2 client without OAuth2 client secret.

    For safety reasons, we recommend web applications using a backend service providing the OAuth2 client secret.

  • Creating Background applications without user interaction

    A background application is installed on the computer.

    Background applications are not connected to a user.

    Create background applications for the following use cases, for example:

    • A server running scheduled events fetching data from the OLT platform
    • A background script fetching device data for all tenants which have installed an application, independent of users
    • Slackbot or other notification applications
  • Managing Applications: Use the OLT platform to manage your applications. Add tenants, for example.

OAuth2

Background

To authenticate users and background applications, we use the OAuth2 protocol and OpenID Connect.

To access the OLT API, an OAuth2 access token is required.

To retrieve an OAuth2 access token, you need an OAuth2 client.

Without a registered application, access to the OLT API is not possible.

For more information about the OAuth2 protocol and OpenID Connect, see

Permissions

We don't use the OAuth2 protocol to grant permissions to applications.

The application permissions are controlled by the user roles.

Registering and Implementing User Applications

To turn a user application into an OAuth2 client, register it to the OLT platform and implement OAuth2 in your application.


Note

Simulating an Application

In the following, we use OAuth 2.0 <debugger/> (https://oauthdebugger.com) to simulate an application.


Prerequisites

To register applications to the OLT platform, you have owner or writer authorization.


Note

Checking permissions

To verify you have owner or writer authorization, in the OLT portal, under Users, check your roles.


Registering and Installing an Application

To access your data in the OLT platform, create an application using the OLT API.

To allow your application to communicate with the OLT platform, create an OAuth2 client.

Procedure

  1. Obtain your tenant ID and an authentication token:

    1. Log on to the OLT portal https://portal.lightelligence.io/.
    2. Select the tenant who is to own the application.
    3. Under Developer Area, look up the
      • authentication token (in our example "eyJhbGciOi ...")
      • tenant ID (in our example "b1747579-355 ...")
  2. To register the application to the OLT platform, make a POST request to the /application-developer/applications endpoint.

    You have the following options, depending on the application type:

    • Web application (recommended): Create web applications authenticating users with the OAuth2 client secret. Ensure that the withPublicOauth2Client property is set to false (confidential).
    • User Agent application: If you don't have a backend service to store the OAuth2 client secret, set the withPublicOauth2Client property to true (public).

    The request passes the following data:

    • one or more redirect URLs where your application is to be hosted. Define different redirect URLs for development, test, and production, for example. Wildcards (*) are not allowed in the redirect URLs. In our simulation, the redirect URL is https://oauthdebugger.com/debug.

    • the authentication token

    • the tenant ID of the tenant owning the application

      Note Managing Applications You can change the application properties later. Add a description and a URL to provide additional information, for example.

      If you have multiple tenants, to facilitate application management consider assigning all applications to the same tenant owning the applications.

      For more information, see Managing Applications.

Example of a web application authenticating users with the OAuth2 client secret ("withPublicOauth2Client": false):

curl -X POST \
    https://api.lightelligence.io/v1/application-developer/applications \
    -H 'Authorization: Bearer {authentication token}' \
    -H 'Content-Type: application/json' \
    -d '{
        "name": "My application name",
        "withPublicOauth2Client": false,
        "allowedTenants": [
            {
                "tenantId": "b1747579-355d-4b7a-aa72-c2336d3a7211",
                "comment": "Example Inc., northern plant"
            }
        ],
        "redirectUris": [
            "https://oauthdebugger.com/debug",
            "https://dev.application.com/auth/callback",
            "https://prod.application.com/auth/callback"
        ]
    }'

You get a response similar to the following. The type is confidential (web application) or public (user agent application).

The response contains the following data:

  • application ID (in our example "3333333-1111-2222-3333-4534g4gd4")
  • OAuth2 client ID (in our example "7222223-1111-2222-3333-fb4444444b7c")
  • OAuth2 client secret (in our example "-9vxPaAd3HmXhNXf")

Example of a response for a web application ("withPublicOauth2Client": false:

{
    "data": {
        "id": "3333333-1111-2222-3333-4534g4gd4",
        "name": "My Web Application",
        "withPublicOauth2Client": false,
        "oauth2Client": {
            "id": "7222223-1111-2222-3333-fb4444444b7c",
            "secret": "-9vxPaAd3HmXhNXf",
            "type": "confidential"
        },
        "tenantId": "b1747579-355d-4b7a-aa72-c2336d3a7211",
        "status": "active",
        "createdAt": "2019-04-25T15:07:15.392Z",
        "updatedAt": "2019-04-25T15:07:15.392Z",
        "allowedTenants": [
            {
                "tenantId": "b1747579-355d-4b7a-aa72-c2336d3a7211",
                "createdAt": "2019-04-25T15:07:15.407Z",
                "installed": false,
                "comment": "Example Inc., northern plant"
            }
        ],
        "redirectUris": [
            "https://oauthdebugger.com/debug",
            "https://dev.application.com/auth/callback",
            "https://prod.application.com/auth/callback"
        ],
    }
}

Example of a response for a user agent application ("withPublicOauth2Client": true):

{
   "data": {
        "id": "2f594b28-411e-4334-9f72-75e1bff2e7f3",
        "name": "My User Agent Application",
        "withPublicOauth2Client": true,
        "oauth2Client": {
            "id": "fe1e5704-1fb1-4e66-818d-f7724f1743e0",
            "secret": "gX1WLw4O7YBwjsw5",
            "type": "confidental"
        },
        "publicOauth2Client": {
            "id": "3f7225f7-9818-4634-8613-c9676935847a",
            "type": "public"
        },
        "tenantId": "b1747579-355d-4b7a-aa72-c2336d3a7211",
        "status": "active",
        "createdAt": "2019-05-16T09:01:10.825Z",
        "updatedAt": "2019-05-16T09:01:10.825Z",
        "redirectUris": [
            "https://oauthdebugger.com/debug",
            "https://dev.application.com/auth/callback",
            "https://prod.application.com/auth/callback"
        ],
        "allowedTenants": [
            {
                "tenantId": "b1747579-355d-4b7a-aa72-c2336d3a7211",
                "createdAt": "2019-05-16T09:01:10.918Z",
                "installed": false,
                "comment": "Example Inc., northern plant"
            }
        ]
    }
}

You have now registered the application to your tenant, so the application is available to be installed in the tenant.

  1. Implement a process to store the OAuth2 client secret.

    If you develop a user agent application without a backend service to store the OAuth2 client secret, ensure that you have set the withPublicOauth2Client property to true, in step 1.


    Note

    Why store the OAuth2 client secret?

    To display application data, you can use the /application-developer/applications endpoint.

    But the response does not contain the OAuth2 client secret.

    If you don't store it, you have to regenerate it making a POST request to the /application-developer/applications/{applicationId}/secret endpoint.


  2. To install the application, make a PUT request to the /applications/{applicationId}/installation endpoint.

  curl -X PUT \
  https://api.lightelligence.io/v1/applications/{application ID}/installation \
  -H 'Authorization: Bearer {authentication token}'
  -H 'Content-Type: application/json'

In our example:

curl -X PUT \
    https://api.lightelligence.io/v1/applications/3333333-1111-2222-3333-4534g4gd4/installation \
    -H 'Authorization: Bearer {eyJhbGciOi ...}
    -H 'Content-Type: application/json'

Result

You get a response similar to the following:

{
    "data": {
        "tenantId": "b1747579-355d-4b7a-aa72-c2336d3a7211",
        "createdAt": "2019-04-25T10:27:20.312Z"
    }
}

Your application is registered to the OLT platform and installed in the tenant owning the application.

A user can logon to the OLT platform and use your application as an OAuth2 client to get data from the tenant in which the application is installed.

Installing the Application in Multiple Tenants

To install an existing application in additional tenants, whitelist the tenants and install the application in each of them.

For more information, see Managing Applications.

Implementing OAuth2 in the Application

Enable your application to act as an OAuth2 client, depending on the application type:

  • Web application running on a web server
  • User agent application running in a browser

Implementing a Web Application

If you have a web application (in which the application source code is protected), implement a confidential OAuth2 client with OAuth2 client secret.

We recommend web applications due to safety reasons.

Prerequisites

When registering the application to the OLT platform, you have set the application property withPublicOauth2Client to false (see above).

Procedure

  1. To get the OAuth2 authorization code, redirect the API call to the URL of our OLT authorization server (id.lightelligence.io):
https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/auth \
?client_id={oauth2Client.id} \
&redirect_uri={redirectUri} \
&scope=openid \
&response_type=code \
&response_mode=form_post

In our example, we authenticate the OAuth 2.0 <debugger/> application simulation hosted under https://oauthdebugger.com/debug:

https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/auth \
?client_id=7222223-1111-2222-3333-fb4444444b7c \
&redirect_uri=https://oauthdebugger.com/debug \
&scope=openid \
&response_type=code \
&response_mode=form_post \

If the user isn't logged on to the OLT platform already, the login screen appears.

On selecting the tenant, the user is redirected to the redirect URL.

You get the OAuth2 authorization code, in our example eyJhb ...:

{
name: 'code', value: 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..ZT1EOZlAoohBhGj2J24ydw.uyRYHynYGlrNpve4UmjsMXzVfXp2XBQPfXHrQWjfqYrPOUZVWoDWDJp7DpWvL8YAPnKANQnUsfEyE3JMA7qdOUHNr5wf2mT1tU3L1RBARui3gefXWlSZXTcC-ULnPmwjqyfVKRb5IPG-6N2Y20Xn0BBFEZEtN1AXslYvts4nKUG-Metg03NKP9Pi3CYVFrlUZIR6sAGsIeNXRiJPtXZ7CtQPStQGOMK_Y-TCXKWT9WUem7FOn3b_U_p7dEWR5Grp.I6Me3lQsqicV9zoH6i293g' },{ name: 'session_state', value: 'da6ee469-6030-495f-a1ce-7262a7b65ef9' }        ]
}
  1. To get an OAuth2 access token, implement a browser callback function to extract the OAuth2 authorization code and make the following POST request to the /id/auth/realms/olt/protocol/openid-connect/token.

    The request passes the following data to the OLT authorization server:

    • the OAuth2 authorization code
    • the OAuth2 client ID of your application
    • the redirect URL
    • the client_secret
curl -X POST \
https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
    -d 'grant_type=authorization_code&code={authorizationCode}&client_id={oauth2Client.id}&redirect_uri={redirectUri}&client_secret={oauth2Client.secret}'

In our example:

curl -X POST \
  https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code&code=eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..ZT1EOZlAoohBhGj2J24ydw.uyRYHynYGlrNpve4UmjsMXzVfXp2XBQPfXHrQWjfqYrPOUZVWoDWDJp7DpWvL8YAPnKANQnUsfEyE3JMA7qdOUHNr5wf2mT1tU3L1RBARui3gefXWlSZXTcC-ULnPmwjqyfVKRb5IPG-6N2Y20Xn0BBFEZEtN1AXslYvts4nKUG-Metg03NKP9Pi3CYVFrlUZIR6sAGsIeNXRiJPtXZ7CtQPStQGOMK_Y-TCXKWT9WUem7FOn3b_U_p7dEWR5Grp.I6Me3lQsqicV9zoH6i293g&client_id=7222223-1111-2222-3333-fb4444444b7c&redirect_uri=https://dev.application.com/auth/callback&client_secret=-9vxPaAd3HmXhNXf'

Note

We can't simulate this step because the request requires the application to be in the same session, in our example the https://oauthdebugger.com/debug application session.


Result

You get the OAuth2 access token allowing your application to access the tenant data.

200:
    {
        "access_token": "eyAdG ..."
    }

Implementing a User Agent Application

If you have a browser application without a backend service, a JavaScript application, retrieve the OAuth2 authorization code without the OAuth2 client secret.

Prerequisites

You have registered and installed the applicattion as described above.

When registering your application to the OLT platform, you have set the application property withPublicOauth2Client to true.

Procedure

  1. To get the OAuth2 authorization code, redirect the API call to the URL of our OLT authorization server (id.lightelligence.io):
    https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/auth \
    ?client_id={oauth2Client.id} \
    &redirect_uri={redirectUri} \
    &scope=openid \
    &response_type=code \
    &response_mode=form_post
  1. To get an OAuth2 access token, implement a browser callback function to extract the OAuth2 authorization code and make the following POST request to the /id/auth/realms/olt/protocol/openid-connect/token.

The request passes the following data to the OLT authorization server:

  • the OAuth2 authorization code
  • the OAuth2 client ID of your application
  • the redirect URL
curl -X POST \
https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code&code={authorizationCode}&client_id={oauth2Client.id}&redirect_uri={redirectUri}'

In our example:

curl -X POST \
    https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/token \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    -d 'grant_type=authorization_code&code={authorizationCode}&client_id=7222223-1111-2222-3333-fb4444444b7c&redirect_uri=https://oauthdebugger.com/debug'

Registering and Implementing Background Applications

To turn a background application into an OAuth2 client, register it to the OLT platform and implement OAuth2 in your application.

Prerequisites

To register applications to the OLT platform, you have owner or writer authorization.


Note

Checking permissions

To verify you have owner or writer authorization, in the OLT portal, under Users, check your roles.


Registering and Installing a Background Application

  1. From the OLT portal, under Developer Area, obtain the tenant ID and the authentication token of the tenant who is to own the application.

    For more information, see the analogous process under Creating and Implementing User Applications.

  2. To register the application to the OLT platform, make a POST request to the /application-developer/applications endpoint.

    The request passes the following data:

    • the authentication token
    • the tenant ID of the tenant owning the application

    Note Managing Applications

    You can change the application properties later, for example, the application name.

    For more information, see Managing Applications.


Example:

    url -X POST \
     https://api.lightelligence.io/v1/application-developer/applications \
     -H 'Authorization: Bearer {authentication token}' \
     -H 'Content-Type: application/json' \
     -d '{
       "name": "Sample Application",
       "allowedTenants": [
          {
               "tenantId": "{tenant Id}"
           }
       ]
    '

You get a response similar to the following, containing the following data:

  • application ID (in our example "9aa3b618-8cd2-4dc0-b7a1-da6df60af254")
  • OAuth2 client ID (in our example "44c11af1-c549-4c18-98bd-bcef92c8b45b")
  • OAuth2 client secret (in our example "vr7i9-P9brKIGYIQ")
    200: {
        "data": {
            "id": "9aa3b618-8cd2-4dc0-b7a1-da6df60af254",
            "name": "Test Application",
            "oauth2Client": {
               "id": "44c11af1-c549-4c18-98bd-bcef92c8b45b",
               "secret": "vr7i9-P9brKIGYIQ",
               "type": "confidential"
            },
            ...
        }
    }
  1. Implement a process to store the OAuth2 client secret.


    Note

    Why store the OAuth2 client secret?

    To display application data, you can use the /application-developer/applications endpoint.

    But the response does not contain the OAuth2 client secret.

    If you don't store it, you have to regenerate it making a POST request to the /application-developer/applications/{applicationId}/secret endpoint.


  2. To install the application, make a PUT request to the /applications/{application Id}/installation endpoint.

curl -X PUT \
https://api.lightelligence.io/v1/applications/{application ID}/installation \
  -H 'Authorization: Bearer {authentication token}'
  -H 'Content-Type: application/json'

In our example:

curl -X PUT \
  https://api.lightelligence.io/v1/applications/9aa3b618-8cd2-4dc0-b7a1-da6df60af254/installation \
  -H 'Authorization: Bearer {authentication token}'
  -H 'Content-Type: application/json'

Result

Your background application is registered to the OLT platform and installed in a tenant.

The background application can get data from the tenant in which the application is installed, without logging on to the OLT platform.

Installing the Application in Multiple Tenants

To install an existing application in additional tenants, whitelist the tenants and install the application in each of them.

For more information, see Managing Applications.

Implementing a Background Application

Implement a confidential OAuth2 client with OAuth2 client secret.

Procedure

To get the OAuth2 access token, do the following:

  • Implement a process to submit, in the request header, the tenant ID of the tenant in which the application is installed.
  • To use the OAuth2 client credentials flow, set the grant type parameter to client_credentials.
  • Submit the OAuth2 client ID and the OAuth2 client secret.
  1. Make a POST request to the id/auth/realms/olt/protocol/openid-connect/token endpoint:
curl -X POST \
https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -H 'tenant: {tenant ID}' \
  -d 'grant_type=client_credentials&client_id={oauth2Client.id}&client_secret={oauth2Client.secret}'

In our example:

curl -X POST \
https://id.lightelligence.io/v1/id/auth/realms/olt/protocol/openid-connect/token \
 -H 'Content-Type: application/x-www-form-urlencoded' \
 -H 'tenant: {tenant ID}' \
 -d 'grant_type=client_credentials&client_id=44c11af1-c549-4c18-98bd-bcef92c8b45b&client_secret=vr7i9-P9brKIGYIQ'

You get a response like the following, containing the OAuth2 access token allowing your application to access the tenant data.

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJWV0VOVDNBN1FLWllFTURoWFBKd3dVa1Jpd04tREI5OThQeUpoU0gzRDZFIn0.eyJqdGkiOiI4YzhlMDAxMi1lYWFiLTRkYzYtYmZiOC1iNTUyNTQ3YTJiMGEiLCJleHAiOjE1NTgyNjA2OTIsIm5iZiI6MCwiaWF0IjoxNTU3Mzk2NjkyLCJpc3MiOiJodHRwczovL2lkLmRldi5vbHQtZGV2LmlvL3YxL2lkL2F1dGgvcmVhbG1zL29sdCIsImF1ZCI6IjI4ZjgzODE5LTE5OWYtNDQxMC1hZTdmLTcyMjE3NjUxMmI5MyIsInN1YiI6IjZmM2Q2MGQwLWJlMzAtNGNiYS1hOTU1LTczMDYzMDExNDg3YyIsInR5cCI6IkJlYXJlciIsImF6cCI6IjI4ZjgzODE5LTE5OWYtNDQxMC1hZTdmLTcyMjE3NjUxMmI5MyIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjAwNjY4OGIxLTEzZjEtNGJhZi1hNzQxLTc4NTdmZmE5NjM2ZiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZXNvdXJjZV9hY2Nlc3MiOnt9LCJzY29wZSI6Im9sdC1hcHBsaWNhdGlvbnMiLCJjbGllbnRJZCI6IjI4ZjgzODE5LTE5OWYtNDQxMC1hZTdmLTcyMjE3NjUxMmI5MyIsImNsaWVudEhvc3QiOiIxMC4yNDAuMC42NiIsImNsaWVudEFkZHJlc3MiOiIxMC4yNDAuMC42NiIsInRlbmFudCI6ImIxNzQ3NTc5LTM1NWQtNGI3YS1hYTcyLWMyMzM2ZDNhNzIxMSJ9.v7cu0zDJY0BqLSmTUauJW46XkGWOuNxVPV7qY4530FZU2BHwZuR5URPlJtHbWpe2QUqxSXboq4dPnL9PmCltUO11DT6cartsJAte4rvvJE2WHb_YtmRasn8b-PxZ9ZVFXIHQRDnIKDu0xPl29ijyqkWbTawdxvuLkwThi4Gu-apqWAjCX2pNBivmuT-25QVBA-FAD_cHuxRPgJ5DJ8BbFIOYR-WjGRAO9v7RLjANSRjXLCS69WP6nKtZn0xJT0GXCUyyLeo_zI4FMWosq9UEFb2hIlXi4kJbkK_pD6KsXq5RGEL7Ap812DUdTDzfA1IcqLH14S38PTnHCFwRssbx0g",
    "expires_in": 863999,
    "refresh_expires_in": 950399,
    "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJWV0VOVDNBN1FLWllFTURoWFBKd3dVa1Jpd04tREI5OThQeUpoU0gzRDZFIn0.eyJqdGkiOiI4ZGMxYWQ3ZC04ZDg1LTQwZjUtOWNjZS05NWZhMGQwNzNlNDEiLCJleHAiOjE1NTgzNDcwOTIsIm5iZiI6MCwiaWF0IjoxNTU3Mzk2NjkzLCJpc3MiOiJodHRwczovL2lkLmRldi5vbHQtZGV2LmlvL3YxL2lkL2F1dGgvcmVhbG1zL29sdCIsImF1ZCI6IjI4ZjgzODE5LTE5OWYtNDQxMC1hZTdmLTcyMjE3NjUxMmI5MyIsInN1YiI6IjZmM2Q2MGQwLWJlMzAtNGNiYS1hOTU1LTczMDYzMDExNDg3YyIsInR5cCI6IlJlZnJlc2giLCJhenAiOiIyOGY4MzgxOS0xOTlmLTQ0MTAtYWU3Zi03MjIxNzY1MTJiOTMiLCJhdXRoX3RpbWUiOjAsInNlc3Npb25fc3RhdGUiOiIwMDY2ODhiMS0xM2YxLTRiYWYtYTc0MS03ODU3ZmZhOTYzNmYiLCJyZXNvdXJjZV9hY2Nlc3MiOnt9LCJzY29wZSI6Im9sdC1hcHBsaWNhdGlvbnMifQ.HN0JYs0PchnO1yOiEt05ZLT0slpJgxuHjnAsR6bIPDMeB-T0g_95ejZvSHp5WsHOeNP8Iu3Z8JCBIEQnTjoSxUVycCtL13ujODsmrzzEFDz4807O4BqMcoTewx_BxlCBSxXzn9mrRPPO-QkWUnwxVLXy1tcgZns3X9DGtmfWNz7HBwzhjutk2fpY2GOMuENgjhhVLhYYYuhY1E74iCt9uK_8XcQsWZKHHxMdNheJ4-Us3-E78sM9skSUUaa6dIN9dhSD51uB-61qiA6zEX91j6FYwSnnLi6CnZMNcwT8ROhxKOyxN98JDRJCwTcPHFcAeFHlTYohRqFTHVnuwAg38Q",
    "token_type": "bearer",
    "not-before-policy": 0,
    "session_state": "006688b1-13f1-4baf-a741-7857ffa9636f",
    "scope": "olt-applications"
}
  1. To verify that your application can access tenant data, fetch some data from a tenant that has installed the application, with the authorization token retrieved from the application.

For example, list the devices registered to the tenant by making a GET request to the /devices endpoint:

curl -X GET \
 https://api.lightelligence.io/v1/devices \
  -H 'Authorization: Bearer {access token}' \
  -H 'Content-Type: application/json' \

In our example:

curl -X GET \
 https://api.lightelligence.io/v1/devices \
  -H 'Authorization: Bearer ey ...' \
  -H 'Content-Type: application/json' \

You get a response similar to the following:

{
    "meta": {
        "page": 0,
        "pageSize": 50,
        "itemsTotal": 6,
        "pagesTotal": 1
    },
    "data": [
        {
            "id": "383b8c61-a9c7-487f-b4e1-66fad753e546",
            "info": {
                "name": "RGB LED",
                "description": "",
                "deviceTypeId": "04f14462-b44f-493c-aa2c-dd6d1c439ec3",
                "tags": [],
                "location": ""
          }
      },
...
}

Managing Applications

Perform activities to maintain applications as an application developer or as a tenant owner using applications.

As the developer, deactivate applications temporarily or whitelist additional tenants, for example.

As a tenant owner, install or uninstall applications, for example.

Verifying Permissions

To manage applications, verify you have the permissions required for the specific endpoints.

Procedure

  1. To identify your user ID, make a GET request to the tenants/{tenantID}/users endpoint.

You get user data such as the user ID (in our example 72fa ...).

{
"data": [
    {
        "id": "72fac0d5-fe32-4599-8f9c-a033e42faaa9",
        "email": "John.Doe@example.com",
        "firstName": "John",
        "lastName": "Doe",
        "userRoles": [
              {
                "id": "3100bdf8-90d9-471d-86ae-f7ba9eff0a86",
                "name": "owner",
                "displayName": "Owner",
                "description": "Default owner role with full access to all resources.",
                "locked": true
            }
        ]
      }
    ],
  ...
  }
}
  1. To list your permissions, make a GET request to the /users/{userId}/permissions endpoint.

Result

You get the user's permissions, for example, the permissions related to application management:

{
    "data": {
        "permissions": [

            ...

            {
                "id": "1a484122-4276-452f-86fe-35328a269e0e",
                "alias": "applications_development:read"
            },
            {
                "id": "c4d20bb1-40a9-4e23-9ceb-ca970b6cd29d",
                "alias": "applications_development:write"
            },
            {
                "id": "b25a38ad-86f9-458d-825a-8c0234f146e7",
                "alias": "applications:read"
            },
            {
                "id": "d430282c-a7a3-4163-92f7-b6055466d318",
                "alias": "applications:write"
            },

            ...

        ]
    }
}

Managing Applications as a Developer

We provide functions to manage applications you have developed.

Examples:

  • Deactivate an application temporarily or change application properties
  • Allow tenants to install applications by registering an application to tenants (whitelisting)

Changing Application Properties

Change the following properties, if required:

  • application name
  • application type (web application with confidential OAuth2 client or user agent application with public OAuth2 client)
  • redirect URLs
  • teaser description to describe the application briefly.
  • URL to provide additional information about the application

Procedure

Make a PATCH request to the use the /application-developer/applications/{applicationId} endpoint.

Deactivating an Application Temporarily

To maintain an application, deactivate it temporarily.

Do some fixes, for example, and ensure the application isn't being used during this time.

The user will see a message that the app is inactive and is asked to contact the developer for more information.

Procedure

Make a PATCH request to the use the /application-developer/applications/{applicationId} endpoint.

Set the status property to inactive.

Regenerating the OAuth2 Client Secret

Regenerate the OAuth2 client secret in the following cases, for example:

  • You have given the OAuth2 client secret out to someone that shouldn't have it. For security reasons, you want to make sure no possible attacker has access to your application data.
  • You have forgotten or lost the OAuth2 client secret when registering your application.

You can always generate a new OAuth2 client secret.

The new OAuth2 client secret invalidates any previous OAuth2 client secret.

For security reasons, we don't allow for fetching OAuth2 client secrets already created.

Procedure

Make a POST request to the /application-developer/applications/{applicationId}/secret endpoint.

Whitelisting Additional Tenants

To install applications in additional tenants, whitelist the tenants. Control the tenants that are to use an application.

Background: To be able to install an application in a tenant, you must have whitelisted the tenant.

Procedure

Deleting an Application

Delete an application if it's obsolete, for example.

Procedure

  1. Identify the whitelisted tenants who might have installed the application.

    Inform the tenant owners to uninstall the application.

    To identify whitelisted tenants, make a GETrequest to the /application-developer/applications/{applicationId}/allowed-tenants endpoint.


    Note

    If you have a background application, you can list the tenants that have actually installed your application.

    See Listing Tenants.


  2. Make a DELETE request to the /application-developer/applications/{applicationId} endpoint.

Listing Tenants

If you have a background application, list all tenants which have currently installed the application and to whose data the application, therefore, has access to.

You get the tenant IDs and tenant names.

The endpoint only fetches up-to-date data from the tenants that currently have installed your application.

Prerequisites

Your application is a background application using client credentials.

For more information, see Creating and Implementing Background Applications.

Procedure

Make a GET request to the /application-info/installed-tenants endpoint.

Managing Applications as a Tenant Owner

Install or uninstall applications.

Installing an Application

Roll out applications to a tenant.

Prerequisites

The application is whitelisted.

Procedure

  1. List all applications available (whitelisted) for a tenant:

    1. Log on to the tenant.
    2. Under Developer Area, copy the authorization token.
    3. Make a GET request to the /applications endpoint.

    To get only the applications not yet installed, set the query parameter installed to false. You get the application name and application ID.

    If the application property available is true, the application can be installed.

    "data": [
     {
         "id": "570e0a66-974b-40dd-8108-844da77719e9",
         "name": "Display Motion Sensor Time Series Data",
         "available": true,
         "availableCode": "APP_AVAILABLE",
         "installation": {
             "tenantId": "570e0a66-974b-40dd-8108-844da77719e9",
             "createdAt": "2019-04-28T23:17:21Z"
         }
     }
    ]
    
  2. Install an application:

    1. Ensure that the application property available is true. Only available (whitelisted) applications can be installed.
    2. Ensure that your user has authorization as writer or owner.
    3. Make a PUT request to the /applications/{applicationId}/installation endpoint.

Performing Miscellaneous Activities

Uninstall an application no longer needed, for example.

Procedure

Troubleshooting Application Management

Resolve typical issues when developing custom applications.

Access Denied

Your custom application can't access a certain endpoint?

Verify that an endpoint has the permission required to access the tenant's data.


Background

For security reasons, custom applications are not allowed to use API endpoints related to tenant management and user management.

You can access these endpoints only in the OLT portal.

So even if your user has the owner role, with a custom application the access is restricted to permissions assigned to the writer role.

If you need to develop custom applications that use endpoints related to user management, contact our OLT support under contact@lightelligence.io.


Custom applications cannot access endpoints which require the following permission:

  • "tenant:read"
  • "tenant:write"
  • "tenant_user_management:read"
  • "tenant_user_management:write"

The /tenants/{tenantId}/users/{userId}/roles endpoint, for example, requires the "tenant_user_management:read" permission. You cannot access it with a custom application.

Prerequisites

You have owner or writer authorization.

Procedure

Make a GET request to the /permissions endpoint.

To authenticate the request, use the OAuth2 access token.

curl -X GET \
https://api.lightelligence.io/v1/permissions \
  -H 'Authorization: Bearer {OAuth2 access token}' \
  -H 'Content-Type: application/json' \

You get a response similar to the following:

{
    "meta": {
        "page": 0,
        "pageSize": 50,
        "totalSize": 26
    },
    "data": {
        "permissions": [
            {
                "id": "78624d68-b09c-4e28-ae5e-812c3cfa1126",
                "alias": "devicetypes:read",
                "category": "devices",
                "name": "Access devicetypes",
                "description": "Get device types and online monitoring rules \\nList available device types and categories\n"
            },
            {
                "id": "d06e523b-d729-4b6d-b7b7-203ab8eaf102",
                "alias": "devicetypes:write",
                "category": "devices",
                "name": "Edit devicetypes",
                "description": "Create device types \\nModify device types and online monitoring rules \\nRemove device types\n"
            },

            ...
        ]
    }
}

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": {
        "additionalProperties": false
      },
      "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": {
      "hue": {
        "b": 0,
        "g": 0,
        "r": 255
      },
      "brightness": 50
    }
  }
}

Creating and updating a device configuration will trigger an MQTT message containing the new / updated configuration object that will be sent to the physical device or the gateway, as explained in section 15.

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. Copy and paste the certificate:

cat device_cert.pem

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": 300
        },
        "attributes": {},
        "status": "NOT MONITORED",
        "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.

Please note, that the /v1/devices/{deviceId}/timeseries-dump endpoint is an asynchronous interface and therefore the generation of the dump takes some time and there is no promise that the dump is ready as soon as the response is received from the POST /v1/devices/{deviceId}/timeseries-dump endpoint. Hence, it's necessary to call the corresponding GET /v1/devices/{deviceId}/timeseries-dump/{dumpId} endpoint until it returns a 200 response.

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}/timeseries-dump 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": "$.configuration.brightness"}'
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: '$.configuration.brightness'
};

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 https://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" }
          }
        },
        "additionalProperties": false
      }
    }
  }
}

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));

The response should contain any devices that you've created and which match the provided filters. Keep in mind that any configuration values will be as they were defined in the OLT cloud rather than what has been sent by the device itself. For example, $.data.configuration.brightness will be 50 instead of 300.

{
  "meta": {
    "page": 0,
    "pageSize": 50,
    "itemsTotal": 1,
    "pagesTotal": 1
  },
  "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": {
        "hue": {
          "b": 0,
          "g": 0,
          "r": 255
        },
        "brightness": 50
      }
    }
  ]
}

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": {
    "attributes": {
      "states": {
        "type": "array",
        "items": {
          "minItems": 2,
          "maxItems": 5,
          "type": "boolean"
        }
      }
    }
  },
  "reportingRules": [
    {
      "path": "$.attributes.states[0]",
      "reportTo": [
        "timeseries"
      ]
    }
  ]
}'
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": {
    "attributes": {
      "states": {
        "type": "array",
        "items": {
          "minItems": 2,
          "maxItems": 5,
          "type": "boolean"
        }
      }
    }
  },
  "reportingRules": [
    {
      "path": "$.attributes.states[0]",
      "reportTo": [
        "timeseries"
      ]
    }
  ]
};

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 to 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 synchronize configurations and send actions over the cloud to a device.

Updating device configurations in the cloud will also trigger an update of the configuration on the device level, whereas a device action is a command that can be executed by a device.

In both cases, the device does no longer produce data but rather consumes/receives data.

Configuration synchronization

Prerequisite for receiving configurations

To be able to receive a configuration update, you have a device type that has a configuration definition in its schema.

In section 03, we have created a device type with configuration.brightness. In section 04 we have added a device of that type.

We're going to update the configuration of that device and listen for a configuration change via MQTT now.

Connecting to the MQTT endpoint and subscribing to a topic

To receive configuration updates for your device, simply subscribe to the topic devices/{deviceId}/configuration.

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}/configuration 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}/configuration' -d

Triggering a configuration synchronization

Configuration updates are sent to a device when the configuration changes in the cloud or when a device with a configuration is created.

If the affected device is connected to a gateway (via connectedBy), the configuration update will be sent to the gateway instead.

To trigger a configuration update, send a PATCH request to /devices/{deviceId}, similarly to updating device attributes, as outlined in section 12:

curl -X PATCH \
  https://api.lightelligence.io/v1/devices/{deviceId} \
  -H 'Authorization: Bearer {TOKEN}' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
  "configuration": {
      "brightness": 100
  }
}'

When you've updated the device configuration, on your device you receive an MQTT message similar to the following:

{
    "deviceId": "{deviceId}",
    "configuration": {
        "brightness": 100
    }
}

This updates your device's internal configuration according to its digital twin in the cloud.

Device actions

Prerequisite for receiving actions

Before triggering a specific action on a device, you have defined the action in the device's type.

You already know how to create a device type from section 03.

To define an action, 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. It 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" : {
              "type": "object",
              "properties": {
                  "brightness": {
                      "type": "number"
                  },
                  "description": {
                      "type": "string"
                  }
              }
          }
      }
    }
}

Connecting to the MQTT endpoint and subscribing to a topic

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

Similarly to subscribing to configuration updates, you can use the following command for Mosquitto:

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

To push an action to your now connected and subscribed device, 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, in your device you now see an MQTT message 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 successfully forwarded an action to your device.

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.