1. Introduction

2. Overview

2.1. What is Live Objects?

Live Objects is a Software as a Service belonging to IoT & Data Analytics services.

Live Objects is a software suite for IoT / M2M solution integrators offering a set of tools to facilitate the interconnection between devices (or connected « things ») and business applications:

  • Connectivity Interfaces (public and private) to collect data, send command or notification from/to IoT/M2M devices,

  • Device Management :inventory, supervision, configuration, resources, campaign management…​,

  • Data Management and collect: Data Storage with Advanced Search features, but also: Message enrichment process, Decoding service and custom pipelines for external enrichment,

  • Message Routing between devices and business applications,

  • Event processing: Alarming with an event detection service by analyzing the data flows sent by devices or occurring on the devices themselves. When these events take place, Live Objects has notification mechanisms to complete the process.

Live Objects overview

Interactive

The public interfaces are reachable from internet. The private interfaces provide interfaces with a specific network (LoRa®).

The SaaS allows multiple tenants on the same instance without possible interactions across tenant accounts (i.e. isolation, for example a device belonging to one tenant could not communicate with a device belonging to an other tenant).

A web portal provides a UI to administration functions like manage the messages and events, supervise your devices and control access to the tenant.

2.2. Architecture

Live Objects SaaS architecture is composed of two complementary layers:

  • Connectivity layer: manages the communications with the client devices and applications,

  • Service layer: various modules supporting the high level functions (device management, data processing and storage, etc.).

Live Objects architecture

Interactive

2.3. Connectivity layer

Live Objects exposes a set of standard and unified public interfaces allowing to connect any programmable devices, gateway or functional IoT backend.

The existing public interfaces are:

MQTT is an industry standard protocol which is designed for efficient exchange of data from and to devices in real-time. It is a binary protocol and MQTT libraries have a small footprint.

HTTPS could be rather used for scarcely connected devices. It does not provide an efficient way to communicate from the SaaS to the devices (requiring periodic polling for example).

For more info, see "Message encodings" section

The public interfaces share a common security scheme based on API keys that you can manage from Live Objects APIs and web portal.

Live Objects is fully integrated with a selection of devices and network. It handles communications from specific families of devices, and translate them as standardized messages available on Live Objects message bus.

The existing private interfaces:

  • LoRa® interface connected with LoRa® network server,

    • to provision LoRa® devices

    • to receive and send data from/to LoRa® devices

Also, it may be possible that your devices are not complient with Live Objects interfaces. It is still possible to use the API for "external connector" feature:

"External connector" mode : a good fit for connect your custom backend who manage your devices and when your devices don’t support Live objects connectivity. This mode has an MQTT API described in mode "External connector".

2.4. Service layer

Behind the connectivity layers for devices, Live Objects is a platform with several, ready to use services to enhanced you IoT potential.

On the one hand, the data collect part with various services: internal enrichment, decoding and custome pipelines for external enrichment services.

On the other hand, these data can be publish into a FIFO and consume using MQTT "application" mode.

  • FIFO : the solution to prevent from message loss in the case of consumer unavailability. Messages are stored in a queue on disk until consumed and acknowledged. When multiple consumers are subscribed to the same queue concurrently, messages are load-balanced between available consumers. More info: FIFO mode,

  • Application mode : a good fit for real-time exchanges between Live Objects backend and your business application. Data messages exchanged are queued in the FIFO queuing bus mechanism mode "Application".

2.4.1. Device management

Live Objects offers various functions dedicated to device operators:

  • supervise devices and manage connectivity,

  • manage devices configuration parameters,

  • send command to devices and monitor the status of these commands,

  • send resources (any binary file) to devices and monitor the status of this operation.

Live Objects attempts to send command, resources or update the parameters on the device as soon as the device is connected and available.

For more info about device and connectivity inventory, see "Device and connectivity inventory" chapter.
For more info about device connectors, see "Device connectors" section.
For more info about device management, see "Device Management" chapter.

2.4.2. Data management

2.4.2.1. Data transformation

Live Objects can transform the published messages by using data enrichment, message decoding and external datamessage transformation by using custom pipelines.

For more info, see "Data transformation" chapter.

2.4.2.3. Data analysis and display

Live Objects allows to store the collected data from any connectivity interfaces. These data could be then retrieved by using HTTPS REST interface.

A full-text search engine based on Elastic search is provided in order to analyze the data stored. This service is accessible through HTTPS REST interface.

For more info, see "Data analysis" chapter.

2.4.3. Messages and Events Processing

2.4.3.1. SEP, SP and AP

Simple event processing service is aimed at detecting notable single event from the flow of data messages.

Based on processing rules that you define, it generates fired events that your business application can consume to initiate downstream action(s) like alarming, execute a business process, etc.

For more info, see "Simple Event Processing" section.

In the other hand, Live Objects allows to process the Activity processing (AP) service which aims at detecting devices that have no activity.

For more info, see "•Activity processing" section.

The State processing (SP) service aims at detecting changes in "device state" computed from data messages.

For more info, see "•State processing" section.

2.4.3.2. Routing and Alarming

The FIFO mode communication is based on the usage of topics to publish a messages with ensuring no message loss. It can forward or route messages to recipients without loss using FIFO Publication and FIFO subscription. You can also use the HTTP push forwarding after the message is processed by event processing service or message routing service. Those services give a notifications or give an alarm to the recipients on purpose.

2.5. Access control

2.5.1. API keys

API keys are used to control the access to the SaaS for devices/application and users to authenticate. You must create an API key to use the API.

For more info, see "API key" and "Role" chapters.

2.5.2. Users management

When an account is created, a user with administration priviledges is also created on the account. This administrator can add other users to the account and set their priviledges. These priviledges are defined by a set of roles. The users can connect to the Live Objects web portal.

2.6. Edge computing

In an advanced usage, you have some ways to integrate the IOT edge plateform which can collect, manage and store the business data. But more use cases need treatments close to devices to provide :

  • Local treatment with low latency and independency

  • interoperability with industrial protocols

  • Secure approach with keeping locally the business and critical data

3. Getting started

This chapter is a step-by-step manual for beginners with Live Objects giving instructions covering the basic use cases of the service. Here is a small process to begining with Live objects and help you to easy building a use case and end-to-end test.

  • If you have device you can starting to use it.

  • If you do not have a device, browse the instructions in this guide to build a usage that uses only simulators to replace a device. You can use your own device simulator and use MQTT or COAP protocol to connect your virtual device to Live Objects.

Requirements : the data message sent by device (or simulator) must respect the Live Objects data model.

Connect your device and retrieve data with Live Objects (steps by device category and connectivity)

Interactive

3.1. Log in

To log in to Live Objects web portal, connect to liveobjects.orange-business.com using your web-browser:

landing

  • Fill the Sign in form with your credentials:

    • your login,

    • the password set during the activation phase,

  • then click on the Sign in button.

You are redirected to your “Dashboard” page:

landing

3.2. Connect and test your LoRa® device

LoRa® devices need to be registered on Live Objects to send messages.

To quick register your LoRa® device, use the Live Objects portal, liveobjects.orange-business.com.

3.2.1. Register your device

To register a LoRa® device, go to the Devices menu, select LoRa® in the list and click on Add device.

In the form, select the profile that corresponds to your device. If you do not know, select Generic_classA_RX2SF12. Enter your device’s DevEUI, AppEUI and AppKey. Depending on the LoRa® device you are using, these parameters are pre configured and they should come with the device, or you can configure the device resource with your own parameters. Then click on Register.

You can see your device in the Devices menu.

3.2.2. Connect your LoRa® device

When the device is registred then join LoRa® network and it would automatically connected to Live Objects. The device is now ready to send uplink data and begining to publish the data messages.

When you prefer using an API, see Register a LoRa® device

3.3. Simulating an MQTT device

To make a device or an application communicate with Live Objects using MQTT, you will need an API key.

3.3.1. Create an API key

To create an API key, go to the Configuration menu, click on Api keys in the left menu and create a new API key. Select at least the role "DEVICE_ACCESS".

landing

As a security measure, you can not retrieve the API key again after you have closed the API key creation results page. So, note it down to work with the MQTT client, during the scope of this getting started.

landing

3.3.2. Download your simulator tool

It is up to you to choose your favorite MQTT client or library. We will use here MQTTBox. This client is available on Win/MacOSX/Linux and is free (until now). Download and install the last version of MQTTBox.

3.3.3. Connect your simulator

We will start by creating a new Connection profile and configure it based on the device mode set up.

General panel:

You will configure here the endpoints of Live Objects including authentication information. In this panel, you can set :

landing

Credentials panel:

  • username: json+device : for device mode MQTT connection

  • password: the API key that you just created with the "DEVICE_ACCESS" role

landing

3.3.4. Verify status

We can simulate a device connection to Live Objects with MQTTbox client by clicking on Connect button of MQTTbox client.

landing

In Live Objects portal, go to the Devices page, the connected device has "green" status.

landing

3.3.5. Publishing data messages

We will use MQTTbox client with device mode to send data message as a device would do.

Data message must be published on this topic: dev/data.

Message:

{
    "streamId" : "urn:lo:nsid:sensor:2327398!measures",
    "location": {
        "lat": 48.86667,
        "lon": 2.33333
    },
    "model": "temperatureDevice_v0",
    "value": {
        "status" : "online",
        "tempreature rise frequency" : 10,
        "temp" : 17.25
    },
    "tags": [ "City.NYC", "Model.Prototype" ]
}

With:

  • streamId: the streamId of the message, the message will be forwarded to a topic containing the streamId so an application connected to Live Objects can retrieve messages

  • timestamp: the timestamp of the message, this field is optionnal, if not set by the device, Live Objects will set it with the time of arrival,

  • location: the location of the device, this field is optionnal,

  • model: the model of data contained in the v field, (more about data model)

  • value: the value, this is a free field to store device specific data such as the device sensor values,

  • tags: a list of tags, this field is optionnal.

landing

3.4. Device Management basics

3.4.1. Sending a command to a LoRa® device

Messages sent by LoRa® devices to Live Objects are called uplinks. Messages sent by Live Objects to LoRa® devices are called downlinks.

To send a command, go to Devices then select your LoRa® device in the list and go to Downlink tab. Click on Add command, enter a port number between 1 and 223 and enter data in hexadecimal, 0A30F5 for example. The downlink will be sent to your device after the next uplink.

3.4.2. Sending a command to an MQTT device

You must first subscribe to the topic waiting for command "dev/cmd". (Subscribe tab of MQTTbox)

Go to Devices then select your device in the list and go to Commands tab.

Click on add command then fill the event field with "reboot" then click on Register. The command will appear in MQTTbox client subscribe tab.

command request

 {
    "req":"reboot",
    "arg":{},
    "cid":94514847
  }

landing

A response can be sent to acknowledge the command received.

To send this response, you can publish a message to this topic "dev/cmd/res". (correlation identifier) must be set with the value received previously.

command response

 {
   "res": {
      "done": true
   },
   "cid": 94514847
 }

Once published, the status of the command will change to "processed" in the portal commands history tab.

A correlation ID uniquely identifies each ‘request’, or the equivalent and used in your intercation with Live Objects API.

3.5. Accessing the stored data

There are several ways to access you device’s data:

  • Going back to Live Objects portal, you can consult the data message that was just stored. Go to Data then search for stream "urn:lo:nsid:dongle:00-14-22-01-23-45!temperature". The data message sent will appear.

landing

  • You can access data from the HTTPS interface.

  • You can perform complex search queries like aggregation using elasticsearch DSL HTTPS interface. See example in See example in Data API chapter

  • Through the MQTT interface, either your configured FIFO queue or your connected MQTT client will receive data messages.

3.6. Connect an application to collect your devices data

3.6.1. Using HTTPS to retrieve your devices' data

Data from you device can be retrived using HTTPS API.

You will need an API key with the DATA_R role. You can create it as you did in the previous part.

The following endpoint enables you to retrieve data from a stream: https://liveobjects.orange-business.com/api/v0/data/streams/{streamId}

Example with a MQTT device:

GET /api/v0/data/streams/urn:lo:nsid:dongle:00-14-22-01-23-45!temperature
Host: https://liveobjects.orange-business.com
Header: X-API-KEY: <a valid API key with DATA_R role>

Example with a LoRa® device:

GET /api/v0/data/streams/urn:lo:nsid:lora:<DevEUI>
Host: https://liveobjects.orange-business.com
Header: X-API-KEY: <a valid API key with DATA_R role>

3.6.2. Using MQTTs to retrieve your device’s data

Data published by your devices can be consumed using the MQTT protocol.

You will need an API key with the BUS_R role. You can create it as you did in a previous part.

Then configure a FIFO queues to persist your device’s data until you consume them. To do this, you will have to create a FIFO queue and then route your device’s data to the queue.

In the Data menu, go to the FIFO tab and click on the add a FIFO queue button In the pop-in enter a name myFifo for your FIFO queue, then press Register button: the newly created FIFO queue myFifo is now listed.

landing

The FIFO queue is ready to persist data. To make your device’s data enter the queue, you have to route them to the queue. More information about routing in the section FIFO publish action.

Future messages sent by your device will be stored in the FIFO queue until an MQTT client subscribes to the queue.

The "application" mode purpose is to retrieve messages available in your FIFOs.

Available MQTT endpoints are described in the section Endpoints.

Beforehand, a connection must be established as follows :

  • clientId: ignored

  • username: application

  • password: a valid Live Objects API key with a BUS_R role

  • willRetain, willQoS, willFlag, willTopic, willMessage: ignored

Then a subscription to the following topic to consume data from your FIFO : "fifo/myFifo".

3.6.3. Tutorial video

3.7. Connect a device without a supported protocols

If you have a fleet of devices that do not support traditional protocols or that are connected to a custom backend, you can use the external connector mode:

  • Connect your specific devices with this mode

  • The external connector which uses the MQTT protocol, allows for all your data to be collected in a single place.

  • Monitor your devices connectivity

  • Configure your devices from Live objects platform

  • Receive command from Live Objects platform

  • Update your devices resource and configuration

4. Account Management and Access Control

4.1. Tenant account

A tenant account is the isolated space on Live Objects dedicated to a specific customer: every interaction between Live Objects and an external actor (user, device, client application, etc.) or registered entities (user accounts, API keys, etc.) is associated with a tenant account.

Live Objects ensures isolation between those accounts: you can’t access the data and entities managed in another tenant account.

Each tenant account is identified by a unique identifier: the tenant ID.

A tenant account also has a name, that should be unique.

4.2. User account

A User Account represents a user identity, that can access the Live Objects web portal.

A user account is identified by a login. A user account is associated with one or many roles. A user can authenticate on the Live Objects web portal using a login and password.

When user authentication request succeeds, a temporary API key is generated and returned, with same roles as the User account.

In case of too many invalid login attempts, the user account is locked out for a while.

For security purpose, a password must be at least 8 characters including at least 1 uppercase letter, 1 lowercase letter, 1 special character, 1 digit and 1 special characters.

4.3. API key

Interactive

A Live Objects API key is a secret that can be used by a device, an application, or a user to authenticate when accessing to Live Objects on the MQTT or HTTPS/REST interfaces. At least one API key must be generated. As a security measure, an API key can not be retrieved after creation (As describe in this section), .

An API key belongs to a tenant account: after authentication, all interactions will be associated only to this account (and thus isolated from other tenant accounts).

An API key can have zero, one or many Roles. These roles allows to restrict the operations that could be performed with the key.

An API key validity can be limited in time.

Creating a tenant account automatically attribute a "master" API key.

That API key is special: it can’t be deleted.

An API key can generate child-API keys that inherit (a subset of) the parent roles and validity period.

An API key can be restrained to one or more message queues:

  • If one or more message queues are selected, the API key can access only these queues.

  • If no message queue is selected, the API key has no restriction and can access any queue.

Thus, the API key can only be used in MQTT access limited to these selected message queues. This for example, makes it possible, after having oriented the right device to the right queue, to restrict access to the data of specific devices.

Usage:

  • In MQTT, clients must connect to Live Objects by using a valid API key value in the password field of the (first) MQTT « CONNECT » packet,

    • In case of unknown API key value, or invalid, the connection is refused.

    • On success, all messages published on this connection will be enriched with the API key id and roles.

  • In HTTPS, clients must specify a valid API key value as HTTP header X-API-Key for every request,

    • In case of unknown API key value, request is refused (HTTP status 403).

    • In case of invalid API key value, request is refused (HTTP status 401).

    • On success, all messages published due to this request will be enriched with the API key id and roles.

4.4. Role

A Role is attributed to an API key or User Account. It defines the privileges on Live Objects. A Role is attributed to an API key or User Account.

Important Notice : Some features are only available if you have subscribed to the corresponding offer, so you may have the proper roles set on your user but no access to some features because these features are not activated on your tenant account (check the tenant offer).

The currently available roles and their inclusion in Admin or User profiles:

Role Name Technical value Admin profile User profile Priviledges

API key

API_KEY_R

X

X

Read parameters and status of an API key.

API key

API_KEY_W

X

X

Create, modify, disable an API key.

User

USER_R

X

X

Read parameters and status of a user.

User

USER_W

X

Create, modify, disable a user.

Settings

SETTINGS_R

X

X

Read the tenant account custom settings.

Settings

SETTINGS_W

X

X

Create, modify tenant account custom settings.

Device

DEVICE_R

X

X

Read parameters and status of a Device management.

Device

DEVICE_W

X

Create, modify, disable a Device management, send command, modify config, update resource of a Device.

Device Campaign

CAMPAIGN_R

X

X

Read parameters and status of a massive deployment campaign on your Device Fleet.

Device Campaign

CAMPAIGN_W

X

Create, modify a campaign on your Device Fleet.

Data

DATA_R

X

X

Read the data collected by the Store Service or search into this data using the Search Service.

Data

DATA_W

X

Insert a data record to the Store Service. Minimum permission required for the API key of a device pushing data to Live Objects in HTTPS.

Data Processing

DATA_PROCESSING_R

X

X

Read parameters and status of an event processing rule or a Data decoder.

Data Processing

DATA_PROCESSING_W

X

Create, modify, disable an event processing rule or a Data decoder.

Bus Config

BUS_CONFIG_R

X

X

Read config parameters of a FIFO queue or a binding rule.

Bus Config

BUS_CONFIG_W

X

Create, modify a FIFO queue or a binding rule.

Bus Access

BUS_R

X

X

Read data on the Live Objects bus. Minimum permission for the API key of an application collecting data on Live Objects in MQTT(s).

Bus Access

BUS_W

X

X

Publish data on the Live Objects bus.

Bus Access

DEVICE_ACCESS

X

X

Role to set on a Device API key to allow only MQTT Device mode

Bus Access

CONNECTOR_ACCESS

X

X

Role to set on a external connector API key to allow only MQTT external connector mode

Audit Log

LOGS_R

X

X

Read the logs collected by the Audit Log service. This right allows users to use the Audit Log service as debugging tool.

5. Device and connectivity

The version 1 of the device APIs (/api/v1/deviceMgt) comes up with a brand new model of devices in Live Objects.

We have worked on providing unified representations whatever the technology that is used to connect the device to Live Objects using IP connectivity (MQTT, HTTP), LoRa® or SMS, while maintaining the access to each specific technology.

5.1. Principles

A device is a generic term that can designate an equipment (sensor, gateway) or an entity observed by equipments (ex: a building, a car).

5.2. Device description

A device description is a set of JSON documents that store a device identity information, a device state information, a metadata (definition, activity, alias) a device connectivity information for each device that you will connect to Live objects.

Each device description has 2 sections to describe the device representation :

  • Device identity.

  • Device interface representation.

5.2.1. Devices representation

5.2.1.1. Device identifier format

A device identity is represented by a unique identifier. This identifier must respect the following format:

urn:lo:nsid:{ns}:{id}

Where:

  • ns: your device identifier "namespace", used to avoid conflicts between various families of identifier

  • id: your device id

Should only contain alphanumeric characters (a-z, A-Z, 0-9) and/or any special characters amongst : - _ and must avoid $ ' ' * # / !| + and must respect the following regular expression: ^urn:lo:nsid:([\w-]{1,128}):([:\w-]{1,128})$ (with max 269 characters).

If your device is auto-provisioned (first connection), the device identifier namespace is automatically completed according to the "urn:lo:nsid" prefix (if not available) + the set of characters according the previous rule of regular expression.
5.2.1.2. Device object model

Depending on your connectivity interface, the device object model may have a dedicated "definition" section to describe the parameters of your interface (s).

Device object model overview:

Interactive

Device model in Json format

{
  "id": "urn:lo:nsid:sensor:temp001",
  "name": "mySensor001",
  "description": <<some description>>,
  "defaultDataStreamId": <<myStreamId>>,
  "activityState": <<monitoring the device>>
  "tags": ["Lyon", "Test"],
  "properties" : {
      "manufacturer": <<myManufacturer>>,
      "model": <<myModel>>
  },
  "group": {
      "id": <<id>>,
      "path": <<myPathId>>
  },
  "interfaces": [
        {
          "connector": <<myConnector>>,
          "nodeId": <<interface Id>>,
          "deviceId": "urn:lo:nsid:sensor:temp001",
          "enabled": <<true/false>>,
          "status": <<the status of the interface>>,
          "definition": {
                ........to learn more, see the "Device interface representation" section
          },
          "activity": {},
          "capabilities": {
                "command": {
                   "version" : <<versionNumber>>,
                   "available": <<true/false>>
                },
                "configuration": {
                   "available": <<true/false>>
                },
                "resources": {
                   "available": <<true/false>>
               }
           }
        }
    ],
    "created": <<date>>,
    "updated": <<date>>,
    "staticLocation": {
        "lat": <<Latitude value>>,
        "lon": <<Longitude value>>,
        "alt": <<Altitude value>>
    }
}

Device object model description:

JSON Params Description

id

device unique identifier (Cf. device identifier)

description

Optional. detailed description of the device

name

Optional. name of the device

defaultDataStreamId

default data stream id. Specify the streamId where the data will be store (Cf. "Manage your data stream" section).

tags

Optional. list of additional information used to tag device messages

properties

Optional. map of key/value string pairs detailing device properties

group

group to which the device belongs. The group is defined by its id and its path

interfaces

Optional. list of device network interfaces (Cf. interface object model)

created

creation date of the device

updated

last update date of the device

config

Optional. device configuration

firmwares

Deprecated device firmware versions (same value as "resources", available for compatibily reasons)

resources

Optional. device resource versions

activityState

Optional. device activity state aggregated from the activity processing service, the special state NOT_MONITORED means that the device is not targeted by any activity rule

staticLocation

Optional. the static location of device.

5.2.1.3. Device interface representation

An interface is a platform access. A device can have no, one or several interfaces, which represent different connectivities that the device could use to communicate with Live Objects. Each interface is associated to a protocol managed by Live Objects connector: LoRa®, SMS or MQTT. For the custom protocols, the devices must connected with external connector interface.

devices with single/multi connectivity

Interactive

Interface object model:

JSON Params Description

connector

connector identifier

nodeId

interface unique identifier

deviceId

Optional. device unique identifier

enabled

define if the interface is enabled or disabled

status

interface status

definition

interface definition. The definition depends on connector.

lastContact

Optional. lastContact is the last date of the last uplink from the device, in LoRa® connectivity, this field is also updated during a join request sent by the device.

activity

interface activity. The activity depends on connector.

capabilities

interface capabilities.

locations

Optional. list of last interface location.

created

registration date of the interface

updated

last update date of the interface

For more information on each connector definition, activity and status, see the appropriate section:

5.2.1.4. Interface status

Each interface has a status field which shows the state of the corresponding interface. The values are the same for all connectors, but each connector sets the status differently. The following table shows which statuses are supported, or will soon be supported by connectors.

Status \ Connector

LoRa®

MQTT

SMS

External connector

LwM2M

REGISTERED

ONLINE

OFFLINE

SLEEPING

CONNECTIVITY_ERROR

INITIALIZING

INITIALIZED

REACTIVATED

ACTIVATED

DEACTIVATED

Each interface has an enabled flag which allows or forbids an interface to connect and communicate with Live Objects. The enabled flag changes the interface’s status.

This flag can be set when creating the interface or updating the interface.

The following table shows a description of each technical value of the interface status.

Status Value Description

REGISTERED

The device has been registered in the network with the parameters specified when it was created. No uplink data has yet been received by the platform.

INITIALIZING

The network received a Join Request from the device

INITIALIZED

The network sent a Join Accept to the device

ACTIVATED

At least one uplink issued by the device was received by Live Objects (excluding MAC messages)

DEACTIVATED

The device has been deactivated in Live Objects. He can no longer communicate on the network (See the paragraph "Deactivate and reactivate a LoRa® device" and see the deactivation of the LwM2M device.

REACTIVATED

The device has been reactivated in Live Objects. Not being able to know a priori the state of the device at the time of the reactivation, the state will pass to "Activated" if a Join Request is received, or directly to "Activated" if an uplink is received.

CONNECTIVITY_ERROR

This status, rare, is displayed in case of problem on configuration of the equipment in the network. If this status appears, contact your support.

ONLINE (MQTT)

The MQTT connection of the device is active

ONLINE (LwM2M)

The LwM2M device is registered and active

SLEEPING (LwM2M)

The LwM2M device is in sleeping mode but the session is still active.

OFFLINE (MQTT)

The device has already connected at least once but its MQTT connection is inactive

OFFLINE (LwM2M)

The LwM2M device is deregistred or deactivated.

ONLINE (SMS)

The SMS device is activated at Live Objects level

OFFLINE (SMS)

The SMS device is deactivated at Live Objects level

5.2.1.5. Capabilities

Capabilities \ Connector

LoRa®

MQTT

SMS

External connector

LwM2M

Command

Configuration

Resource

Twin

Interface capabilities represent the Live Objects features compatibility.

  • Command : Compatibility with the generic command engine and API

  • Configuration : Compatibility with config update feature. MQTT connectivity only for now

  • Resource : Compatibility with resource update feature. MQTT connectivity only for now

  • Twin : Compatibility with the Live Objects twin service. LwM2M/CoAP connectivity only for now

5.2.1.6. Device static location

The static location is a set of a declared geographical coordinates values (longitude, latitude and altitude). Its section in the device object model must have the following format:

"staticLocation": {
        "lat": <<Latitude value>>,
        "lon": <<Longitude value>>,
        "alt": <<Altitude value>>
    }

This info is useful for stationary devices, or devices that are not sending location information to Live Objects.

This section can be created if setted during device provisioning.
POST /api/v1/deviceMgt/devices/<myDeviceId>
{
    "id": "<myDeviceId>",
    "description": "Device 123",
    "name": "My Device",
    "defaultDataStreamId": "MydefaultStream"
    "interfaces": [
        {
            "connector": "mqtt",
            "enabled": "true",
            "definition": {
                "clientId" : "<myDeviceId>",
                "encoding" : "myEncoding"
            }
        }
    ],
    "staticLocation": {
        "lat": <<Latitude value>>,
        "lon": <<Longitude value>>
    }
}

5.3. Device management basic

5.3.1. Register a device

5.3.1.1. Request

Endpoint:

POST /api/v1/deviceMgt/devices

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Body:

JSON Params Description

id

device unique identifier (Cf. device object model)

tags

Optional. (Cf. device object model)

name

Optional. (Cf. device object model)

description

Optional. (Cf. device object model)

defaultDataStreamId

Optional. (Cf. device object model)

properties

Optional. (Cf. device object model)

group

Optional. (Cf. device object model)

interfaces

Optional. (Cf. device object model)

Devices can be registered with one or more chosen interfaces.

Currently, you can associate an SMS interface (Cf. register device with an SMS interface example) or a LoRa® interface (Cf. register device with a LoRa® interface example) with the devices. The other supported interfaces, the MQTT and External connector interfaces can be automatically registered during the first MQTT connection.

Example: Register a device without interface

POST /api/v1/deviceMgt/devices
{
  "id": "urn:lo:nsid:sensor:temp001",
  "tags": ["Lyon", "Test"],
  "name": "mySensor001",
  "description": "moisture sensor",
  "properties" : {
      "manufacturer": "Orange",
      "model": "MoistureSensorV3"
  },
  "group": {
      "path": "/france/lyon"
  }
}
5.3.1.2. Response

HTTP Code:

200 OK

Body:

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

403

GENERIC_OFFER_DISABLED_ERROR

The requested service is disabled in your offer settings. Please contact a sales representative.

403

GENERIC_ACTION_FORBIDDEN_ERROR

You do not have the required permissions to execute this action.

404

DM_GROUP_NOT_FOUND

Group not found

409

DM_INTERFACE_DUPLICATE

Interface already exists. Conflict on (connector/nodeId)

409

DM_DEVICE_DUPLICATE

Conflict on device id

Example: Register a device without interface

{
    "id": "urn:lo:nsid:sensor:temp001",
    "description": "moisture sensor",
    "name": "mySensor001",
    "defaultDataStreamId": "urn:lo:nsid:sensor:temp001",
    "tags": ["Lyon", "Test"],
    "properties": {
        "manufacturer": "Orange",
        "model": "MoistureSensorV3"
    },
    "group": {
        "id": "sWyaL2",
        "path": "/france/lyon"
    },
    "created": "2018-02-12T13:29:52.442Z",
    "updated": "2018-02-12T13:29:52.442Z"
}

5.3.2. List devices

5.3.2.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices

Query parameters:

Name Description

limit

Optional. maximum number of devices in response. 20 by default.

offset

Optional. the number of entries to skip in the results list. 0 by default.

sort

Optional. sorting selection. Prefix with '-' for descending order. Supported value: id, name, group, created, updated,interfaces.status, interfaces.enabled, interfaces.lastContact. Example: ["urn","-creationTs"]"..

id

Optional. device id

groupPath

Optional. groupPath, Supported filters are → exact match : foo, group or subgroups : foo/*

groupId

Optional. filter list by groupId

name

Optional. device name, Supported filters are → contains : *foo*, end with foo : *foo, start with foo : foo*, exact match : "foo" or foo

tags

Optional. filter list by device tags

connectors

Optional. filter list by interface connector

fields

Optional. fields to return for each device. By default, information returned are id, name, group and tags. Supported value: name, description, group, tags, properties, interfaces, config, firmwares (deprecated), resources, defaultDataStreamId, activityState, created and updated.

interfaces.nodeId

Optional. Filter list by nodeId.

interfaces.status

Optional. Filter list by interface status.

interfaces.enabled

Optional. Filter list by interface enabled state.

property.{filterName}

Optional. Multiple filters, Example: devices?property.temperature=25&property.humidity=58…​

filterQuery

Optional. Device filter expression using RSQL notation. Supported device properties are tags, properties, groupId,groupPath, connector . Supported RSQL operators are ==, !=, =in=, =out=, =lt=, =le=, =gt=, =ge=, and, or.

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json
X-Total-Count: <boolean>

For more info about X-Total-Count, see "API v1 paging" section.

Simple devices list request:

Get name, creation date and group of device having name starting with mySensor sorted by id descending.

GET /api/v1/deviceMgt/devices?name=mySensor*&sort=-id&fields=name,created,group

RSQL advanced devices list request:

Get id field only of devices matching following (RSQL filter url-encoded under) filterQuery: groupPath==/France;tags==demo;connector==lwm2m or (connector==x-connector)

For example, devices having /France as path and demo in tags, and (lwm2m or x-connector) as connector

GET /api/v1/deviceMgt/devices?fields=id&filterQuery=groupPath%3d%3d/France%3btags%3d%3ddemo%3bconnector%3d%3dlwm2m+or+(connector%3d%3dx-connector)
5.3.2.2. Response

HTTP Code:

200 OK

Body: List of device object model

JSON Params Description

id

device unique identifier

description

Optional. detailed description of the device

name

Optional. name of the device

defaultDataStreamId

Optional. default data stream Id of the device

tags

Optional. list of device tags

properties

Optional. properties of the device

group

Optional. group to which the device belongs

interfaces

Optional. list of device’s network interfaces

created

Optional. registration date of the device

updated

Optional. last update date of the device

config

Optional. device configuration

firmwares

Deprecated device firmware versions (same value as "resources", available for compatibily reasons)

resources

Optional. device resource versions

activityState

Optional. device activity state aggregated from the activity processing service, the special state NOT_MONITORED means that the device is not targeted by any activity rule

Simple devices list response example:

[
    {
        "id": "urn:lo:nsid:sensor:temp002",
        "name": "mySensor002",
        "group": {
            "id": "root",
            "path": "/"
        },
        "created": "2021-07-01T09:02:40.616Z"
    },
    {
        "id": "urn:lo:nsid:sensor:temp001",
        "name": "mySensor001",
        "group": {
            "id": "sWyaL2",
            "path": "/france/lyon"
        },
        "created": "2021-07-01T09:02:40.616Z"
    }
]

5.3.3. Get a device

5.3.3.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/<deviceId>

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:mqtt:myTest
5.3.3.2. Response

HTTP Code:

*200 OK*

Body:

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

401

UNAUTHORIZED

Authentication failure.

404

DM_DEVICE_NOT_FOUND

Device not found.

Example:

{
    "id": "urn:lo:nsid:sensor:temp002",
    "name": mySensor002",
    "description": "This device was auto registered by the connector [mqtt] with the nodeId [urn:lo:nsid:mqtt:myTest]",
    "group": {
        "id": "root",
        "path": "/"
    },
    "defaultDataStreamId": "urn:lo:nsid:sensor:temp002",
    "created": "2021-07-01T09:02:40.616Z",
    "updated": "2021-07-01T09:04:46.752Z",
    "activityState": "NOT_MONITORED",
    "interfaces": [
        {
            "connector": "mqtt",
            "nodeId": "urn:lo:nsid:mqtt:myTest",
            "enabled": true,
            "status": "OFFLINE",
            "lastContact": "2021-08-13T09:05:06.751Z",
            "capabilities": {
                "configuration": {
                    "available": false
                },
                "command": {
                    "available": false
                },
                "resource": {
                    "available": false
                },
                "twin": {
                    "available": false
                }
            },
            "activity": {
                "apiKeyId": "60508c314ca6b82d6d605b1e",
                "mqttVersion": 4,
                "mqttUsername": "json+device",
                "mqttTimeout": 60,
                "remoteAddress": "82.13.102.175/27659",
                "lastSessionStartTime": "2021-08-13T09:03:21.158Z",
                "lastSessionEndTime": "2021-08-13T09:04:06.750Z"
            },
            "created": "2021-07-01T09:02:40.615Z",
            "updated": "2021-07-01T09:04:46.752Z"
        }
    ]
}

5.3.4. Delete device

5.3.4.1. Request

Endpoint:

DELETE /api/v1/deviceMgt/devices/<deviceId>

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

DELETE /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001
5.3.4.2. Response

HTTP Code:

204 NO CONTENT

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

404

DM_DEVICE_NOT_FOUND

Device not found

5.4. Device interface management

5.4.1. Add an interface to a registered device

5.4.1.1. Request

Endpoint:

POST /api/v1/deviceMgt/devices/<deviceId>/interfaces

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Body:

JSON Params Description

connector

connector id

enabled

define if the interface is enabled or disabled

definition

interface definition. The definition depends on connector (Cf. SMS interface definition or LoRa® interface definition).

Currently, you can only create an SMS or an LoRa® interface, MQTT interface will be auto-provisionned at the first connection.

Example: Create an SMS interface

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/interfaces
{
    "connector": "sms",
    "enabled": true,
    "definition": {
        "msisdn": "33601201201"
    }
}
5.4.1.2. Response

HTTP Code:

200 OK

Body:

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

403

GENERIC_OFFER_DISABLED_ERROR

The requested service is disabled in your offer settings. Please contact a sales representative.

404

DM_DEVICE_NOT_FOUND

Device not found

404

DM_CONNECTOR_UNAVAILABLE

Connector not found or unavailable

409

DM_INTERFACE_DUPLICATE

Interface already exists. Conflict on (connector/nodeId)

Example:

{
    "connector": "sms",
    "nodeId": "33601201201",
    "deviceId": "urn:lo:nsid:sensor:temp001",
    "enabled": true,
    "status": "ONLINE",
    "definition": {
        "msisdn": "33601201201"
    },
    "activity": {},
    "capabilities": {
        "command": {
            "version" : 1,
            "available": true
        },
        "configuration": {
            "available": false
        },
        "resources": {
            "available": false
        }
    },
    "created": "2018-03-02T15:54:33.943Z",
    "updated": "2018-03-02T15:54:33.943Z"
}

5.4.2. List device interfaces

5.4.2.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/<deviceId>/interfaces

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/interfaces
5.4.2.2. Response

HTTP Code:

200 OK

Body:

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

404

DM_DEVICE_NOT_FOUND

Device not found.

Example:

[
  {
    "connector": "sms",
    "nodeId": "33601201201",
    "enabled": true,
    "status": "ONLINE",
    "activity": {},
    "definition" : {
        "msisdn" : "33601201201",
        "serverPhoneNumber" : "12345"
    },
    "capabilities": {
        "command": {
            "version" : 1,
            "available": true
        },
        "configuration": {
            "available": false
        },
        "resources": {
            "available": false
        }
    }
  },
  {
    "connector": "mqtt",
    "nodeId": "urn:lo:nsid:sensor:temp001",
    "enabled": true,
    "status": "ONLINE",
    "lastContact": "2018-03-02T15:57:23.772Z",
    "activity" : {
        "apiKeyId" : "6c2c569d91b5f174f60bd73d",
        "mqttVersion" : 4,
        "mqttUsername" : "json+device",
        "mqttTimeout" : 60,
        "remoteAddress" : "217.0.0.0/44341",
        "lastSessionStartTime" : "2019-07-24T15:09:22.560Z",
        "lastSessionEndTime" : "2019-07-24T16:20:37.333Z",
        "security" : {
            "secured": true,
            "protocol": "TLSv1.2",
            "cipher": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
            "clientCertAuthentication": true,
            "sniHostname": "mqtt.liveobjects.orange-business.com"
        }
    },
    "capabilities": {
        "command": {
            "version" : 1,
            "available": true ("false" if the device is "OFFLINE" or has not suscribed to the topic "dev/cmd")
        },
        "configuration": {
            "version" : 1,
            "available": true ("false" if the device is "OFFLINE" or has not suscribed to the topic "dev/cfg")
        },
        "resources": {
            "version" : 1,
            "available": true ("false" if the device is "OFFLINE" or has not suscribed to the topic "dev/rsc/upd")
        }
    },
    "firmwares" : { (same value as "resources", available for compatibility reasons)
        "MyFW" : "1.0.2"
    },
    "resources" : {
        "MyFW" : "1.0.2"
    }
  }
]

5.4.3. Get interface details

5.4.3.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/<deviceId>/interfaces/<interfaceId>

The interfaceId must respect the following format {connector}:{nodeId}.

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/interfaces/sms:33601201201
5.4.3.2. Response

HTTP Code:

200 OK

Body:

Error case:

HTTP Code Error code message

403

GENERIC_OFFER_DISABLED_ERROR

The requested service is disabled in your offer settings. Please contact a sales representative.

404

DM_CONNECTOR_UNAVAILABLE

Connector not found or unavailable

404

DM_INTERFACE_NOT_FOUND

Interface not found

404

DM_DEVICE_NOT_FOUND

Device not found

Example:

{
        "connector": "sms",
        "nodeId": "33601201201",
    "deviceId": "urn:lo:nsid:sensor:temp001",
        "enabled": true,
        "status": "ONLINE",
        "definition": {
            "msisdn": "33601201201"
        },
        "activity": {
            "lastUplink": {
                "timestamp": "2018-03-05T10:43:46.268Z",
                "serverPhoneNumber": "20259"
            }
        },
    "capabilities": {
        "command": {
            "version" : 1,
            "available": true
    },
        "configuration": {
            "available": false
        },
        "resources": {
            "available": false
        }
    },
    "created": "2018-03-05T10:20:06.404Z",
    "updated": "2018-03-05T10:20:06.408Z"
}

5.4.4. Update an interface

5.4.4.1. Request

Endpoint:

PATCH /api/v1/deviceMgt/devices/<deviceId>/interfaces/<interfaceId>

The interfaceId must respect the following format {connector}:{nodeId}.

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Body:

JSON Params Description

deviceId

Optional. new device identifier

enabled

Optional. define if the interface is enabled or disabled

definition

Optional. new interface definition

Example:

PATCH /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/interfaces/sms:33601201201
{
    "deviceId": "urn:lo:nsid:sensor:temp002",
    "enabled": "false",
    "definition": {
        "encoding": "myDecoder"
    }
}
5.4.4.2. Response

HTTP Code:

200 OK

Body:

Error case:

HTTP Code Error code message

404

DM_INTERFACE_NOT_FOUND

Interface not found

404

DM_DEVICE_NOT_FOUND

Device not found

Example:

{
    "connector": "sms",
    "nodeId": "33601201201",
    "deviceId": "urn:lo:nsid:sensor:temp002",
    "enabled": false,
    "status": "ONLINE",
    "definition": {
        "msisdn": "33601201201",
        "encoding": "myDecoder"
    },
    "activity": {
        "lastUplink": {
            "timestamp": "2018-03-05T10:43:46.268Z",
            "serverPhoneNumber": "20259"
        }
    },
    "capabilities": {
        "command": {
            "version" : 1,
            "available": true
        },
        "configuration": {
            "available": false
        },
        "resources": {
            "available": false
        }
    },
    "created": "2018-03-05T10:20:06.404Z",
    "updated": "2018-03-05T13:51:09.312Z"
}

5.4.5. Delete an interface

5.4.5.1. Request

Endpoint:

DELETE /api/v1/deviceMgt/devices/<deviceId>/interfaces/<interfaceId>

The interfaceId must respect the following format {connector}:{nodeId}.

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

DELETE /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/interfaces/sms:33601201201
5.4.5.2. Response

HTTP Code:

204 NO CONTENT

Error case:

HTTP Code Error code message

403

GENERIC_OFFER_DISABLED_ERROR

The requested service is disabled in your offer settings. Please contact a sales representative.

404

DM_CONNECTOR_UNAVAILABLE

Connector not found or unavailable

404

DM_INTERFACE_NOT_FOUND

Interface not found

404

DM_DEVICE_NOT_FOUND

Device not found

5.5. Connectivity

5.5.1. LoRa® connector

For information about legacy API (v0), please see API LoRa® legacy section.

5.5.1.1. Definitions

devEUI

The global end-device ID of the interface (for more information, see the chapter 6.2.1 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

appEUI

The global application ID of the interface (for more information, see the chapter 6.1.2 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

appKey

The application key of the interface (for more information, see the chapter 6.2.2 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

activationType

OTAA: Over The Air Activation.

profile

profile of the Interface which represents the Class (A or C). Can be specific for an Interface (ex. LoRaMote devices) or generic (ex. LoRaWAN/DemonstratorClasseA or LoRaWAN/DemonstratorClasseC). Please refer to Orange LoRa® device reference. The API GET Profile allows to have the list of available profiles.

encoding

Optional. encoding type of the binary payload sent by the interface, the decoder must be registered first (Cf. "Decoding service" section).

connectivityOptions

connectivity options used for the interface. Supported options are ackUl and tdoa.

connectivityPlan

connectivity plan to use for the interface.

Example:

{
    "devEUI": "0101010210101010",
    "profile": "Generic_classA_RX2SF9",
    "activationType": "OTAA",
    "appEUI": "9879876546543211",
    "appKey": "11223344556677889988776655443322",
    "connectivityOptions" : {
        "ackUl" : true,
        "tdoa" : false
    },
    "connectivityPlan" : "orange-cs/CP_Basic"
}

Important Notice : Some features are only available if you have subscribed to the corresponding offer, so you may have the rights set on your tenant but no access to some features because these features are not activated on your tenant account (check the tenant offer).

If an option is applied to a device, it will be effective only if the option is allowed for the tenant. If both connectivityOptions and connectivityPlan are set, connectivityPlan will be selected. connectivityPlan should be used preferably at connectivityOptions but at least one of two shall be defined. connectivityPlan could be selected among list returned by the API LIST Connectivity plans .

5.5.1.2. Activity
JSON Params Description

lastActivationTs

Optional. last activation date of the interface

lastDeactivationTs

Optional. last deactivation date of the interface

lastSignalLevel

Optional. last signal level : this value is a signal level computed from last uplink. This value is the same as the one showed in the data message (Lora message signalLevel).

avgSignalLevel

Optional. average signal level : provides a level of the signal during the last uplinks transmitted by the device. The value is between 1 and 5 is computed from uplinks history (PER+SNR+ESP quality indicators aggregate). On frame counter reset, the uplinks history and average signal level are reset.

lastBatteryLevel

Optional. last battery level (for more information, see the chapter 5.5 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

lastDlFcnt

Optional. last downlink frame counter

lastUlFcnt

Optional. last uplink frame counter

Example:

{
    "activity": {
        "lastActivationTs": "2018-03-19T13:02:13.482Z",
        "lastActivationTs": "2018-03-20T14:10:26.231Z",
        "lastSignalLevel": 5,
        "avgSignalLevel": 4,
        "lastBatteryLevel": 54,
        "lastDlFcnt": 7,
        "lastUlFcnt": 1
    }
}
5.5.1.3. Status

LoRa® supports the following statuses: REGISTERED, INITIALIZING, INITIALIZED, ACTIVATED, DEACTIVATED, REACTIVATED, CONNECTIVITY_ERROR. The following diagram shows how LoRa® connector sets interfaces' status. The consistency check referred in the diagram is an automatic periodic check that verifies the consistency of information between Live Objets and the LoRa® network provider, it can detect potential problems on an LoRa® interface.

Status state machine in LoRa® connector

Interactive

5.5.1.4. Examples
5.5.1.4.1. Register a device with LoRa® interface

For more explanation on device creation, please see Register a device section.

Request:

POST /api/v1/deviceMgt/devices
{
    "id": "urn:lo:nsid:lora:0101010210101010",
    "tags": ["Lyon", "Test"],
    "name": "myLoraSensor",
    "description": "device with LoRa interface",
    "properties" : {
        "manufacturer": "Orange",
        "model": "LoraSensor"
    },
    "interfaces": [
        {
            "connector": "lora",
            "enabled": true,
            "definition": {
                "devEUI": "0101010210101010",
                "profile": "Generic_classA_RX2SF9",
                "activationType": "OTAA",
                "appEUI": "9879876546543211",
                "appKey": "11223344556677889988776655443322",
                "connectivityOptions" : {
                    "ackUl" : true,
                    "tdoa" : false
                },
                "connectivityPlan" : "orange-cs/CP_Basic"
            }
        }
    ],
    "group": {
        "id": "sWyaL2",
        "path": "/france/lyon"
    }
}

Response:

200 OK
{
    "id": "urn:lo:nsid:lora:0101010210101010",
    "name": "myLoraSensor",
    "description": "device with LoRa interface",
    "tags": [
        "Test",
        "Lyon"
    ],
    "properties": {
        "manufacturer": "Orange",
        "model": "LoraSensor"
    },
    "group": {
        "id": "sWyaL2",
        "path": "/france/lyon"
    },
    "interfaces": [
        {
            "connector": "lora",
            "nodeId": "0101010210101010",
            "enabled": true,
            "status": "REGISTERED",
            "definition": {
                "devEUI": "0101010210101010",
                "profile": "Generic_classA_RX2SF9",
                "activationType": "OTAA",
                "appEUI": "9879876546543211",
                "appKey": "11223344556677889988776655443322",
                "connectivityOptions" : {
                    "ackUl" : true,
                    "tdoa" : false
                },
                "connectivityPlan" : "orange-cs/CP_Basic"
            }
        }
    ],
    "defaultDataStreamId": "urn:lo:nsid:lora:0101010210101010",
    "created": "2018-03-06T13:23:37.712Z",
    "updated": "2018-03-06T13:23:37.945Z"
}
5.5.1.4.2. Add a LoRa® interface to a registered device

For more information on interface addition, please see Add a interface section.

Request:

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/interfaces
{
    "connector": "lora",
    "enabled": true,
    "definition": {
        "devEUI": "0202020220202020",
        "profile": "Generic_classA_RX2SF9",
        "activationType": "OTAA",
        "appEUI": "4573876546543211",
        "appKey": "11113344556677889988776655443322",
        "connectivityOptions" : {
            "ackUl" : true,
            "tdoa" : false
        },
        "connectivityPlan" : "orange-cs/CP_Basic"
    }
}

Response:

201 CREATED
{
    "connector": "lora",
    "nodeId": "0202020220202020",
    "deviceId": "urn:lo:nsid:sensor:temp001",
    "enabled": true,
    "status": "REGISTERED",
    "definition": {
        "devEUI": "0202020220202020",
        "activationType": "OTAA",
        "profile": "Generic_classA_RX2SF9",
        "appEUI": "4573876546543211",
        "connectivityPlan" : "orange-cs/CP_Basic"
    },
    "activity": {},
    "created": "2018-03-06T13:37:31.397Z",
    "updated": "2018-03-06T13:37:31.397Z"
}
5.5.1.4.3. List LoRa® connectivity plans

A connectivity plan defines the interface capabilities and parameters that are needed by the network for access service. These information elements shall be provided by the manufacturer.

5.5.1.4.4. Request

Endpoint:

GET /api/v1/deviceMgt/connectors/lora/connectivities

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json
5.5.1.4.5. Response

HTTP Code:

200 OK

Body:

[ {
  "id" : "orange-cs/CP_Basic",
  "name" : "CP_Basic",
  "parameters" : {
    "nbTransMax" : 3,
    "tdoa" : false,
    "ackUl" : false,
    "sfMax" : 12,
    "sfMin" : 7,
    "nbTransMin" : 1
  }
}, {
  "id" : "orange-cs/CP_ACK",
  "name" : "CP_ACK",
  "parameters" : {
    "nbTransMax" : 3,
    "tdoa" : false,
    "ackUl" : true,
    "sfMax" : 12,
    "sfMin" : 7,
    "nbTransMin" : 1
  }
} ]
HTTP Code Error code message

403

4030

Service is disabled. Please contact your sales entry point.

5.5.1.4.6. Get LoRa® interfaces profiles

An interface-profile defines the interface capabilities and boot parameters that are needed by the network for access service. These information elements shall be provided by the manufacturer.

The profile of the interface which represents the Class (A or C). Can be specific for an Interface (ex. LoRaMote devices) or generic (ex. LoRaWAN/DemonstratorClasseA or LoRaWAN/DemonstratorClasseC). Please refer to Orange LoRa® device reference. The API GET profiles allows to have the list of available profiles.

5.5.1.4.7. Request

Endpoint:

GET /api/v1/deviceMgt/connectors/lora/profiles

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json
5.5.1.4.8. Response

HTTP Code:

200 OK

Body:

[ "JRI", "DP_Generic_AS923_ClassA", "ERCOGENER_EG-IoT", "Sensing_Labs_T_IP68", "ESM 5k ELSYS Class A", "NETVOX_R711_AS923_ClassA", "Connit Pulse", "OCEAN_OBR-L", "ATIM Class A", "Adeunis RF Demonstrator_US_915", "DECENTLAB_DLR2-EU868", "DIGITAL_MATTER_EU868"]

Error case:

HTTP Code Error code message

403

4030

Service is disabled. Please contact your sales entry point.

5.5.2. SMS connector

5.5.2.1. Definitions

msisdn

device msisdn. Number uniquely identifying a subscription in a Global System for Mobile communications.

serverPhoneNumber

Optional. server phone number. Must be defined in the offer settings.

encoding

Optional. name of the decoder that will be used to decode received SMSs, the decoder must be registered first (Cf. "Decoding service" section).

{
    "msisdn": "33601201201",
    "serverPhoneNumber": "20259",
    "encoding": "myDecoder"
}

Msisdn is an international phone number : 6..15 digits starting with country code (ex. '33') and without international prefix (ex. '00').

Dummy examples of phone numbers:

  • Belgium: 32654332211

  • France: 33654332211

  • Spain: 34654332211

  • Romania: 40654332211

  • Slovakia: 421654332211

5.5.2.2. Eligible cellular subscriptions for SMS connectivity

To send and receive SMS messages to/from a device using an SMS interface, this device must have a cellular subscription from the following operators :

  • Orange France

  • Orange Poland

  • Orange Romania

  • Orange Slovakia

  • Orange Spain

5.5.2.3. Activity
JSON Params Description

lastUplink

Optional. last uplink date of the interface

lastDownlink

Optional. last downlink date of the interface

lastUplink and lastDownlink have the following format:

JSON Params Description

timestamp

date of the activity

serverPhoneNumber

server phone number used

Example:

{
    "activity": {
      "lastUplink" : {
        "timestamp" : "2020-09-07T14:50:04.352Z",
        "serverPhoneNumber" : "+3320259"
      },
      "lastDownlink" : {
        "timestamp" : "2020-09-07T14:42:24.180Z",
        "serverPhoneNumber" : "20259"
      }
    }
}
5.5.2.4. Status

The SMS connector supports the following statuses describes in interface status. When an SMS interface is created, its status is set to ONLINE and it will not change. When an SMS interface is disabled, its status is set to DEACTIVATED.

5.5.2.5. Examples
5.5.2.5.1. Register a device with an SMS interface

For more information on device creation, please see Register a device section.

Request:

POST /api/v1/deviceMgt/devices
{
    "id": "urn:lo:nsid:sensor:temp002",
    "tags": ["Lyon", "Test"],
    "name": "mySensor002",
    "description": "moisture sensor",
    "properties" : {
        "manufacturer": "Orange",
        "model": "MoistureSensorV3"
    },
    "interfaces": [
        {
            "connector": "sms",
            "enabled": true,
            "definition": {
                "msisdn": "33600000001",
                "serverPhoneNumber" : "20259"
            }
        }
    ],
    "group": {
        "id": "sWyaL2",
        "path": "/france/lyon"
    }
}

Response:

200 OK
{
    "id": "urn:lo:nsid:sensor:temp002",
    "name": "mySensor002",
    "description": "moisture sensor",
    "tags": [
        "Test",
        "Lyon"
    ],
    "properties": {
        "manufacturer": "Orange",
        "model": "MoistureSensorV3"
    },
    "group": {
        "id": "sWyaL2",
        "path": "/france/lyon"
    },
    "interfaces": [
        {
            "connector": "sms",
            "nodeId": "33600000001",
            "enabled": true,
            "status": "ONLINE",
            "definition": {
                "msisdn": "33600000001",
                "serverPhoneNumber" : "20259"
            }
        }
    ],
    "defaultDataStreamId": "urn:lo:nsid:sensor:temp002",
    "created": "2018-03-06T11:30:42.777Z",
    "updated": "2018-03-06T11:30:42.819Z"
}
5.5.2.5.2. Add an SMS interface to a registered device

For more information on interface addition and example with SMS interface, please see Add a interface section.

Request:

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/interfaces
{
    "connector": "sms",
    "enabled": true,
    "definition": {
      "msisdn": "33600000001",
      "serverPhoneNumber" : "20259"
    }
}

Response:

201 CREATED
{
    "connector": "sms",
    "nodeId": "33600000001",
    "deviceId": "urn:lo:nsid:sensor:temp001",
    "enabled": true,
    "status": "ONLINE",
    "definition": {
      "msisdn": "33600000001",
      "serverPhoneNumber" : "20259"
    },
    "activity": {},
    "created": "2018-03-06T13:37:31.397Z",
    "updated": "2018-03-06T13:37:31.397Z"
}

5.5.3. MQTT connector

For information about MQTT interface and messages that your device can send or receive, please refer to the MQTT device mode.

5.5.3.1. Definition

clientId

device clientId used in mqtt MQTT device mode.

encoding

Optional. name of the decoder that will be used to decode data received from this interface. It will override 'metadata.encoding' value from this device’s data messages. The decoder must be registered first (Cf. "Decoding service" section).

{
    "clientId" : "mydevice_001",
    "encoding" : "myEncoding_v1"
}
5.5.3.2. Activity
JSON Params Description

apiKeyId

Optional. id of the API KEY used for the last device connection

mqttVersion

Optional. mqtt version used by the device mqtt client

mqttUsername

Optional. mqtt username used by the device mqtt client

mqttTimeout

Optional. mqtt timeout configured by the device mqtt client

remoteAddress

Optional. public IP address of the device mqtt client

lastSessionStartTime

Optional. last mqtt session start date

lastSessionEndTime

Optional. last mqtt session end date

security

security information

security has the following format:

JSON Params Description

secured

is (or was) a security protocol used

protocol

Optional. security protocol used

cipher

Optional. cipher suite used

clientCertAuthentication

Optional. is (or was) client certificate authentication used

sniHostname

Optional. hostname provided by the Server Name Indication extension

Example:

{
    "activity" : {
      "apiKeyId" : "5de8d14085a455f5c8525655",
      "mqttVersion" : 4,
      "mqttUsername" : "json+device",
      "mqttTimeout" : 60,
      "remoteAddress" : "217.167.1.65/61214",
      "lastSessionStartTime" : "2020-08-18T15:32:33.510Z",
      "lastSessionEndTime" : "2020-08-18T15:48:51.488Z",
      "security" : {
        "secured": true,
        "protocol": "TLSv1.2",
        "cipher": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
        "clientCertAuthentication": true,
        "sniHostname": "mqtt.liveobjects.orange-business.com"
      }
    }
}
5.5.3.3. Status

MQTT connector supports the ONLINE, OFFLINE, REGISTERED and DEACTIVATED statuses. The following diagram shows how the MQTT connector sets interfaces' status.

Status state machine in MQTT connector

Interactive

5.5.3.4. Examples
5.5.3.4.1. Register a device with an MQTT interface

For more information on device creation, please see Register a device section.

Request:

POST /api/v1/deviceMgt/devices

{
    "id": "urn:lo:nsid:mqtt:mydevice_001",
    "tags": ["Lyon", "Test"],
    "name": "mySensor002",
    "description": "moisture sensor",
    "properties" : {
        "manufacturer": "Orange",
        "model": "MoistureSensorV3"
    },
    "interfaces": [
        {
            "connector": "mqtt",
            "enabled": true,
            "definition": {
                "clientId" : "mydevice_001"
            }
        }
    ],
    "group": {
        "id": "sWyaL2",
        "path": "/france/lyon"
    }
}

Response:

200 OK
{
    "id": "urn:lo:nsid:mqtt:mydevice_001",
    "name": "mySensor002",
    "description": "moisture sensor",
    "tags": [
        "Test",
        "Lyon"
    ],
    "properties": {
        "manufacturer": "Orange",
        "model": "MoistureSensorV3"
    },
    "group": {
        "id": "sWyaL2",
        "path": "/france/lyon"
    },
    "interfaces": [
        {
            "connector": "mqtt",
            "nodeId": "mydevice_001",
            "enabled": true,
            "status": "REGISTERED",
            "definition": {
                "clientId" : "mydevice_001"
            }
        }
    ],
    "defaultDataStreamId": "urn:lo:nsid:mqtt:mydevice_001",
    "created": "2018-03-06T11:30:42.777Z",
    "updated": "2018-03-06T11:30:42.819Z"
}

5.5.4. LwM2M/CoAP Connector

Based on the LwM2M protocol, this connector implements the LwM2M connectivity based on the CoAP messaging protocol.

5.5.4.1. LwM2M interface representation

In addition to the unified representation of Live Objects interfaces, the LwM2M interface has specific fields that can provide information specific to LwM2M devices. :

Interactive

5.5.4.2. Definition

This section contains all security credentials used by the LWM2M device.

"definition": {
    "endpointName": "My_Device_End_Point_Name",
    "security": {
        "mode": "PSK",
        "pskInfo": {
            "identity": "My_PSK_Identity"
        }
    },
    "bootstrap": {
        "managed": "false"
    }
}
Json Params Description

endpointName

Unique identifier of the LWM2M interface.

security.mode

The security mode. Example: "PSK" for Pre-Shared Key mode. The security mode "PSK" for DTLS Pre-Shared Key is currently the only supported security mode.

security.pskInfo.identity

The Pre-Shared key (PSK) identity.

security.pskInfo.secret

The Pre-Shared key (PSK) secret.

bootstrap.managed

Whether the LiveObjects Bootstrap server is allowed to automatically provision information in the interface definition (e.g. the security section) or not. If enabled, the 'security' section must not be set manually.

5.5.4.3. Activity

The activity item provides a data on the connectivity as the device is active (or inactive) on the network and its interact with Live Objects connector.

"activity": {
    "lwm2mVersion": "1.1",
    "remoteAddress": "190.92.12.113",
    "remotePort": 59436,
    "queueMode": false,
    "bindings": [
        "U"
    ],
    "lastRegistrationDate": "2022-02-16T09:08:26.995Z",
    "registrationLifetime": 300,
    "lastUpdateDate": "2022-02-16T09:17:17.301Z",
    "lastBootstrapProvisioningDate": "2022-02-16T09:08:23.621Z"
}
Json Params Description

lwm2mVersion

Supported LwM2M protocol version.

remoteAddress

Used in the IP connections, the IP adress of the device wich have been registered on the LwM2M Live Objects service.

remotePort

Used port.

lastRegistrationDate

Last registration date.

registrationLifetime

Max duration of registered status of the interface. The lifetime is set by LwM2M device connector, when expires, the device is automatically deregistered and the connector change the interface status to OFFLINE. The value is expressed in seconds and can be announced by the the device during the registering (by default : value = 300 seconds).

queueMode

Bolean to set the max of the lifetime timeout before the device go to the sleeping status. This parmeter is set to false, only the the devices with the queuing mode can have the queueMode setted to true.

bindings

List of the network/transport protocols binding supported by the device (Only UDP ="U") will be supported until now.

lastUpdateDate

Last update date of the LwM2M interface parameters.

lastBootstrapProvisioningDate

the last time the device definition was updated by the LiveObjects Bootstrap server (only if bootstrap.managed is true in the interface definition).

5.5.4.4. Status

The LwM2M device interface can supports the following statuses :

Status Description

REGISTERED

The lwm2m interface is registered on LiveObjects, and LwM2M connector is waiting for connection from the device. The Capability TWIN is set to FALSE (device Twin is added at the time as the interface is created)

ONLINE

The lwm2m interface is connected to LwM2M connector and is in active listening. The TWIN capability is set to TRUE.

SLEEPING

The LwM2M interface is connected to LwM2M connector but is no longer in active listening (PSM = Power Saving Mode, used if QueueMode supported by the device).

OFFLINE

The LwM2M interface is disconnected and the LwM2M connector is waiting for the next connection request. The twin capability is set to FALSE.

DEACTIVATED

The LwM2M interface was deactivated by the user.

The following diagram shows how LwM2M connector sets interfaces' status.

Interactive

5.5.4.5. Examples
5.5.4.5.1. Create a LwM2M device

In order to provision a CoAP identity to connect your device, you will have to use the dedicated REST API as described in a following section.

When you need to create a new device, you must use the same way to create every type of Live Objects devices. The LwM2M interface is specific, so you can provision it by following this way:

Request

Endpoint:

POST /api/v1/deviceMgt/devices

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json
{
    "id": "urn:lo:nsid:lwm2m:test12",
    "name": "Lwm2m device",
    "description": "device for test",
    "defaultDataStreamId": "urn:lo:nsid:lwm2m:test13Stream",

    "interfaces": [
        {
            "connector": "lwm2m",
            "enabled": "true",
            "definition": {
                "endpointName": "urn:lo:lwm2m:my_endpoint123",
                "security": {
                    "mode": "PSK",
                    "pskInfo": {
                        "identity": "test_lwm2m_id2",
                        "secret" : "my_psk_secret"
                    }
                }
            }
        }
    ]

}
Refer to definition to learn more about the definition section fields. The credentials endpointName, identity and secret are mandatory.

Body:

JSON Params Description

id

device unique identifier (Cf. device object model)

tags

Optional. (Cf. device object model)

name

Optional. (Cf. device object model)

description

Optional. (Cf. device object model)

defaultDataStreamId

Optional. (Cf. device object model)

properties

Optional. (Cf. device object model)

group

Optional. (Cf. device object model)

interfaces

Optional. (Cf. device object model)

Devices can be registered with one or more chosen interfaces. It mean that the LwM2M device can have other connectivity (MQTT, SMS, Lora or External connector)

Response

{
    "id": "urn:lo:nsid:lwm2m:test12",
    "name": "Lwm2m device",
    "description": "device for test",
    "tags": [],
    "properties": {},
    "group": {
        "id": "root",
        "path": "/"
    },
    "interfaces": [
        {
            "connector": "lwm2m",
            "nodeId": "urn:lo:lwm2m:my_endpoint123",
            "enabled": true,
            "status": "REGISTERED",
            "definition": {
                "endpointName": "urn:lo:lwm2m:my_endpoint123",
                "security": {
                    "mode": "PSK",
                    "pskInfo": {
                        "identity": "test_lwm2m_id2"
                    }
                }
            },
            "capabilities": {
                "configuration": {
                    "available": false
                },
                "command": {
                    "available": false
                },
                "resource": {
                    "available": false
                },
                "twin": {
                    "available": false,
                    "version": 1
                }
            },
            "activity": {},
            "created": "2022-02-17T13:21:52.838Z",
            "updated": "2022-02-17T13:21:52.838Z"
        }
    ],
    "defaultDataStreamId": "urn:lo:nsid:lwm2m:test13Stream",
    "created": "2022-02-17T13:21:52.831Z",
    "updated": "2022-02-17T13:21:52.874Z",
    "activityState": "NOT_MONITORED"
}

The twin capability is automatically loaded by the service but not operational until the first device connection.

For the security raisons, the value of the PSK key is deliberately hidden.

From this moment and after the complete provisioning of the LwM2M interface with the twin capability, the device can perform a register operation.

5.5.4.5.2. Create a LwM2M device managed by the LiveObjects Bootstrap server

If your device is managed by the LiveObjects LwM2M Bootstrap server, the security info will be automatically provisioned by the Bootstrap server during the bootstrap process. To allow this, the device must be created with the bootstrap.managed parameter set to true.

Request

Endpoint:

POST /api/v1/deviceMgt/devices

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json
{
    "id": "urn:lo:nsid:lwm2m:test12",
    "name": "Lwm2m device managed by Bootstrap",
    "description": "device for test",
    "defaultDataStreamId": "urn:lo:nsid:lwm2m:test13Stream",
    "interfaces": [
        {
            "connector": "lwm2m",
            "enabled": "true",
            "definition": {
                "endpointName": "urn:lo:lwm2m:my_endpoint123",
                "bootstrap": {
                    "managed": true
                }
            }
        }
    ]
}
5.5.4.5.3. Checking the LwM2M interface

Endpoint:

GET /api/v1/deviceMgt/devices/my_device_id/interfaces

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json
[
    {
        "connector": "lwm2m",
        "nodeId": "urn:lo:lwm2m:my_endpoint123",
        "enabled": true,
        "status": "REGISTERED",
        "definition": {
            "endpointName": "urn:lo:lwm2m:my_endpoint123",
            "security": {
                "mode": "PSK",
                "pskInfo": {
                    "identity": "test_lwm2m_id2"
                }
            }
        },
        "capabilities": {
            "configuration": {
                "available": false
            },
            "command": {
                "available": false
            },
            "resource": {
                "available": false
            },
            "twin": {
                "available": false,
                "version": 1
            }
        },
        "activity": {},
        "created": "2022-02-17T13:21:52.838Z",
        "updated": "2022-02-17T13:21:52.838Z"
    }
]

5.5.5. External connector

When you will connect devices that can not use a native connectivity in Live Objects (MQTT, LoRa®, SMS, COAP/LWM2M), you can use this API with the MQTT protocol and the external connector interface to connect and manage your devices. The protocol adapters (MQTT ⇐⇒ proprietary protocol) must be developed and maintained by the client.

The external connector mode purpose is to :

  • publish data and devices status

  • manage devices commands : subscribe to command requests and publish command responses

Typically, use this mode when you want to connect your back-end service (where your devices are connected to) to Live Objects.

"Connector" mode usage

Interactive

5.5.5.1. Definition

nodeId

the external connector’s id of the device. This is the shared id with Live Objects that will be used in all communication regarding this device.

encoding

Optional. name of the decoder that will be used to decode data received from this interface. It will override 'metadata.encoding' value from this device’s data messages. The decoder must be registered first (Cf. "Decoding service" section).

{
    "nodeId" : "myDevice_101",
    "encoding" : "myEncoding_v1"
}
5.5.5.2. Register a device with external connector interface

Before registering a device with an external connector interface, you must register a device. For more explanation on device creation, please see Register a device section.

Request:

POST /api/v1/deviceMgt/devices

{
  "id": "urn:lo:nsid:external:measures",
  "name": "sensor #12",
  "description": "MyDeviceMaker sensor #12",
  "defaultDataStreamId": "urn:lo:nsid:external:measures",
  "tags": [
    "demo",
    "sensor"
  ],
  "properties": {
    "manufacturer": "MyDeviceMaker, Inc.",
    "hwVersion": "2.0.1.7-us_64"
  },
  "interfaces": [
    {
      "connector": "x-connector",
      "enabled": true,
      "definition" : {
        "nodeId" : "myDevice1234"
      }
    }
  ]
}

Response:

{
  "id": "urn:lo:nsid:external:measures",
  "name": "sensor #12",
  "description": "MyDeviceMaker sensor #12",
  "tags": [
    "sensor",
    "demo"
  ],
  "properties": {
    "manufacturer": "MyDeviceMaker, Inc.",
    "hwVersion": "2.0.1.7-us_64"
  },
  "group": {
    "id": "root",
    "path": "/"
  },
  "interfaces": [
    {
      "connector": "x-connector",
      "nodeId": "myDevice1234",
      "enabled": true,
      "status": "REGISTERED",
      "definition": {
        "nodeId": "myDevice1234"
      },
      "capabilities": {
        "configuration": {
          "available": false
        },
        "command": {
          "available": false
        },
        "resource": {
          "available": false
        }
      },
      "created": "2020-02-06T09:31:44.461Z"
    }
  ],
  "defaultDataStreamId": "urn:lo:nsid:external:measures",
  "created": "2020-02-06T09:31:44.389Z",
  "updated": "2020-02-06T09:31:44.479Z",
  "activityState": "NOT_MONITORED"
}
When you register your device with an external connector interface, you must set a nodeId field in the definition section. The nodeId must be a string between 1 and 128 characters long, containing no spaces or special characters except :, - or _ . The nodeId must be unique.

When connected through this mode, this is the x-connector interface of the device which is used.

5.5.5.3. Auto-register

By default, the auto-provisioned deviceId for nodeId will be:

urn:lo:nsid:x-connector:{nodeId}

5.5.5.4. Status

The device behind the external connector interface supports only the REGISTERED, ONLINE and OFFLINE statuses. To learn more about how the device publish it’s statuses, see NodeStatus publication.

To learn more about how your external connector work, see "External connector" mode section.

Interactive

The REGISTERED status setted just after the registration step, once the new state is published, the REGISTERED status is no longer publishable in the connector/v1/nodes/{nodeId}/status topic.

6. MQTT protocol

Live Objects supports the MQTT protocol to enable bi-directional (publish/subscribe) communications between devices or applications and the platform.

MQTT must be used with encryption (TLS layer). It is possible to use MQTT without encryption in "device" mode but we strongly recommend a secured connection. MQTT can be used with or without encryption (TLS layer).

Live Objects also supports MQTT over secure WebSocket.

The Live Objects MQTT interface offers multiples "modes":

  • mode "device": dedicated only to device connection use-cases, based on simple JSON messages,

  • mode "connector": dedicated to application that will act as cloud gateway and transfer device status and data from devices toward Live Objects

  • mode "application": useful for your business application to retrieve data or event from Live Objects.

6.1. MQTT protocol support

MQTT protocol level supported is 3.1.1 (cf. MQTT Protocol Specification 3.1.1)

Live Objects acts as a standard MQTT message broker with some limitations:

  • the "will" functionality is not implemented, all "willXXX" flags and headers are not taken into account,

  • the "retain" functionality is not implemented,

  • the "duplicate" flag is not used,

  • the "clean session" flag is not used, the server always starts a new session.

Although Live Objects supports all control packets, QoS levels beyond the exchanges are not all fully guaranteed.

QoS definition guaranteed limitation

0

at most once delivery

yes

no

1

at least once delivery

yes

"duplicate" flag is not used,

2

exactly once delivery

no

same as QoS1


Live Objects has several application behaviors depending on the connection mode (user name) described in the following section. Currently Live objects supports 3 connection modes:

  • "device" mode used to communicate with a native MQTT device.

  • "external connector" mode is an API that allows communication with devices using other protocols not supported by Live Objects. To communicate with Live Objects, these devices are connected with a backend itself connected in "external connector" mode that can translate requests and responses (from / to) MQTT.

  • "application" mode with this mode, Live Objects provides an application mode to allow business applications to use the MQTT API.

6.1.1. Access topics restrictions

The first packet exchanged must be a MQTT CONNECT packet, sent from the client to the MQTT endpoint.

This packet must contain:

  • clientId: usage depends on the "mode", usually the deviceId in "device" mode

  • username: used to select a mode and encoding: (case sensitive)

  • password: an API Key with the mandatory roles depending of the connection mode

  • willRetain, willQoS, willFlag, willTopic, willMessage: ! Not taken into account !,

On reception, Live Objects validates the API key provided.

  • If the API key is valid, then Live Objects returns a MQTT CONNACK message with return code 0x00 Connection Accepted.

  • If the API key is not valid, then Live Objects returns a MQTT CONNACK message with return code 0x04 Connection Refused: bad username or password, and closes the TCP connection.

6.1.2. MQTT keep alive interval and Ping Req/Res

Live Objects answers to MQTT PINGREQ packets with MQTT PINGRES packets: this is a way for the MQTT client to avoid connection timeouts.

A Keep Alive value of zero (0) has the effect of turning off the keep alive mechanism. This means that, in this case, the Server is not required to disconnect the Client on the grounds of inactivity. Note that a Server is permitted to disconnect a Client that it determines to be inactive or non-responsive at any time, regardless of the Keep Alive value provided by that Client.

6.1.3. MQTT Subscribe

Once connected, the client can at any time subscribe and unsubscribe to/from topics.

Live Objects answers with a MQTT SUBACK packet only once all subscriptions could be resolved:

MQTT specification enforce that a MQTT SUBACK is returned even if actual subscription is impossible / forbidden. In Protocol 3.1 the MQTT client cannot be informed that it subscribed to an non existing Topic. In Protocol 3.1.1 the MQTT client will receive MQTT SUBACK with corresponding QoS of 0x80 (Failure).

Live Objects answers to MQTT UNSUBSCRIBE packet with a MQTT UNSUBACK packet only once existing subscriptions have been properly closed.

6.1.4. MQTT Disconnect

Live Objects closes the MQTT / TCP connection when receiving a MQTT DISCONNECT message.

6.1.5. TCP Disconnect

When the TCP connection closes (by client or broker), the broker will close the currently active subscriptions, etc.

6.2. Endpoints

Type Modes Endpoint Description

MQTT

device

mqtt://mqtt.liveobjects.orange-business.com:1883

Unsecure plain MQTT connection. Not recommended for production grade applications. Only available for prototyping on discover offers. Please reach out to us for specific use cases.

MQTTS

mqtts://mqtt.liveobjects.orange-business.com:8883

Secure MQTTS connection. Recommended for device mode. Supports both server and client authentications.

Secure Websocket

wss://mqtt.liveobjects.orange-business.com:443/mqtt

Secure MQTTS connection over Websocket. Supports server authentication only.

MQTTS

application, connector

mqtts://liveobjects.orange-business.com:8883

Secure MQTTS connection. Recommended. Supports both server and client authentications.

Secure Websocket

wss://liveobjects.orange-business.com:443/mqtt

Secure MQTTS connection over Websocket. Supports server authentication only.


Live Objects MQTTS endpoint supports the following cipher suites:

  • TLS_AES_256_GCM_SHA384 for TLS v1.3 only

  • TLS_AES_128_GCM_SHA256 for TLS v1.3 only

  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 for TLS v1.2 only

  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

  • TLS_RSA_WITH_AES_128_GCM_SHA256 for TLS v1.2 only

  • TLS_RSA_WITH_AES_128_CBC_SHA

  • TLS_RSA_WITH_AES_256_CBC_SHA

TLS Server Name Indication (SNI) extension should be used for TLS connections. The SNI host_name field must match the target domain name. TLS connection is refused if host_name is invalid.

Mandatory: For TLS connections, MQTT devices MUST support:

  • At least TLS 1.2

  • Server Name Indication (SNI) extension

It is strongly recommended to use MQTTS for your production environment. Unsecured MQTT connections are not allowed for "Application" and "External connector" modes.

6.2.1. Legacy endpoints

Legacy endpoints liveobjects.orange-business.com are deprecated for device mode. TLS 1.0 and 1.1 on legacy endpoints are not supported. Legacy endpoints will be removed in the future

Type Modes Endpoint Description

MQTT

device

mqtt://liveobjects.orange-business.com:1883

Unsecure plain MQTT connection.

MQTTS

mqtts://liveobjects.orange-business.com:8883

Secure MQTTS connection. Supports both server and client authentications.

Websocket

wss://liveobjects.orange-business.com:443/mqtt

Unsecure plain MQTT connection over Websocket.

6.3. Secure your MQTT connection

6.3.1. Why use Secure MQTT protocol?

Using MQTT with TLS enabled provides privacy and data integrity between your devices/applications and Live Objects. It guarantees that your device/application is communicating with the authentic Live Objects platform, and it prevents a malicious third-party from eavesdropping or tampering. Using secure TLS communication is becoming a de facto standard when communicating over internet as more and more software / operating systems / Hardware refuse to communicate over non-encrypted protocols. Live Objects offers several levels of security that require adapted credentials according to the expected level of security.

6.3.2. MQTT security levels

3 security levels are available, for each one, the authentication is protected by TLS protocol and credentials, the client must have in its truststore and keystore the credentials below :

Authentication\ Credentials

Authentication level

clientId

API_KEY

Root CA certificate

Client certificate

MQTT

basic authentication

MQTTS server authentication

secured authentication

MQTTS server and client authentication

high secured authentication

6.3.3. MQTTS server authentication

A connection to the MQTT server secure endpoints requires that the MQTT clients maintain an up-to-date list of trusted root CA (Certificate Authority) certificates in order to seamlessly handle periodic server certificate updates.

6.3.3.1. Server Root CA certificates
domain name root certificate TLS supported version TLS mandatory options

mqtt.liveobjects.orange-business.com

DigiCert Global Root G2

TLS 1.2 , TLS 1.3

Server Name Indication (SNI)

liveobjects.orange-business.com

DigiCert Global Root CA

TLS 1.2 , TLS 1.3

Your device must have in its truststore the root CA DigiCert Global Root G2. If your device use the Live Objects resource update (firmware) feature, it must also have in its trustore DigiCert Global Root CA.

Your application or external connector must have in its truststore the root CA DigiCert Global Root CA

  • Ensure that you can securely update your device or application software if security vulnerabilities are discovered.

  • Ensure that you have a way to update your root certificate list. Root CA are meant to be long-term certificates but Live Objects might have to change it.

  • Devices must be able to support at least two root CA certificates.

6.3.4. Go further with server and client authentication

Live Objects goes beyond server authentication and implements client authentication based on your own Certification Authority (CA). When enabled for a given API Key, Live Objects will:

  • make sure that only TLS with client authentication is made with this API key when used for MQTT connections

  • make sure that the client certificate has been signed by one of the CA certificates associated to the API key used by the device,

  • verify the identity of the device, by checking that client certificate’s Common Name (CN) matches the device id (in the MQTT client id). This last verification is done for MQTT “device” mode only. (i.e. not for MQTT “application” and “connector” mode)

Live Objects does not provide PKI services, but you can configure your Live Objects account to use your own PKI’s certificates. For the time being, a maximum limit of 10 certificates is set for a tenant.
6.3.4.1. Client certificat CA issuer requirements

Standard extensions

Basic constraints

A CA issuer certificate (which signed your client certificate) must include the basicConstraints value with the CA field set to TRUE. An end user certificate (device) must either set CA to FALSE or exclude the extension entirely.

You must check key usage extension of your CA issuer certificate, here are some common rules to consider :

Extension KeyUsage defined

In this case the KeyUsage extension must contains the permitted key usage with keyCertSign value. It can only be used to sign end user certificates and not further CAs. The end user certificates are used by the devices.

For example:

basicConstraints=CA:TRUE
keyUsage= keyCertSign <--

Extension KeyUsage not defined

Nothing to do. Your CA issuer can sign your devices certificates.

For example:

basicConstraints=CA:TRUE
without KeyUsage extension <--
Otherwise, in case where this rules are not respected, your CA certificate is rejected by Live Objects.
6.3.4.2. How to setup client authentication

The client authentication setup is done in 2 steps:

  • Make Live Objects aware of your Certification Authority (CA) by configuring the CA certificate which used to sign the devices certificates.

  • Check that your CA certificate meets standard requirements.

  • Associate that CA certificate with the API key used by your devices/external connector. This will force all communications to Live Objects using MQTT using that API key to be secured with a client certificate (or it will be rejected).

  • Generate a client certificate, signed with your CA certificate, with the MQTT Client ID as common name (CN) (for MQTT "device" mode only).

Client authentication is only available for MQTTS protocol. MQTT over secure websocket connection does not support client authentication.

1. Configure your Certification Authority’s intermediate certificate on Live Objects

Generate a key pair.

 openssl genrsa -out rootCA.key 2048

Use the key pair to generate your CA certificate.

 openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

Configure your certificate on Live Objects:

POST /api/v0/certificates/ca
 {
   "certificate": "your pem formatted certificate",
   "comment": "my awesome intermediate CA certificate"
 }

This call will return an id for your certificate.

Only provision the CA’s intermediate certificate that directly signed the device Certificate Signing Request (CSR).
 {
  "id": "your_certificate_id"
 }
To get a JSON compliant string of your pem certificate you can use the command line tool jq : cat rootCA.pem | jq -R --slurp

2. Associate this certificate with an Api Key

POST /api/v0/apiKeys/{your-api-key-id}
 {
   "clientCert": {
     "caCertIds": [
       "your-certificate-id1",
       "your-certificate-id2"
     ],
     "required": true
   }
 }
Once a certificate is associated with an Api Key and clientCert.required=true client authenticated MQTTS connection will be mandatory, otherwise the MQTT(s)/websocket connection will be closed with a Bad username or password error.

3. Generate a client certificate for a device with id *your-device-id*

Create a key pair for the device.

 openssl genrsa -out deviceCert.key 2048

Create a certificate signing request from your key pair

 openssl req -new -key deviceCert.key -out deviceCert.csr

Enter the information when prompted

 Country Name (2 letter code) []:
 State or Province Name (full name) []:
 Locality Name (for example, city) []:
 Organization Name (for example, company) []:
 Organizational Unit Name (for example, section) []:
 Common Name (e.g. server FQDN or YOUR name) []: <--------- ENTER YOUR DEVICE URN HERE
 Email Address []:

Generate the device certificate by signing the CSR with your Certification Authority intermediate key.

 openssl x509 -req -in deviceCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out deviceCert.pem -days 365 -sha256

4. Try it

Try your newly configured MQTTS with client configuration by sending a new data on the dev/data topic. We will be using the node mqtt.js client:

mqtt publish -h "mqtt.liveobjects.orange-business.com" --port 8883 -i your-device-id -q 0 -u json+device -C mqtts -t dev/data -m '{"s": "myStreamId", "v": {"temp": 12}}' --key your-cert-private-key --cert your-cert.pem --ca liveObjects.ca.cert.pem -P your-api-key
Once a certificate is associated with an Api Key and clientCert.required=true client authenticated MQTTS connection and MQTTS endpoint usage will be mandatory (see how to use MQTTS).

6.4. Debug MQTT/MQTTS connection

Usual error codes returned by MQTT connector when the client try to connect Live Objects over MQTT protocol :

Authentication

Username (depending on your MQTT mode)

API_KEY (password)

Root CA issuer certificate

API key CA certificate

Client certificate (CN=ClientID)

Connack return code

MQTT (basic authentication/TLS)

bad

bad

none

none

none

0x04 bad credentials

MQTT (basic authentication/TLS)

bad

compliant

none

none

none

0x04 bad credentials

MQTT (basic authentication/TLS)

compliant

bad

none

none

none

0x04 bad credentials

MQTT (basic authentication)

compliant

compliant

none

none

none

0x00 accepted

MQTTS server authentication (TLS)

compliant

compliant

Bad, expired or missing

none

none

0x05 not authorized

MQTTS server authentication (TLS)

compliant

compliant

compliant

none

none

0x00 accepted

MQTTS server and client authentication

compliant

compliant

compliant

compliant

none

0x05 not authorized

MQTTS server and client authentication

compliant

compliant

compliant

compliant

CN =/= client ID

0x05 not authorized

MQTTS server and client authentication

compliant

compliant

compliant

compliant

bad certificate chain

0x05 not authorized

MQTTS server and client authentication

compliant

compliant

compliant

compliant

compliant

0x00 accepted

6.5. "Device" mode

In the "Device" mode, a single MQTT connection is associated with a specific device, and JSON messages can be exchanged to support various Device Management and Data features:

  • notifying of the device connectivity status,

  • notifying of the current device configuration and receiving configuration updates,

  • notifying of the list of current device "resources" (i.e. binary contents) versions, and receiving resource update requests,

  • receiving commands and responding to them,

  • receiving configuration update and responding to it,

  • sending data messages that will be stored.

Device and data management features

Interactive

6.5.1. Connection

When initiating the MQTT connection, to select the "Device" mode you must use the following credentials:

  • clientId: your device unique identifier (cf. Device Identifier (URN)). It must be between 1 and 128 characters long, containing no spaces or special characters except :, - or _

  • username: json+device (case sensitive)

  • password: a valid API key value with DEVICE_ACCESS role

To find more information regarding Live Objects MQTT endpoints, please refer to: MQTT endpoints

We strongly recommend to use a secured connection (MQTTS port 8883).

As soon as the MQTT connection has been accepted by Live Objects, your device will appear as "ONLINE" in Live Objects, with various information regarding the MQTT connection.

Once you close the connection (or if the connection timeouts), your device will appear as "OFFLINE" in Live Objects.

6.5.2. MQTT client identity (URN)

The "clientId" value is used as MQTT client Id must be a valid Live Objects URN and conform to the following format:

urn:lo:nsid:{namespace}:{id}

Where:

  • namespace: your device interface identifier "namespace", used to avoid conflicts between various families of identifier (ex: device model, identifier class "imei", msisdn", "mac", etc.).

  • id: your MQTT custom ID (ex: IMEI, serial number, MAC address, etc.)

"namespace" and "id" must only contain alphanumeric characters (a-z, A-Z, 0-9) or : - _ and must avoid # / !.* | +

Examples:

urn:lo:nsid:tempSensor:17872800001W
urn:lo:nsid:gtw_M50:7891001
urn:lo:nsid:gtw-M200:7891:001

6.5.3. Provisioning

By default, any device with a valid API Key will be able to connect to Live Objects using MQTT protocol.

You can explicitly define the MQTT capability for a device (see 'Device management - Interfaces' in Swagger documentation).

A device with an interface provisioned as "connector:"mqtt" and "enabled":false will not be able to connect to Live Objects through MQTT protocol.

6.5.4. Summary

Authorized MQTT actions for a device:

Direction

Topic

Description

Data message publication

publish to

dev/data

to publish a JSON data message

publish to

dev/v1/data/binary

to publish a binary data message and use a decoder associated to the device’s interface

publish to

dev/v1/data/binary/{encoding}

to publish a binary data message and use a decoder directly with the topic’s name

Command management

subscribe to

dev/cmd

to receive commands and announce remote command compatibility

publish to

dev/cmd/res

to return command responses

Configuration management

publish to

dev/cfg

to notify the current configuration or respond to a config update request

subscribe to

dev/cfg/upd

to receive configuration update requests and announce remote configuration update compatibility

Resource management

publish to

dev/rsc

to notify the current resource versions

subscribe to

dev/rsc/upd

to receive resource update requests and announce remote resource update compatibility

publish to

dev/rsc/upd/res

to respond to resource update requests

publish to

dev/rsc/upd/err

to notify resource update error

An AuditLog message will be sent if the device uses an unauthorized topic.

6.5.5. Data message publication

6.5.5.1. JSON data publication

Data published by devices through MQTT will be processed by the Data enrichment logic.

To publish JSON data into Live Objects, your device must publish on the MQTT topic dev/data the following messages:

{
    "streamId": "<<StreamId>>",
    "timestamp": "<<timestamp>>",
    "model": "<<model>>",
    "value": {
       "<<key>>":"<<value>>"      // a free JSON object
    },
    "location": {
       "lat":<<>>,
       "lon":<<>>,
       "alt":<<>>,
       "accuracy":<<>>,
       "provider":<<>>
    },
    "tags": [<<tag1>>,<<tag2>>,...]
}

Message fields:

  • streamId : identifier of the timeseries this message belongs to,

  • timestamp : (optional) data/time associated with the message, is ISO 8601 format,

  • model : a string identifying the schema used for the "value" part of the message, to avoid conflict at data indexing,

  • value : a free JSON object describing the collected information,

  • tags : list of strings associated to the message used to carry extra-information,

  • lat, lon : latitude, longitude details of the geo location associated with the message (in degrees),

  • alt : height from sea level (in meters),

  • accuracy : the value depends on the combinaison of the tools provided the geo location tools (provider),

  • provider : GPS, cellular or custom

Please read this chapter to have the complete dataMessage description.

Example:

{
    "streamId": "mydeviceTemp1234",
    "timestamp": "2020-10-13T12:15:02Z",
    "model": "tempV2",
    "value": {
        "temp": 12.75,
        "humidity": 62.1,
        "doorOpen": true
    },
    "location": {
        "lat": 48.86667,
        "lon": 2.33333,
        "alt": 35.2,
        "accuracy": 12.3,
        "provider": "GPS"
    },
    "tags": [ "CityNYC", "Prototype" ]
}
6.5.5.2. Binary/hexa data publication

There are two different ways to publish binary data in Live Objects:

Topic Description

dev/v1/data/binary

Useful if you pre-provisioned your device using http API or the web portal. You can specify the "encoding" when the interface is created in the device inventory and use the decoding service. (1)

dev/v1/data/binary/{encoding}

This topic allows to specify directly the "encoding" that is used to match with a decoder name provisioned in Live Objects. With this topic, you don’t have to declare the "encoding" in the device inventory.

In both ways, the "encoding" value must match with the "name" of the decoder you want to use to decode the payload.

(1) The workflow if you prefer to declare the encoding in the device inventory is:

  • Create or update the device’s interface in the device inventory using http API or the web portal. See more information here.

  • Publish to the topic dev/v1/data/binary

In both cases, when pushing binary data, a dataMessage will be generated with the following values:

  • streamId: device urn

  • timestamp: timestamp of MQTT publication

  • value.payload: binary content of MQTT publication as a string in hexBinary www.datypic.com/sc/xsd/t-xsd_hexBinary.html

  • model: if a model is set in the decoder then it will be added. if not, this field is empty

When you publish binary data into Live Objects, only binary or javascript encoders (public or private) can be invoked. The csv decoder would not work in this case.

Please refer to the decoding service section for decoders management.

Examples:

Using the topic dev/v1/data/binary/{encoding}

  • Considering the following binary decoder already provisioned in Live Objects:

{
    "encoding": "my_encoding_v0",
    "format": "float sent_value;",
    "enabled": true,
    "model":"my_encoding_model_v0"
}
  • Sending a MQTT message with following bytes 0x41200000 as a payload on topic dev/v1/data/binary/my_encoding_v0, it will generate and store the following message:

{
    "timestamp" : "2020-10-31T16:15:21.288Z,"
    "streamId" : "urn:lo:nsid:mqtt:123456,"
    "value": {
        "payload": "41200000",
        "sent_value": 10.0
    },
    "model": "my_encoding_model_v0"
}

Using the topic dev/v1/data/binary

  • Declaration of the encoding in the device’s interface using http API: PATCH /api/v1/deviceMgt/devices/{deviceId}/interfaces/{interfaceId}

{
  "connector": "mqtt",
  "nodeId": "123456",
  "enabled": true,
  "status": "ONLINE",
  "definition": {
    "encoding": "my_encoding_v0",        // the name of the decoder that will be used to decode the payload
    "clientId": "123456"
  }
}

Considering the same decoder than in the previous example.

  • Sending a MQTT message with following bytes 0x41200000 as a payload on topic dev/v1/data/binary, it will generate and store the following message:

{
    "timestamp" : "2020-10-31T16:15:21.288Z,"
    "streamId" : "urn:lo:nsid:mqtt:123456,"
    "value": {
        "payload": "41200000",
        "sent_value": 10.0
    },
    "model": "my_encoding_model_v0"
}

6.5.6. Configuration

6.5.6.1. Current Configuration

To notify Live Objects of its current configuration, your device must publish a message to the MQTT topic dev/cfg with the following JSON structure:

{
   "cfg": {
      "<<param1Key>>": {
         "t": "<<param1Type>>",
         "v": <<param1Value>>
      },
      ...
   }
}

Message fields:

  • param{X}Key: the identifier for the device configuration parameters,

  • param{X}Type : indicates the config parameter type between

    • "i32": the value must be an integer from -2,147,483,648 to 2,147,483,647,

    • "u32": the value must a positive integer from 0 to 4,294,967,295,

    • "str": the value is a UTF-8 string,

    • "bin": the value is a base64 encoded binary content,

    • "f64": the value is float (64 bits) value,

  • param{X}Value : the config parameter value.

Example:

{
   "cfg": {
      "log_level": {
         "t": "str",
         "v": "DEBUG"
      },
      "secret_key": {
         "t": "bin",
         "v": "Nzg3ODY4Ng=="
      },
      "conn_freq": {
         "t": "i32",
         "v": 80000
      }
   }
}
6.5.6.2. Update Configuration

When your device is ready to receive configuration updates, it can subscribe to the MQTT topic dev/cfg/upd from where it will receive messages of the following format:

{
   "cfg": {
      "<<param1Key>>": {
         "t": "<<param1Type>>",
         "v": <<param1Value>>
      },
      ...
   },
   "cid": <<correlationId>>
}

Message fields:

  • param{X}Key : The identifier of a device configuration parameter that must be updated,

  • param{X}Type, param{X}Value : the new type and value to apply to the parameter,

  • correlationId : an identifier that your device must set when publishing your new configuration, so that Live Objects updates the status of your configuration parameters.

Example:

{
   "cfg": {
      "logLevel": {
         "t": "bin",
         "v": "DEBUG"
      },
      "connPeriod": {
         "t": "i32",
         "v": 80000
      }
   },
   "cid": 907237823
}
6.5.6.3. Response publication

Once your device has processed a configuration update request, it must return a response to Live Objects by publishing on topic dev/cfg the current value for the parameters that were updated:

{
   "cfg": {
      "<<param1Key>>": {
         "t": "<<param1Type>>",
         "v": <<param1Value>>,
      },
      ...
   },
   "cid": <<correlationId>>
}

Message fields:

  • config : the new configuration of your device (complete or at least all parameters that were in the configuration update request),

  • correlationId : the correlationId of the configuration update request.

Example:

{
   "cfg": {
      "logLevel": {
         "t": "bin",
         "v": "DEBUG"
      },
      "connPeriod": {
         "t": "i32",
         "v": 80000
      }
   },
   "cid": 907237823
}

If the new value for a parameter is the one that was requested in the configuration update request, the parameter will be considered as successfully updated by Live Objects.

If the new value for a parameter is not the one request, the parameter update will be considered as "failed" by Live Objects.

6.5.7. Commands

6.5.7.1. Retrieve the command request

When your device is ready to receive commands, it can subscribe to the MQTT topic dev/cmd from where it can receive the following messages:

{
   "req":  "<<request>>",
   "arg": {
      "<<arg1>>": <<arg1Value>>,
      "<<arg2>>": <<arg2Value>>,
      ...
   },
   "cid":  <<correlationId>>
}

Message fields:

  • request : string identifying the method called on the device,

  • arg{X}, arg{X}Value : name and value (any valid JSON value) of an argument passed to the request call,

  • correlationId : an identifier that must be returned in the command response to help Live Objects match the response and request.

Example:

{
   "req":  "buzz",
   "arg": {
      "durationSec": 100,
      "freqHz":     800.0
   },
   "cid": 12238987
}
6.5.7.2. Response publication

To respond to a command, your device must publish the response to the MQTT topic dev/cmd/res with a message of the following format:

{
   "res": {
      "<<res1>>": "<<res1Value>>",
      "<<res2>>": "<<res2Value>>",
      ...
   },
   "cid":  <<correlationId>>
}

Message fields:

  • res{X}, res{X}Value : optional information returned by the command execution,

  • correlationId : a copy of the command correlationId value.

Example #1:

{
   "res": {
      "done": true
   },
   "cid": 12238987
}

Example #2:

{
   "res": {
      "error": "unknown method 'buzz'"
   },
   "cid": 12238987
}

Any response of the device will set the command state to PROCESSED and the optional information will be available in the command result.

6.5.8. Resources

6.5.8.1. Current Resources publication

Once connected, your device can announce the currently deployed versions of its resources by publishing a message on MQTT topic dev/rsc with the following format:

{
   "rsc": {
      "<<resource1Id>>": {
         "v": "<<resource1Version>>",
         "m": <<resource1Metadata>>
      },
      "<<resource2Id>>": {
         "v": "<<resource2Version>>",
         "m": <<resource2Metadata>>
      },
      ...
   }
}

Message fields:

  • resource{X}Id : resource identifier,

  • resource{X}Version : currently deployed version of this resource,

  • resource{X}Metadata : (JSON object) (optional) metadata associated with this resource, useful to resource update.

Example:

{
   "rsc": {
      "X11_firmware": {
         "v": "1.2",
         "m": {
            "size": <<firmware size in mbytes>>,
            "md5": "<<firmware sign>>",
         }
      },
      "X11_modem_driver": {
         "v": "4.0.M2"
      }
   }
}
6.5.8.2. Resources update

When your device is ready to receive resource update request, it just needs to subscribe to MQTT topic dev/rsc/upd. Then, the device will receive the request as a message in the following JSON format:

{
   "id": "<<resourceId>>",
   "old": "<<resourceCurrentVersion>>",
   "new": "<<resourceNewVersion>>",
   "m": {
      "size": <<firmware size in mbytes>>,
      "md5": "<<firmware sign>>",
   },
   "cid": "<<correlationId>>"
}

Message fields:

  • resourceId : identifier of resource to update,

  • resourceCurrentVersion : current resource version,

  • resourceNewVersion : new resource version, to download an apply,

  • correlationId : an identifier that must be returned in the resource update response to help Live Objects match the response and request.

Example:

{
   "id": "X11_firmware",
   "old": "1.1",
   "new": "1.2",
   "m": {
      "uri": "http://.../firmware/1.2.bin",
      "md5": "098f6bcd4621d373cade4e832627b4f6"
   },
   "cid": 3378454
}
6.5.8.3. Response publication

Once your device receives a "Resource update request", it needs to respond to indicate if it accepts or not the new resource version, by publishing a message on topic dev/rsc/upd/res with the following JSON format:

{
   "res": "<<responseStatus>>",
   "cid": "<<correlationId>>"
}

Message fields:

  • responseStatus : indicates the response status to the resource update request:

    • "OK" : the update is accepted and will start,

    • "UNKNOWN_RESOURCE" : the update is refused, because the resource (identifier) is unsupported by the device,

    • "WRONG_SOURCE_VERSION" : the device is no longer in the "current" (old) resource version specified in the resource update request,

    • "WRONG_TARGET_VERSION" : the device doesn’t support the "target" (new) resource version specified in the resource update request,

    • "INVALID_RESOURCE" : the requested new resource version has incorrect version format or metadata,

    • "NOT_AUTHORIZED" : the device refuses to update the targeted resource (ex: bad timing, "read-only" resource, etc.),

    • "INTERNAL_ERROR" : an error occurred on the device, preventing for the requested resource update,

  • correlationId : copy of the correlationId field from the resource update request.

Example #1:

{
   "res": "OK",
   "cid": 3378454
}

Example #2:

{
   "res": "UNKNOWN_RESOURCE",
   "cid": 778794
}
6.5.8.4. Response error

Device can report a custom resource update error by publishing a message on MQTT topic dev/rsc/upd/err with the following format:

{
   "errorCode":"ERROR_CODE",
   "errorDetails":"error details"
}

Message fields:

  • errorCode : (optional) device error code,

  • errorDetails : device error details

This fields are limited to 256 characters. Characters outside of this limit will be ignored.

Example:

{
   "errorCode":"DEV123.Z_FIRMW_CRC",
   "errorDetails":"error while loading firmware, bad CRC"
}

6.6. "External connector" mode

6.6.1. Connection

When initiating the MQTT connection, to select the "connector" mode you must use the following credentials:

  • clientId: any string between 1 and 128 characters long, containing no spaces or special characters except :, - or _ . The MQTT protocol indicates it must be unique per connection, but Live Objects does not enforce it.

  • username: connector (case sensitive)

  • password: a valid API Key with CONNECTOR_ACCESS role

To find more information regarding Live Objects MQTT endpoints, please refer to: MQTT endpoints

You must use a secured connection (MQTTS port 8883). The MQTT non-secured connection is not supported for "external connector" mode.

6.6.2. Summary

In "connector" mode, you can manage following device actions:

  • NodeStatus: publish in Live Objects a NodeStatus to set the ONLINE/OFFLINE status of the device (i.e. the node) and its capabilities

  • DataMessage: publish in Live Objects a DataMessage sent by the device

  • Command: subscribe to command requests and publish command responses

  • Configuration: handle configuration request or report modifications of a configuration of a device

  • Resource: manage resource update request or report current resource of a device behind the external connector

Direction Topic Description

NodeStatus publication

Publish

connector/v1/nodes/{nodeId}/status

To publish a NodeStatus for a device

Data message publication

Publish

connector/v1/nodes/{nodeId}/data

To publish a device DataMessage (telemetry event) to Live Objects

Commands

Subscribe

connector/v1/requests/command

To subscribe to command requests for devices. Commands can be manage through HTTP APIs.

Publish

connector/v1/responses/command

To publish a device command response

Configurations

Publish

connector/v1/current/configuration

To send a report of an initial configuration of a device to Live Objects

Subscribe

connector/v1/requests/configuration

To be notified (from Live Objects) of a configuration update for a device

Publish

connector/v1/responses/configuration

To respond/acknoledge to a device configuration request

Resources

Publish

connector/v1/current/resource

To send a report of resources current versions (firmware versions) of a device to Live Objects

Subscribe

connector/v1/requests/resource

To be notified (from Live Objects) of a resource version ugrade request

Publish

connector/v1/responses/resource

To respond/acknoledge to a resource version update request

6.6.3. NodeStatus publication

A NodeStatus publication allows to set the ONLINE/OFFLINE status of the device and its capacity to receive or not command requests.

The topic to publish is: connector/v1/nodes/{nodeId}/status

If the nodeId in the publication topic is unknown by Live Objects, a device with this NodeStatus information will be auto-provisioned in the Device inventory.

If the nodeId is already declared for a device in the Device inventory, then this NodeStatus information will update the corresponding device state in the Device inventory.

The link between a DeviceId and a NodeId is described in the Device and connectivity chapter.

The payload of this publication should follow :

NodeStatus publication
{
    "status": "ONLINE",
    "capabilities": {
        "command": {
            "available": true
        },
        "configuration": {
            "available": true
        },
        "resource": {
            "available": true
        }
    },
    "lastContact": "2019-05-20T16:01:47Z",
    "sessionSequenceId": 1,
    "eventSequenceId": 3
}

Only the 'status' field is mandatory.

Field Description

status

(Mandatory). Either 'ONLINE' or 'OFFLINE'.

capabilities.command

(Optional). Define if the device is able to receive commands. If true, you will be able to send commands to this device using the HTTP API.

capabilities.configuration

(Optional). Define if the device is able to receive configuration update. If true, you will be able to send new configurations to this device using the HTTP API.

capabilities.resource

(Optional). Define if the device is able to receive resource update. If true, you will be able to send new resource update to this device using the HTTP API.

lastContact

(Optional). Should follow ISO-8601 format. Set the lastContact information that will be updated in DataManager.

sessionSequenceId

(Optional). If present, the event will be taken into account only if no previous event had a higher sessionSequenceId.

eventSequenceId

(Optional). If present, the event will be taken into account only if no previous event had a higher sessionSequenceId or eventSequenceId.

As messages are asynchronously handled by Live Objects, sessionSequenceId and eventSequenceId mechanism allows to enforce message ordering (only the last status message will be taken into account). If this ordering is mandatory for your application, you should set them. For a unique MQTT session, sessionSequenceId should remain identical; and you can use epoch milliseconds from your application server as eventSequenceId.

If the publication succeeds, Live Objects will acknowledge the message according to the QoS level.

If the publication fails (for ex. because the JSON is badly formatted), Live Objects will nevertheless acknowledge the message according to the QoS level, and an AuditLog message will be sent with failure details.

6.6.4. Messages publication as a device

A DataMessage publication in the "connector" mode allows to send a DataMessage on behalf of a specific device.

The topic to publish is: connector/v1/nodes/{nodeId}/data

The payload of this publication should follow :

DataMessage publication
{
    "streamId": "urn:lo:nsid:detector_A8:12435355",
    "timestamp": "2019-05-20T16:01:47Z",
    "model": "data_v0",
    "value": {
        "temperature" : 14.6,
                "battery" : 53,
                "messageAlert":"low battery"
    },
    "location": {
        "lat": 48.86667,
        "lon": 2.33333,
        "alt": 35.2,
        "accuracy": 12.3,
        "provider": "GPS"
    },
    "tags": [ "production", "london" ]
}
Field Description

streamId

(Optional). The streamId where the data will be stored in; and retrieved using the HTTP store API. If not set, the default streamId set for this device in the Device inventory will be used. Should not contain any of the following character : ' " \ ; { } ( )

timestamp

(Optional). Should follow ISO-8601 format. If not set, current timestamp will be used.

model

(Optional). Can not contains ' ' (space) or '.' (dot) character. Model is needed to be able to use the search APIs on fields inside the value object.

value

(Optional). JSON compliant object. No inner field name should contains '.' (dot) character.

location

(Optional). If set, geo-query will be available through search APIs.

tags

(Optional) List of additional information used to tag the DataMessage

If the publication succeeds, Live Objects will acknowledge the message according to the QoS level.

If the publication fails (for ex. because the JSON is badly formatted), Live Objects will nevertheless acknowledge the message according to the QoS level, and an AuditLog message will be sent with anomaly details.

6.6.4.1. Encoded DataMessage publication

In order to use the decoding capability of Live Objects, a DataMessage must contains additional 'value.payload' and 'metadata.encoding' fields :

Encoded DataMessage publication
{
    "value": {
        "payload": "000003F5000000DD"
    },
    "metadata": {
        "encoding": "twointegers"
    }
}
Field Description

value.payload

(Mandatory). Payload to decode. In case of binary content, HexBinary String representation of the payload to decode.

metadata.encoding

(Mandatory). Encoded format name, that should match the 'encoding' name of the decoder that can process this message.

All other fields of DataMessage (streamId, timestamp, location, tags…​) can also optionally be set in the encoded DataMessage.

An alternative is to set the encoding property in the x-connector device’s interface definition through DeviceManagement APIs.

6.6.5. Commands

You can refer to commands description to have insights on the devices commands workflow. Using external connector mode, the basics are:

  • once connected in external connector mode, subscribe to command requests

  • create a command targeting a specific device using HTTP APIs or the web portal

  • when this device is connected (publishing a NodeStatus message with a command capability set to true), this command request is published into subscribed topic connector/v1/requests/command

  • optionally, publish the device command response

  • the command status is updated, and can be retrieved using HTTP APIs.

6.6.5.1. Retrieve the command request

Your external connector will receive all command requests targeting your devices.

This command requests are created through Live Objects HTTP APIs; please see dedicated section to know more about command requests.

The topic to subscribe is: connector/v1/requests/command

The received message in the subscribed topic has this model:

Command request message
{
    "id": "0f1253df-9b34-4e97-8e1e-457317107271",
    "nodeId": "myDevice",
    "value": {
        "req": "on",
        "args": {
            "level": 75
        }
    },
    "ackMode": "APPLICATIVE"
}
Field Description

id

(Mandatory). Unique id of the command request. The command response will use this id to correlate request and response.

nodeId

(Mandatory). Define the request’s targeted nodeId.

value

(Optional). The command request value that have been set when created through the HTTP API (any JSON Object).

ackMode

(Mandatory). The acknowledgement mode of this command (set when the command is created through the HTTP API). Either NONE, NETWORK or APPLICATIVE.

If ackMode is NETWORK or APPLICATIVE, a command response with the request’s id should be published as described command response section in order to update the command’s status. In this MQTT 'connector' mode, NETWORK and APPLICATIVE ackModes lead to the same behaviour.

6.6.5.2. Response publication

In order to reply to a command request, your external connector should publish to the topic: connector/v1/responses/command.

Command response message
{
    "id": "0f1253df-9b34-4e97-8e1e-457317107271",
    "nodeId": "myDevice",
    "response": {
        "status": "ok",
        "message": {
            "level": 75
        }
    }
}
Field Description

id

(Mandatory). id of the command request that triggered this response.

nodeId

(Mandatory). the nodeId which has generated the response (should be the same as the one in the request).

response

(Optional). This JSON Object will be stored as the command response when retrieved through he HTTP API.

With this response, the command’s status will change to PROCESSED. And if there is other command requests in queue for this device, the next one will be published.

If the publication succeeds, Live Objects will acknowledge the message according to the QoS level.

If the publication fails (for ex. because the JSON is badly formatted), Live Objects will nevertheless acknowledge the message according to the QoS level, and an AuditLog message will be sent with failure details.

6.6.6. Configurations

You can refer to configuration description to have insights on the devices configuration workflow.

Using external connector mode, the basics regarding this feature are:

  • connect to Live Objects MQTT in external connector mode, subscribe to configuration requests on the following topic connector/v1/requests/configuration

  • connect the device (publish a NodeStatus message with a configuration capability set to true),

  • set requested configuration targeting a specific device behind your external connector using HTTP APIs or the web portal

  • a configuration request will be received on the topic you suscribed above

  • when configuration is set on the device, your external connector publishes a device configuration response to connector/v1/responses/configuration

  • the configurations are updated, and can be retrieved using HTTP APIs: liveobjects.orange-business.com/api/v1/deviceMgt/devices/{deviceId}/config

Also, a device can change its configuration by itself. To report a configuration change, your external connector must publish in connector/v1/current/configuration

6.6.6.1. Retrieve the configuration request

Your external connector will receive all configuration requests targeting your devices.

These configuration requests are created through Live Objects HTTP APIs or web portal. Please see dedicated section to know more about configuration requests.

The topic to subscribe is: connector/v1/requests/configuration

The received message on the subscribed topic has this model:

Configuration request message
{
        "nodeId": "9ea64eb7-a5b4-4573-86e3-b6d949dc55a3",
        "targetVersion": 363745365,
        "parameters": {
                "my_param1": {
                        "type": "UINT32",
                        "value": 8035095625792325998
                },
                "my_param2": {
                        "type": "FLOAT",
                        "value": 0.8862329945028716
                },
                "my_param3": {
                        "type": "BINARY",
                        "value": "WldGbE16QXdtRmlPV1pt"
                },
                "my_param4": {
                        "type": "INT32",
                        "value": 1101263487
                },
                "my_param5": {
                        "type": "STRING",
                        "value": "my config as a string"
                }
        }
}
Field Description

nodeId

(Mandatory). Define the request’s targeted nodeId.

targetVersion

(Mandatory). The configuration request version for all provided parameters

parameters

(Mandatory). A JSON object where each field is a parameter name and each value a ParameterValue object. This format is the same that is used by the HTTP APIs. See the our swagger.

6.6.6.2. Response publication

In order to reply to a configuration request, your external connector must publish in the topic: connector/v1/responses/configuration.

configuration request and configuration response have the same format. To acknowledge a configuration request on a specific parameter, the response must contain the same target version and value.

Configuration response message
{
        "nodeId": "9ea64eb7-a5b4-4573-86e3-b6d949dc55a3",
        "targetVersion": 363745365,
        "parameters": {
                "my_param1": {
                        "type": "UINT32",
                        "value": 8035095625792325998
                },
                "my_param2": {
                        "type": "FLOAT",
                        "value": 0.8862329945028716
                }
        }
}

With this response, "my_param1" and "my_param2" are acknowledged. It can be checked on the portal or with HTTP APIs.

If the publication succeeds, Live Objects will acknowledge the message according to the QoS level.

If the publication fails (for ex. because the JSON is badly formatted), Live Objects will nevertheless acknowledge the message according to the QoS level, and an AuditLog message will be sent with failure details.

6.6.6.3. Publish the current device configuration in Live Objects

In addition to these two topics described in the previous chapter, Live Objects allows your external connector to announce current configuration of a device.

The topic to publish is: connector/v1/current/configuration

The message format is the same than before, except that there is no targetVersion.

Current configuration message
{
        "nodeId": "9ea64eb7-a5b4-4573-86e3-b6d949dc55a3",
        "parameters": {
                "my_param4": {
                        "type": "INT32",
                        "value": 123
                },
                "my_param5": {
                        "type": "FLOAT",
                        "value": 0.45562329946543
                }
        }
}

6.6.7. Resources

You can refer to resource description to have more information on the device resources management workflow.

Using external connector mode, the basics regarding this feature are:

  • Connect to Live Objects using MQTTS in external connector mode

  • Connect the device (publish a NodeStatus message with a resource capability set to true)

  • Send to Live Objects the current version of each device resource by publishing on connector/v1/current/resource

  • Subscribe to resources update requests with the following topic connector/v1/requests/resource

  • In order to update a resource for a given device, set its target version with HTTP APIs or the web portal

  • A resource update request will be received on the topic you suscribed above

  • Download the resource with the given resource url

  • Update your device with the resource (firmware)

  • (opt) Inform Live Objects of failure of the update process. Publish a device resource update response to connector/v1/responses/resource

  • When your resource is updated, send to Live Objects the new version of each device resource. publish on connector/v1/current/resource

  • The resource update informations can be retrieved using HTTP APIs: liveobjects.orange-business.com/api/v1/deviceMgt/devices/{deviceId}/resources/updates

6.6.7.1. Be notified of the resources update request

Your external connector will receive all resources update requests targeting your devices.

These resources update requests are created through Live Objects HTTP APIs or web portal. Please see dedicated section to know more about resource update.

The topic to subscribe is: connector/v1/requests/resource

The received message on the subscribed topic has this model:

resource update request message
{
        "nodeId": "CfnpFC6r",
        "resourceId": "my_resource",
        "updateCorrelationId": "5fc0db74e4332f0001aadf0c",
        "sourceVersion": "1.0",
        "targetVersion": "2.0",
        "delivery": {
                "type": "HTTP_DELIVERY",
                "uri": "https://liveobjects.orange-business.com:443/dl/r7n2b87cc6t8l6pst2t7avg1h5",
                "md5": "6dcdc9dcef09d8571994ac1b712b34c0",
                "size": 1024
        }
}
Field Description

nodeId

(Mandatory). Define the request’s targeted nodeId.

resourceId

(Mandatory). The resource id

updateCorrelationId

(Mandatory). The correlation id for this specific resource update

sourceVersion

(Mandatory). The current version of the resource

targetVersion

(Mandatory). The target version for the resource

delivery

Informations needed for resource download

delivery.type

should be HTTP_DELIVERY

delivery.uri

Download URI

delivery.md5

signature (md5) of the raw (non Base64-encoded) resource file

delivery.size

file size in bytes

6.6.7.2. Resource update report publication

In order to send a report to Live Objects on the resource update process, your external connector must publish on the topic: connector/v1/responses/resource.

The response is optional but is useful when an error occurs during the update process in the device side. If the update succeeded in the device side, your external connector must publish the current resources of the device. See the next chapter.
resource update response message
{
        "nodeId": "HA0lQz8R",
        "updateCorrelationId": "5fc10d40e4332f0001aadf39",
        "status": "FAILED",
        "error": {
                "code": "myErrorCode",
                "details": "myErrorDetails"
        }
}
Field Description

nodeId

(Mandatory). Define the request’s targeted nodeId

updateCorrelationId

(Mandatory). The correlation id for this specific resource update (provided by the resource update request)

status

(Mandatory). Only the status "FAILED" is accepted.

error.code

(Optional) in case of failure, error code (String).

error.details

(Optional) in case of failure, error details (String).

The update process status can be retrieved with HTTP API, using Device management - Resources APIs

6.6.7.3. Publish the current device resources' versions in Live Objects

Live Objects allows your external connector to report the current resources' versions of a device. This can be done at any time. When a resource update is done on the device side (firmware update for instance), the device must report this new version in order to update the resource version declared on the Live Object platform.

The topic to publish is: connector/v1/current/resource

Current resource message
{
  "nodeId": "CLcl0F4b",
  "resources": {
    "my_specific_resource": {
      "version": "1.0"
    },
    "my_firmware": {
      "version": "3.2"
    }
  }
}
Field Description

nodeId

(Mandatory). Define the request’s targeted nodeId.

resources

(Mandatory). map of resource names. The "version" field value must be a "string"

6.7. "Application" mode

In addition to the 2 modes available for devices, the MQTT protocol can also be used for data exchange between a business application and Live Objects. In this mode, the protocol is used by a third party application which requires a reliable link with Live Objects.

Due to the specific use of this mode, it is subject to restrictions and security limitations..

To learn more about "application mode" using MQTTS protocol see.

7. LwM2M protocol

7.1. Introduction

LwM2M, for Lightweight Machine 2 Machine, is a communication protocol standard from the Open Mobile Alliance. It was designed specifically for remote device management and telemetry within the Internet of Things. Unlike MQTT, LwM2M fully specifies the application layer for device management and provides an extensive set of standard objects for telemetry data, enabling interoperability between objects and platforms from different vendors. LwM2M supports also optimized protocol headers and payload encodings to reduce bandwidth consumption and extend sensor’s battery lifetime.

Currently Live Objects LwM2M connector uses CoAPs for the message transfer by using IP connectivity and DTLS secure connections. In the future more connectivities and more security mechanisms will be available (TLS, OSCORE).

Live Objects implements 1.1 version of the protocol which includes the main features (the older version 1.0 of LwM2M protocol is also supported), in addition includes the specific features of device management and data management.

Live Objects provide the following features:

  • LwM2M standard features coming from the specification, which are the standardized interfaces between a lwm2m device and a lwm2m server (LiveObjects).

  • Higher Level features (mainly Device Twin) specific to LiveObjects which allows an advanced and industrial management of LwM2M devices and data, and which allows to benefit from all LiveObjects features also for lwm2m devices.

7.2. LwM2M protocol support

In the LwM2M common features, we find the main ones as specified in the OMA 1.0 and 1.1 specifications, here is the supported features as specified in LWM2M specifications.

7.2.1. Supported network stack

Layer Supported protocol

Transport

UDP

Security

DTLS 1.2 (using PSK identity + PSK key)

Session

CoAP (Constrained Application Protocol)

Application

LwM2M 1.0 specifications & LwM2M 1.1 specifications on CoAP

7.2.2. LwM2M 1.0 supported features

Legend

Fully implemented

Not applicable

Not implemented

🚧

On roadmap

Client registration

Feature Live objects implementation

Register

Register update

De-register

Device Management

Feature Live objects implementation

Read

Write

Execute

Create

Delete

Write attributes

🚧

Discover

Information Reporting

Feature Live objects implementation

Observe

Passive cancel observation

Active cancel observation

Notify

Supported format

Feature Live objects implementation

Plain-text

Opaque

Tlv

Json

Resource Model

Feature Live objects implementation

Object

Object instance

Single Resource

Multi-instance Resource

Object Version

Security

Feature Live objects implementation

NoSec

🚧

Pre-Shared-Key

Raw-Public-Key

X.509

Est

Transport binding and mode

Feature Live objects implementation

Udp

Queue Mode

Sms

Access Control

Feature Live objects implementation

Access Control

Attributes

Feature Live objects implementation

Version

Dimension

Minimum Period

Maximum Period

GreateThan

LessThan

Step

7.2.3. LwM2M 1.1 supported features

Legend

Fully implemented

Non applicable

Not implemented

🚧

On roadmap

Device Management

Feature Live objects implementation

Read-Composite

Write-Composite

Registration Live objects implementation

Supported content

format (ct=<format>)

Information Reporting

Feature Live objects implementation

Send

Observe-Composite

Cancel-Observe-Composite

Resource Instance Operation

Registration Live objects implementation

Read

Write

Observe

Cancel observe

Write attributes

Supported additional formats

Resource instance codec tlv txt json opaque cbor senml-json senml-cbor

encoding

decoding

New data type tlv txt json cbor senml-json senml-cbor

Unsigned Integer

coreLnk

New Data Formats Live objects implementation

CBOR

senML-JSON

senML-CBOR

Resource Model

New Attributes Live objects implementation

short server id

server URI

enabler version

epmin/epmax

Security

Encryption type Live objects implementation

OSCORE

🚧

Certificate Usage

Transport binding and mode

Protocol stack Live objects implementation

Tcp

LoRa®

CIoT

🚧

7.2.4. Live Objects integration features

Additionally, the Live Objects service provides the LwM2M device management and specific device representation implemented behind the LwM2M device interface (Live objects connector):

Live objects LwM2M integrated features overview

Interactive

  • Live Objects integration features

    1. LwM2M devices are included in the unified inventory API (covering all connectivities : LwM2M, MQTT, SMS, LoRa, external connector). LwM2M connectivity configuration (include multi-connectivity).

    2. Twin capability management service to manage the LwM2M device objects and stores the latest LwM2M device ressource values.

    3. Custom object management to define and register the OMA owners objects.

  • Specific features

    1. Live Objects exposes an API that can managing the operations on a given device and monitoring the results of each operation.

    2. To improve the usage in a disturbed network environment, retrieving a device representation of a resource and keep this representation updated by the server over a period of time is persistent. when this happens, and after a device re-register, the OBSERVE operations are automatically reactivated then persisted by the TWIN service.

    3. In the other hand, RFC 7641 tries to sync the "most recent state" and doesn’t care about a "complete history". But in Live Objects the complete /part history can be retrieved using the DataRule. The user can configure a datarule, when triggering, the rule generate and store the uplink message sended by the device.

    4. In a bad network environment, the retrieval of resource values from a device and their updating by the server over a period of time can be affected. The resources objects are persistent even when there are many deconnection or packet loss due bad network QOS. When this happens, and after a device re-register, Live Objects automatically reactivate the OBSERVE operations which are then persisted by the TWIN service.

  • Common features used in the Live Objects environment

    1. LwM2M datamessage stream management (Uplink).

    2. LwM2M datamessage decoding.

    3. Firmware update.

    4. Telemetry data sampling in time series, enrichment and pushing to multiple platforms using Live Objects Custom Pipelines and Datamessage Routing.

    5. Telemetry data vizualisation widgets using Live Objects Data Store & Search.

    6. Alarms and notifications on LwM2M device behavior and telemetry data.

7.3. Data formats

Live Objects supports all data formats defined in the LwM2M v1.1 specification.

A client supporting LwM2M v1.0 must support TLV as stated in the LwM2M V1.0 specification (chapter 6.4). A client supporting LwM2M v1.1 must support Plain Text, Opaque, CoRE Link and at least one of SenML CBOR or SenML JSON.
If supporting optional data formats a LwM2M client may inform the server by including them in the Register operation.

When sending a Write Request or a Composite Request, Live Objects encodes the payload with a data format selected from those that are mandatory for the client and those that are declared as supported by the client (sent in the Register operation). The following rules apply:

Table 1. Request format (Write and Composite requests)
LwM2M version request on a singular resource* request on multiple resources* composite request

v1.0

Opaque if declared as supported and the resource is of type opaque

TLV otherwise

TLV

N/A

v1.1

Opaque if the resource is of type opaque

Plain Text otherwise

SenML CBOR if declared as supported

SenML JSON otherwise

SenML CBOR if declared as supported

SenML JSON otherwise

The preferred response data format can be specified by Live Objects for Read, Observe, and their composite variants. If not specified, the client uses its own preferred format. The following rules apply:

Table 2. Preferred response format (Read, Observe and Composite requests)
LwM2M version request on a singular resource* request on multiple resources* composite request

v1.0

not specified

not specified

N/A

v1.1

not specified

not specified

SenML CBOR if declared as supported

SenML JSON otherwise

*Request on a singular resource

Request targeting a single Resource (ex: /3442/0/110) or a multiple Resource Instance (ex: /3442/0/1110/0).

*Request on multiple resources

Request targeting either an Object Instance (ex: /3442/0) or a multiple Resource (ex: /3442/0/1110).

7.4. LwM2M endpoints

7.4.1. CoAP server URI

For the LwM2M protocol, only secured CoAP binding is supported using DTLS Pre-Shared Key (PSK). The command bellow will bind the Live objects LwM2M server to the server CoAP interface. It known as Live objects LwM2M server URI.

    coaps://lwm2m.liveobjects.orange-business.com:5684

7.4.2. Device identifier : Endpoint Name

Known as endpoint client name in OMA specifications. It should be provided to the LwM2M Server during Registration, also should be provided to LwM2M Bootstrap-Server when executing the Bootstrap procedure when is available. This identifier must respect the URN format.

7.4.3. Bootstrap server URI

For the LwM2M protocol, only secured CoAP binding is supported using DTLS Pre-Shared Key (PSK). The command bellow will bind the Live objects LwM2M bootstrap server to the server CoAP interface. It known as Live objects Boststrap LwM2M server URI.

    coaps://bootstrap.lwm2m.liveobjects.orange-business.com:5684

7.5. Secure your LwM2M connection

7.5.1. Security and encryption

To securing CoAP and due to using UDP with datagram packets without connexion, we optimize the computing effort on the device side (power low consumption), the CoAP transport layer uses the DTLS with a Pre-Shared Key (PSK) to secure the communications between Live Objects and the device fleets. This includes the paired "PSK identity" and shared secret to be used with the Live Objects platform.

DTLS 1.2 is used, to provisione and configure your device, you need:

  1. EndPointName

  2. PSK Identity

  3. PSK key (secret)

To learn more, see this section.

As specified in the CoAP rfc7252 specifications, devices should support the Server Name Indication (SNI) to indicate their authority in the SNI HostName field as defined in section 3 of RFC6066. This is needed so that when a host that acts as a virtual server for multiple authorities receives a new DTLS connection, it knows which keys to use for initialise the DTLS session.

7.5.2. DTLS Ciphers suite

During a device register steps, a DTLS session (1.2) use a PSK (Pre-Shared Key) mode. In this case, the device need a mandatory-to-implement cipher suites as specified in the CoAP rfc7252 specifications.

Supported ciphers are (static list) :

Cipher Hex value ID

ECDHE_ECDSA_WITH_AES_128_CCM

0xC0AC

ECDHE_ECDSA_WITH_AES_128_CCM_8

0xC0AE

ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

0xC02B

ECDHE_ECDSA_WITH_AES_256_CCM

0xC0AD

ECDHE_ECDSA_WITH_AES_256_CCM_8

0xC0AF

ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

0xC02C

ECDHE_RSA_WITH_AES_128_GCM_SHA256

0xC02F

ECDHE_RSA_WITH_AES_256_GCM_SHA384

0xC030

ECDHE_PSK_WITH_AES_128_CCM_8_SHA256

0xD003

ECDHE_PSK_WITH_AES_128_CCM_SHA256

0xD005

ECDHE_PSK_WITH_AES_128_GCM_SHA256

0xD001

ECDHE_PSK_WITH_AES_256_GCM_SHA384

0xD002

PSK_WITH_AES_128_CCM

0xC0A4

PSK_WITH_AES_128_CCM_8

0xC0A8

PSK_WITH_AES_128_GCM_SHA256

0x00A8

PSK_WITH_AES_256_CCM

0xC0A5

PSK_WITH_AES_256_CCM_8

0xC0A9

PSK_WITH_AES_256_GCM_SHA384

0x00A9

7.6. LwM2M device register simulation

Once the identity provisioned, the device can perform a register on the server, which mean that the device is ready to receive a LwM2M messages (CoAP). During this request, the device presents its supported object definitions.

The following sample will provide a simulator in Java:

java -jar leshan-client-demo.jar -u lwm2m.liveobjects.orange-business.com:5684 -n <endpoint LWM2M> -i <PSK_identity> -p <PSK_KEY>
Where : -n <endpoint LWM2M>, -i <PSK_identity>, -p <PSK_KEY> hex format.
  • You should see the DeviceTwin in the Parc menu (select LwM2M device twin tab) of your portal.

  • You should be able to apply the operations ( read,write,execute) on a device and see the results in the Parc menu (select LwM2M operation tab) of your portal.

  • If your device can reports value changes while sending data, under certain conditions, you can see the generated datamessages in the data menu (select Data messages tab) of your portal.

  • If your device can’t perform a DNS resolution on lwm2m.liveobjects.orange-business.com, set the IP adress of the endpoint in your device connection config.

  • The lwm2m.liveobjects.orange-business.com endpoint can be change, make sure that you can update it on your device parc if necessary.

7.7. LwM2M bootstrap (beta)

7.7.1. Principle

The Bootstrap is used to provision essential information (like LwM2M server URIs, credentials to authenticate to the LwM2M servers, etc.) into the LwM2M Client to enable it to register with one or more LwM2M Servers. This Bootstrap information is retrieved from the LwM2M Bootstrap Server.

For more information, please refer to the LwM2M specification.


bootstrap
Figure 1. Overview of LwM2M Bootstrap


7.7.1.1. Bootstrap Configuration

A Bootstrap Configuration defines the bootstrap strategy for a set of Bootstrap Entry:

  • RunServers

  • Run’s key management policy

Example of a Bootstrap Config:

{
    "id": "637d00aedca4b9489573de68",
    "name": "BootstrapConfig",
    "description": "This is a bootstrap config",
    "runServers": [
        {
            "id": "myServer",
            "useLiveObjects": false,
            "lwm2mDefinition": {
                "security": {
                    "shortServerId": 1,
                    "lwm2mServerUri": "coaps://myserver:5684",
                    "securityMode": 1
                },
                "server": {
                    "shortServerId": 1,
                    "lifetime": 200,
                    "binding": "S"
                }
            }
        }
    ],
    "created": "2022-11-22T17:02:38.944Z",
    "updated": "2022-11-22T17:02:38.944Z"
}
Field Description

id

Generated Bootstrap configuration unique identifier. Is used to link the configuration to a Bootstrap Entry.

name

User-defined name for the bootstrap config, must not be empty.

description

User-defined description for the bootstrap config.

runServers.id

Run server unique identifier. Will be used also in Bootstrap Entry

runServers.useLiveObjects

If true, the LiveObjects LwM2M URI will be used as lwm2mServerUr and PSK as the securityMode. If false, they have to be defined.

runServers.renewSecurityOnBootstrap

If true, new credentials (e.g. the PSK identity and secret) will be generated at each Bootstrap. Can be set only if useLiveObjects is true.

runServers.lwm2mDefinition

The LwM2M configuration.

runServers.lwm2mDefinition.security

The configuration for the LwM2M Security object (ObjectID=0).

runServers.lwm2mDefinition.security.lwm2mServerUri

Uniquely identifies the LwM2M Server or LwM2M Bootstrap-Server. Present if and only if useLiveObjects is false.

runServers.lwm2mDefinition.security.securityMode

Determines what credentials are being used by the LwM2M Client and the LwM2M Server. Present if and only if useLiveObjects is false. Allowed values :

- 0: PSK.

- 1: RPK.

- 2: CERTIFICATE.

- 3: NO_SEC.

- 4: CERTIFICATE_WITH_EST.

runServers.lwm2mDefinition.security.serverPublicKey

Stores the LwM2M Server’s, respectively LwM2M Bootstrap-Server’s, certificate, public key (RPK mode) or trust anchor. The Certificate Mode Resource determines the content of this resource. Present if and only if useLiveObjects is false.

runServers.lwm2mDefinition.security.smsSecurityMode

Determines which SMS security mode is used:

- 0: Reserved for future use

- 1: DTLS mode (Device terminated) PSK mode assumed

- 2: Secure Packet Structure mode (Smartcard terminated)

- 3: NoSec mode

- 4: Reserved mode (DTLS mode with multiplexing Security Association support)

- 5-203: Reserved for future use

- 204-255: Proprietary modes

runServers.lwm2mDefinition.security.lwm2mServerSmsNumber

MSISDN used by the LwM2M Client to send messages to the LwM2M Server via the SMS binding.

runServers.lwm2mDefinition.security.shortServerId

This identifier uniquely identifies each LwM2M Server configured for the LwM2M Client.

runServers.lwm2mDefinition.security.clientHoldOffTime

The number of seconds to wait before initiating a Client Initiated Bootstrap once the LwM2M Client has determined it should initiate this bootstrap mode.

runServers.lwm2mDefinition.security.bootstrapServerAccountTimeout

The LwM2M Client MUST purge the LwM2M Bootstrap-Server Account after the timeout value given by this resource.

runServers.lwm2mDefinition.security.matchingType

The Matching Type Resource specifies how the certificate or raw public key in the Server Public Key is presented. Four values are currently defined:

- 0: Exact match. This is the default value and also corresponds to the functionality of LwM2M v1.0. Hence, if this resource is not present then the content of the Server Public Key Resource corresponds to this value.

- 1: SHA-256 hash [RFC6234]

- 2: SHA-384 hash [RFC6234]

- 3: SHA-512 hash [RFC6234]

runServers.lwm2mDefinition.security.sni

This resource holds the value of the Server Name Indication (SNI) value to be used during the TLS handshake. When this resource is present then the LwM2M Server URI acts as the address of the service while the SNI value is used for matching a presented certificate, or PSK identity.

runServers.lwm2mDefinition.security.certificateUsage

The Certificate Usage Resource specifies the semantic of the certificate or raw public key stored in the Server Public Key Resource, which is used to match the certificate presented in the TLS/DTLS handshake. The currently defined values are 0 for "CA constraint", 1 for "service certificate constraint", 2 for "trust anchor assertion", and 3 for "domain-issued certificate". When this resource is absent, value (3) for domain issued certificate mode is assumed. More details about the semantic of each value can be found in the security consideration section of the LwM2M specification. Present if and only if useLiveObjects is false.

runServers.lwm2mDefinition.security.dtlsTlsCiphersuite

When this resource is present it instructs the TLS/DTLS client to propose the indicated ciphersuite(s) in the ClientHello of the handshake. A ciphersuite is indicated as a 32-bit integer value. The IANA TLS ciphersuite registry is maintained at www.iana.org/assignments/tls-parameters/tls-parameters.xhtml. As an example, the TLS_PSK_WITH_AES_128_CCM_8 ciphersuite is represented with the following string "0xC0,0xA8". To form an integer value the two values are concatenated. In this example, the value is 0xc0a8 or 49320.

runServers.lwm2mDefinition.server

The configuration for the LwM2M Server object (ObjectID=1).

runServers.lwm2mDefinition.server.shortServerId

Used as link to associate server Object Instance.

runServers.lwm2mDefinition.server.lifetime

Specify the lifetime of the registration in seconds.

runServers.lwm2mDefinition.server.defaultMinimumPeriod

The default value the LwM2M Client should use for the Minimum Period of an Observation

runServers.lwm2mDefinition.server.defaultMaximumPeriod

The default value the LwM2M Client should use for the Maximum Period of an Observation

runServers.lwm2mDefinition.server.disableTimeout

A period to disable the Server. After this period, the LwM2M Client MUST perform registration process to the Server.

runServers.lwm2mDefinition.server.notificationStoringWhenDisabledOrOffline

If true, the LwM2M Client stores “Notify” operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline

runServers.lwm2mDefinition.server.binding

Defines the transport binding configured for the LwM2M Client. It is a list composed of the following elements:

- U: UDP.

- T: TCP.

- S: SMS.

- N: NON_IP.

- Q: Queue Mode (removed since LwM2M 1.1). Note: the bindings UQ, SQ and UQS are allowed, UQSQ and USQ are not.

runServers.lwm2mDefinition.server.apnLink

If this resource is defined, it provides a link to the APN connection profile Object Instance (OMNA registered Object ID:11) to be used to communicate with this server. The instance id must be provided.

runServers.lwm2mDefinition.server.registrationPriorityOrder

The LwM2M Client sequences the LwM2M Server registrations in increasing order of this value. If this value is not defined, registration attempts to this server are not impacted by other server registrations.

runServers.lwm2mDefinition.server.initialRegistrationDelayTimer

The delay before registration is attempted for this LwM2M Server based upon the completion of registration of the previous LwM2M Server in the registration order. This is only applied until the first successful registration after a successful bootstrapping sequence.

runServers.lwm2mDefinition.server.registrationFailureBlock

When set to true and registration to this LwM2M server fails, the LwM2M Client blocks registration to other servers in the order. When set to false, the LwM2M Client proceeds with registration to the next server in the order.

runServers.lwm2mDefinition.server.bootstrapOnRegistrationFailure

If set to true, this indicates that the LwM2M Client should re-bootstrap when either registration is explicitly rejected by the LwM2M Server or registration is considered as failing as dictated by the other resource settings. If set to false, the LwM2M Client will continue with the registration attempts as dictated by the other resource settings.

runServers.lwm2mDefinition.server.communicationRetryCount

The number of successive communication attempts before which a communication sequence is considered as failed.

runServers.lwm2mDefinition.server.communicationRetryTimer

The delay between successive communication attempts in a communication sequence. This value is multiplied by two to the power of the communication retry attempt minus one (2**(retry attempt-1)) to create an exponential back-off.

runServers.lwm2mDefinition.server.communicationSequenceDelayTimer

The delay between successive communication sequences. A communication sequence is defined as the exhaustion of the Communication Retry Count and Communication Retry Timer values. A communication sequence can be applied to server registrations or bootstrapping attempts. MAX_VALUE means do not perform another communication sequence.

runServers.lwm2mDefinition.server.communicationSequenceRetryCount

The number of successive communication sequences before which a registration attempt is considered as failed.

runServers.lwm2mDefinition.server.trigger

Using the Trigger Resource a LwM2M Client can indicate whether it is reachable over SMS (value set to 'true') or not (value set to 'false')

runServers.lwm2mDefinition.server.preferredTransport

Only a single transport binding SHALL be present. When the LwM2M client supports multiple transports, it MAY use this transport to initiate a connection. This resource can also be used to switch between multiple transports e.g. a non-IP device can switch to UDP transport to perform firmware updates.

runServers.lwm2mDefinition.server.muteSend

If true or the Resource is not present, the LwM2M Client Send command capability is de-activated. If false, the LwM2M Client Send Command capability is activated.

Note : runServers.lwm2mDefinition.security.shortServerId and runServers.lwm2mDefinition.server.shortServerId must be equal.

7.7.1.2. Bootstrap Entry

A Bootstrap Entry is link to a Bootstrap Config and contains:

  • the credentials used to authenticate to the LwM2M Bootstrap server

  • the parameters of the Bootstrap Config specific to an endpoint, namely the credentials used to authenticate to the LwM2M Run server

  • information about past Bootstrap sessions

Example of a Bootstrap Entry:

{
    "endpointName": "my_endpoint",
    "security": {
        "mode": "PSK",
        "pskInfo": {
            "identity": "my_endpoint",
            "secret": "0123456789ABCDEF0123456789ABCDEF"
        }
    },
    "definition": {
        "bootstrapConfigId": "637d00cfdca4b9489573de69",
        "runServers": [
            {
                "id": "LOServer",
                "security": {
                    "pskInfo": {
                        "identity": "my_endpoint",
                        "secret": "0123456789ABCDEF0123456789ABCDEF"
                    }
                }
            }
        ]
    },
    "activity": {
        "status": "FINISHED",
        "endpointBootstrapConfig": {
            "runServers": [
                {
                    "security": {
                        "shortServerId": 1,
                        "lwm2mServerUri": "coaps://lwm2m.liveobjects.orange-business.com:5684",
                        "securityMode": 0,
                        "publicKeyOrIdentity": "urn:imei:000000000000000",
                        "secretKey": "***",
                        "clientHoldOffTime": 0,
                        "bootstrapServerAccountTimeout": 0
                    },
                    "server": {
                        "shortServerId": 1,
                        "lifetime": 3600,
                        "defaultMinimumPeriod": 0,
                        "defaultMaximumPeriod": 500,
                        "disableTimeout": 0,
                        "notificationStoringWhenDisabledOrOffline": true,
                        "binding": "U"
                    }
                }
            ]
        },
        "bootstrapRequestCount": 6,
        "lastBootstrapRequestDate": "2023-01-13T11:50:28.086Z",
        "bootstrapFinishCount": 4,
        "lastBootstrapFinishDate": "2023-01-13T11:50:36.221Z"
    },
    "created": "2023-01-11T17:53:57.021Z",
    "updated": "2023-01-13T11:50:36.227Z"
}
Field Description

endpointName

The endpoint client name.

security

The security information to authenticate to the LwM2M Bootstrap server.

security.mode

The security mode used to authenticate to the LwM2M Bootstrap server.

security.pskInfo

The Pre-Shared Key (PSK) information to authenticate to the LwM2M Bootstrap server.

security.pskInfo.identity

The "bootstrap" PSK Identity.

security.pskInfo.secret

The "bootstrap" PSK secret key.

definition

The Bootstrap Config parameters for the endpoint (must be defined for the Bootstrap to work).

definition.bootstrapConfigId

The identifier of the Bootstrap Config to use for the endpoint (must be defined for the Bootstrap to work).

definition.runServers

The parameters for the runServers defined in Bootstrap Config.

definition.runServers.id

The identifier of the runServer defined in Bootstrap Config.

definition.runServers.security

The security information to authenticate to the LwM2M Run server.

definition.runServers.security.pskInfo

The Pre-Shared Key (PSK) information to authenticate to this LwM2M Run server.

definition.runServers.security.pskInfo.identity

The "run" PSK Identity. If it is not defined, the Identity of the PSK used to authenticate to the LwM2M Bootstrap server is used.

definition.runServers.security.pskInfo.secret

The "run" PSK secret key.

activity

Information about past Bootstrap session.

activity.status

status regarding the Bootstrap

activity.endpointBootstrapConfig

The last Bootstrap configuration that was sent to the LwM2M client. Refer to the Bootstrap Config for the description of each parameter except for publicKeyOrIdentity and secretKey described below.

activity.endpointBootstrapConfig.publicKeyOrIdentity

The LwM2M Client’s certificate, public key (RPK mode) or PSK Identity (PSK mode).

activity.endpointBootstrapConfig.secretKey

The secret key (PSK mode) or private key (RPK or certificate mode).

activity.bootstrapRequestCount

The number of times a Bootstrap sequence has been initiated (a Bootstrap-Request has been received by the LwM2M server).

activity.lastBootstrapRequestDate

The last time a Bootstrap sequence was initiated (a Bootstrap-Request has been received by the LwM2M server).

activity.bootstrapFinishCount

The number of times a Bootstrap sequence has been successfully completed (a Bootstrap-Finish has been sent by the LwM2M server).

activity.lastBootstrapFinishDate

The last time a Bootstrap sequence has been successfully completed (a Bootstrap-Finish has been sent by the LwM2M server).

created

Date on which the Bootstrap Entry was created.

updated

Date on which the Bootstrap Entry was last updated.

7.7.1.3. Bootstrap Sequence
7.7.1.3.1. General case

Before being able to bootstrap a device, it is needed to provision a Bootstrap Entry for the device and link it to a Bootstrap Config.
The Bootstrap sequence starts with the device sending a Bootstrap-Request (preceded by a DTLS Handshake). A Bootstrap-Discover is sent by LiveObjects to be able to know which Security Object instance holds the Bootstrap server information. The Security, Server and OSCORE Objects are deleted. The Security and Server Objects are then written using the parameters defined in the Bootstrap Config and the credentials defined in the Bootstrap Entry.
The Bootstrap sequence ends with LiveObjects sending a Bootstrap-Finish. The device can then register to the LwM2M Run servers.


Bootstrap sequence
Figure 2. Bootstrap sequence diagram


The Bootstrap status is visible in the Bootstrap Entry. The status evolves as follows during the Bootstrap sequence:


Bootstrap sequence
Figure 3. Bootstrap state machine


7.7.1.3.2. Using LiveObjects as Run Server

To use LiveObjects as Run Server, the Bootstrap Config must be created with the parameter useLiveObjects set to true. Refer to this Bootstrap Config creation example. A device must be created (with the same endpoint name as the Bootstrap Entry). The device can be declared as being managed by the LiveObjects Bootstrap Server (bootstrap.managed = true and w/o security info) or not (bootstrap.managed = false and w/ security info). Refer to: LwM2M Device or LwM2M Device managed by Bootstrap creation examples. If the device is created with bootstrap.managed = true (and in the same tenant as the Entry), the security info will be automatically provisioned in the LiveObjects device representation upon bootstrapping. Otherwise, they must be provisioned manually during the device creation, and they will be checked during bootstrap (i.e. do they match the security info that were provisioned in the Bootstrap Entry and that will be set on the physical device). If an error occurs during the automatic provisioning of the security info or if there is a security info mismatch, the Bootstrap sequence will fail. After a successful Bootstrap sequence, the device will register with the LiveObjects LwM2M Run server.


Bootstrap sequence
Figure 4. Bootstrap sequence using LiveObjects as Run Server


7.7.1.3.3. With credentials generated at Bootstrap time

The following diagram describes the sequence when the run credentials are generated at Bootstrap time.
The Bootstrap Config has to be created with the renewSecurityOnBootstrap parameter set to true. Refer to this Bootstrap Config creation example. The Bootstrap Entry should be created without Run credentials (otherwise they will be just be ignored).
A device must be created on LiveObjects with the bootstrap.managed parameter set to true (and with the same endpoint name and on the same account as the Bootstrap Entry). Refer to this Device creation example.
At each Bootstrap new credentials will be generated and automatically provisioned in the LiveObjects device representation. If an error occurs during the credentials provisioning, the Bootstrap sequence will fail. After a successful Bootstrap sequence, the device will register with the LiveObjects LwM2M Run server using the generated credentials.


Bootstrap sequence
Figure 5. Bootstrap sequence with credentials generated at bootstrap time


7.7.2. Bootstrap Configurations API

This section includes API call examples for the Bootstrap Configs management.

You can refer to the swagger documentation to list all available APIs.

7.7.2.1. Create a bootstrap config

Example:

POST /api/v1/bootstrap/lwm2m/configs
{
    "name" : "BootstrapConfig",
    "description" : "This is a bootstrap config",
    "runServers" : [
        {
            "id" : "myServer",
            "useLiveObjects" : false,
            "lwm2mDefinition" : {
                "security" : {
                    "shortServerId" : 1,
                    "lwm2mServerUri" : "coaps://myserver:5684",
                    "securityMode" : 1
                },
                "server" : {
                    "shortServerId" : 1,
                    "lifetime" : 200,
                    "binding" : "S"
                }
            }
        }
    ]
}

Response

201 CREATED
{
    "id": "637d00aedca4b9489573de68",
    "name": "BootstrapConfig",
    "description": "This is a bootstrap config",
    "runServers": [
        {
            "id": "myServer",
            "useLiveObjects": false,
            "lwm2mDefinition": {
                "security": {
                    "shortServerId": 1,
                    "lwm2mServerUri": "coaps://myserver:5684",
                    "securityMode": 1
                },
                "server": {
                    "shortServerId": 1,
                    "lifetime": 200,
                    "binding": "S"
                }
            }
        }
    ],
    "created": "2022-11-22T17:02:38.944Z",
    "updated": "2022-11-22T17:02:38.944Z"
}
7.7.2.2. Create a LiveObjects bootstrap config

This example will produce a bootstrap config with the LiveObjects LwM2M uri as lwm2mServerUri and PSK as the securityMode.

Example:

POST /api/v1/bootstrap/lwm2m/configs
{
    "name": "LOBootstrapConfig",
    "description": "This is a LO bootstrap config",
    "runServers": [
        {
            "id": "LOServer",
            "useLiveObjects": true,
            "renewSecurityOnBootstrap": false,
            "lwm2mDefinition": {
                "security": {
                    "shortServerId": 1
                },
                "server": {
                    "shortServerId": 1,
                    "lifetime": 300,
                    "binding": "U"
                }
            }
        }
    ]
}

Response

201 CREATED
{
    "id": "637d00cfdca4b9489573de69",
    "name": "LOBootstrapConfig",
    "description": "This is a LO bootstrap config",
    "runServers": [
        {
            "id": "LOServer",
            "useLiveObjects": true,
            "renewSecurityOnBootstrap": false,
            "lwm2mDefinition": {
                "security": {
                    "shortServerId": 1
                },
                "server": {
                    "shortServerId": 1,
                    "lifetime": 300,
                    "binding": "U"
                }
            }
        }
    ],
    "created": "2022-11-22T17:03:11.197Z",
    "updated": "2022-11-22T17:03:11.197Z"
}
7.7.2.3. Create a LiveObjects bootstrap config with credentials generation

This example will produce a bootstrap config with the LiveObjects LwM2M uri as lwm2mServerUri and PSK as the securityMode.

A new run Pre-Shared Key will be generated (both the id and the secret) at each Bootstrap.

Example:

POST /api/v1/bootstrap/lwm2m/configs
{
    "name": "LOBootstrapConfig",
    "description": "This is a LO bootstrap config",
    "runServers": [
        {
            "id": "LOServer",
            "useLiveObjects": true,
            "renewSecurityOnBootstrap": true,
            "lwm2mDefinition": {
                "security": {
                    "shortServerId": 1
                },
                "server": {
                    "shortServerId": 1,
                    "lifetime": 300,
                    "binding": "U"
                }
            }
        }
    ]
}

Response

201 CREATED
{
    "id": "637d00cfdca4b9489573de69",
    "name": "LOBootstrapConfig",
    "description": "This is a LO bootstrap config",
    "runServers": [
        {
            "id": "LOServer",
            "useLiveObjects": true,
            "renewSecurityOnBootstrap": true,
            "lwm2mDefinition": {
                "security": {
                    "shortServerId": 1
                },
                "server": {
                    "shortServerId": 1,
                    "lifetime": 300,
                    "binding": "U"
                }
            }
        }
    ],
    "created": "2022-11-22T17:03:11.197Z",
    "updated": "2022-11-22T17:03:11.197Z"
}

7.7.3. Bootstrap Entries API

This section includes API call examples for the Bootstrap Entries management.

You can refer to the swagger documentation to list all available APIs.

7.7.3.1. Create a bootstrap entry

Example:

POST /api/v1/bootstrap/lwm2m/entries
{
    "endpointName": "my_endpoint",
    "security": {
        "mode": "PSK",
        "pskInfo": {
            "identity": "my_endpoint",
            "secret": "0123456789ABCDEF0123456789ABCDEF"
        }
    },
    "definition": {
        "bootstrapConfigId": "63b6dd0d4a3f024c43b88c31",
        "runServers": [
            {
                "id": "LOServer",
                "security": {
                    "pskInfo": {
                        "identity": "my_endpoint",
                        "secret": "0123456789ABCDEF0123456789ABCDEF"
                    }
                }
            }
        ]
    }
}

Response

201 CREATED
{
    "endpointName": "my_endpoint",
    "security": {
        "mode": "PSK",
        "pskInfo": {
            "identity": "my_endpoint"
        }
    },
    "definition": {
        "bootstrapConfigId": "63b6dd0d4a3f024c43b88c31",
        "runServers": [
            {
                "id": "LOServer",
                "security": {
                    "pskInfo": {
                        "identity": "my_endpoint",
                        "secret": "***"
                    }
                }
            }
        ]
    },
    "activity": {
        "status": "NEVER_REQUESTED",
        "bootstrapRequestCount": 0,
        "bootstrapFinishCount": 0
    },
    "created": "2023-01-10T16:57:38.299Z",
    "updated": "2023-01-10T16:57:38.299Z"
}
7.7.3.2. Update the bootstrapConfigId in a bootstrap entry

Example:

PUT /api/v1/bootstrap/lwm2m/entries/my_endpoint/definition/bootstrapConfigId
"6374fc20c63f896edc10726d"

Response

200 OK
{
    "endpointName": "my_endpoint",
    "security": {
        "mode": "PSK",
        "pskInfo": {
            "identity": "my_endpoint"
        }
    },
    "definition": {
        "bootstrapConfigId": "6374fc20c63f896edc10726d",
        "runServers": [
            {
                "id": "LOServer",
                "security": {
                    "pskInfo": {
                        "identity": "my_endpoint",
                        "secret": "***"
                    }
                }
            }
        ]
    },
    "activity": {
        "status": "NEVER_REQUESTED",
        "bootstrapRequestCount": 0,
        "bootstrapFinishCount": 0
    },
    "created": "2023-01-10T16:57:38.299Z",
    "updated": "2023-01-10T18:03:05.488Z"
}
7.7.3.3. Get a bootstrap entry

Example:

GET /api/v1/bootstrap/lwm2m/entries/my_endpoint?showSecuritySecrets=true

Response

200 OK
{
    "endpointName": "my_endpoint",
    "security": {
        "mode": "PSK",
        "pskInfo": {
            "identity": "my_endpoint"
        }
    },
    "definition": {
        "bootstrapConfigId": "6374fc20c63f896edc10726d",
        "runServers": [
            {
                "id": "LOServer",
                "security": {
                    "pskInfo": {
                        "secret": "0123456789ABCDEF0123456789ABCDEF"
                    }
                }
            }
        ]
    },
    "activity": {
        "status": "FINISHED",
        "endpointBootstrapConfig": {
            "runServers": [
                {
                    "security": {
                        "shortServerId": 1,
                        "lwm2mServerUri": "coaps://lwm2m.liveobjects.orange-business.com:5684",
                        "securityMode": 0,
                        "publicKeyOrIdentity": "my_endpoint",
                        "secretKey": "0123456789ABCDEF0123456789ABCDEF",
                        "clientHoldOffTime": 0,
                        "bootstrapServerAccountTimeout": 0
                    },
                    "server": {
                        "shortServerId": 1,
                        "lifetime": 3600,
                        "defaultMinimumPeriod": 0,
                        "defaultMaximumPeriod": 500,
                        "disableTimeout": 0,
                        "notificationStoringWhenDisabledOrOffline": true,
                        "binding": "U"
                    }
                }
            ]
        },
        "bootstrapRequestCount": 1,
        "lastBootstrapRequestDate": "2023-01-10T18:05:23.693Z",
        "bootstrapFinishCount": 1,
        "lastBootstrapFinishDate": "2023-01-10T18:05:31.907Z"
    },
    "created": "2023-01-10T16:57:38.299Z",
    "updated": "2023-01-10T18:03:05.488Z"
}
7.7.3.4. List bootstrap entries

Example:

GET /api/v1/bootstrap/lwm2m/entries?limit=10&bookmarkEndpointName=my_endpoint

Response

200 OK
[
    {
        "endpointName": "urn:imei:000000000000000",
        "security": {
            "mode": "PSK",
            "pskInfo": {
                "identity": "urn:imei:000000000000000"
            }
        },
        "definition": {
            "bootstrapConfigId": "63bbf9244bdab8538b9adcae",
            "runServers": [
                {
                    "id": "LOServer",
                    "security": {
                        "pskInfo": {
                            "secret": "***"
                        }
                    }
                }
            ]
        },
        "activity": {
            "status": "FINISHED",
            "endpointBootstrapConfig": {
                "runServers": [
                    {
                        "security": {
                            "shortServerId": 1,
                            "lwm2mServerUri": "coaps://lwm2m.liveobjects.orange-business.com:5684",
                            "securityMode": 0,
                            "publicKeyOrIdentity": "urn:imei:000000000000000",
                            "secretKey": "***",
                            "clientHoldOffTime": 0,
                            "bootstrapServerAccountTimeout": 0
                        },
                        "server": {
                            "shortServerId": 1,
                            "lifetime": 3600,
                            "defaultMinimumPeriod": 0,
                            "defaultMaximumPeriod": 500,
                            "disableTimeout": 0,
                            "notificationStoringWhenDisabledOrOffline": true,
                            "binding": "U"
                        }
                    }
                ]
            },
            "bootstrapRequestCount": 6,
            "lastBootstrapRequestDate": "2023-01-13T11:50:28.086Z",
            "bootstrapFinishCount": 4,
            "lastBootstrapFinishDate": "2023-01-13T11:50:36.221Z"
        },
        "created": "2023-01-11T17:53:57.021Z",
        "updated": "2023-01-13T11:50:36.227Z"
    },
    {
        "endpointName": "urn:imei:000000000000001",
        "security": {
            "mode": "PSK",
            "pskInfo": {
                "identity": "urn:imei:000000000000001"
            }
        },
        "definition": {
            "bootstrapConfigId": "63bbf9244bdab8538b9adcae",
            "runServers": [
                {
                    "id": "LOServer",
                    "security": {
                        "pskInfo": {
                            "secret": "***"
                        }
                    }
                }
            ]
        },
        "activity": {
            "status": "FINISHED",
            "endpointBootstrapConfig": {
                "runServers": [
                    {
                        "security": {
                            "shortServerId": 1,
                            "lwm2mServerUri": "coaps://lwm2m.liveobjects.orange-business.com:5684",
                            "securityMode": 0,
                            "publicKeyOrIdentity": "urn:imei:000000000000001",
                            "secretKey": "***",
                            "clientHoldOffTime": 0,
                            "bootstrapServerAccountTimeout": 0
                        },
                        "server": {
                            "shortServerId": 1,
                            "lifetime": 3600,
                            "defaultMinimumPeriod": 0,
                            "defaultMaximumPeriod": 500,
                            "disableTimeout": 0,
                            "notificationStoringWhenDisabledOrOffline": true,
                            "binding": "U"
                        }
                    }
                ]
            },
            "bootstrapRequestCount": 13,
            "lastBootstrapRequestDate": "2023-01-13T12:30:00.594Z",
            "bootstrapFinishCount": 4,
            "lastBootstrapFinishDate": "2023-01-13T12:30:00.912Z"
        },
        "created": "2023-01-13T10:22:41.821Z",
        "updated": "2023-01-13T12:30:00.921Z"
    }
]

7.7.4. Bootstrap entries mass import tutorial

The mass import will be fully available soon on the Live Objects portal, but you can already use our API to import batches of bootstrap entries into Live Objects from a .csv file with the help of Postman, a popular and free API toolbox. Simply follow the step by step tutorial below, you do not need any development skills for this.

7.7.4.1. How to import a list of bootstrap entries from a (CSV file)
7.7.4.1.1. Requirements
  1. Install Postman on your desktop : You can download it from this link download Postman

  2. Create an Api key with "customized" profil + DEVICE_R and DEVICE_W roles : here is the API key configuration requirements, and here is how to create an API key if you don’t have it.

  3. set your Api Key value in the key tab.

Interactive

  1. If you don’t have a bootstrap configuration, create a new one, and save the id.

7.7.4.1.2. Build a list of entries under CSV format file
field endpointName pskInfo.identity pskInfo.secret bootstrapConfigId runServers.id runServers.security.pskInfo.identity runServers.security.pskInfo.secret

entry1

my_endpointName1

pskIdentity1

secret1

bootstrap_configId

runServers.id

runServers.security.pskInfo.identity1

runServers.security.pskInfo.secret1

entry2

my_endpointName2

pskIdentity2

secret2

bootstrap_configId

runServers.id

runServers.security.pskInfo.identity2

runServers.security.pskInfo.secret2

Here is a CSV template : to be completed by your device entries.
The header column of your CSV should contain the exact field id and it will be instantiated during the script execution in both the script and the endpoint.
7.7.4.1.3. Build and write the postman script
  1. We are using this endpoint to create a postman request:

    POST api/v1/bootstrap/lwm2m/entries/
  2. In postman, put your Api key : in the "Headers" window, add in the KEY cells, the variable x-api-key and set it with the Api key value.

  3. In the "Body" window, set this Json :

    {
        "endpointName": "{{endpointName}}",
        "security": {
            "mode": "PSK",
            "pskInfo": {
                "identity": "{{pskInfo.identity}}",
                "secret": "{{pskInfo.secret}}"
            }
        },
        "definition": {
            "bootstrapConfigId": "{{bootstrapConfigId}}",
            "runServers": [
                {
                    "id": "{{runServers.id}}",
                    "security": {
                        "pskInfo": {
                            "identity": "{{runServers.security.pskInfo.identity}}",
                            "secret": "{{runServers.security.pskInfo.secret}}"
                        }
                    }
                }
            ]
        }
    }

    Interactive

  4. In the "Pre-request Script" cell, report the following script to monitor the operation:

    console.log("body contains endpointName" + "->" + data.endpointName)
    console.log(pm.response.json())

    Interactive

  5. The script is ready.

The Json body format and the fields are described here.

7.7.4.2. Script execution
  1. Launch the runner (in postman at the bottom right) Interactive

  2. Select your CSV entries file

  3. Check with preview button : postman must read correctely the data’s (the fields and values must be match). Interactive

  4. Drag and drop your endpoint, in the run order, and select your endpoint for running. Interactive

  5. Set a delay between 2 requests to avoid consuming the API’s live objects quotas limits : reaching limits of API will be causes some troubles → check the limits.

  6. Now the Postman script can be run, queries provision every entry you defined in the CSV file and are now displayed in your portal’s LwM2M bootstrap list.

7.8. LwM2M device Twin

7.8.1. Principle

The DeviceTwin is a Live Objects service that can collect, update and display the device resources information whether the device is connected to Live Objects or not.The device twin is created when the LwM2M device is created in Live Objects.Because the device twin representation is stored by Live Objects, the service can be collect and report device resources and state from apps and other services.

DeviceTwin feature is a way to define, retrieve or interact with a Twin representation of a device.

Interactive

The way to define entities supported and instantiated by a device is called a TwinModel, it’s a list of ObjectsDefinitions where each object includes a list of AttributesDefinitions.

Note: LiveObjects TwinModel is compatible with OMA LWM2M model.

Each twin-capable physical device (LWM2M) connected to LiveObjects has an associated DeviceTwin:

  • a DeviceTwin is a list of supportedObjects, instantiatedObjects, and reportedValues.

  • it is possible to send orders (downlink) to a DeviceTwin using commands representation called TwinOperation.

And when a device reports value changes, LiveObjects could produce an associated data message under certain conditions. This condition are handled by a tenant DataRule entry.

7.8.2. Use cases

DeviceTwin use cases are

From Customer API

From Device to LiveObjects

  • a device uses Coap + LwM2M to talk to LiveObjects,

  • a device reports the supported and instantiated objects,

  • a device reports the attribute values.

  • a device respond to a twin operation.

7.8.3. Model

LiveObjects Twin Model is a specification of object definitions.

A Twin Model is a tree of objectDefinitions where each objectDefinition includes attributeDefinitions.

Twin Model is compatible with the OMA LWM2M Specifications.

Overview of Twin Model

Interactive

  • an ObjectDefinition can have 0, 1 or more children,

  • a root ObjectDefinition has no parent,

  • there is one root Object definition for LwM2M model (objectDefinitionId=urn:oma:lwm2m)

  • direct children of urn:oma:lwm2m are normalized.

Children ObjectDefinition of urn:oma:lwm2m represents LwM2M Objects, where a Twin Model AttributeDefinition represents a LwM2M Object Resource.

For example the Firmware Update LwM2M Object (Object Id=5) has a Resource called PkgName (Id=6):

Firmware Update LwM2M Object 5

landing

7.8.3.1. Model - ObjectDefinition

Firmware Update Object is represented by the following ObjectDefinition:

Field Value Comment

owner

A public definition has no owner.

objectDefinitionId

urn:oma:lwm2m:5:1.1

Object-definition unique identifier.

For example, objectDefinitionId urn:oma:lwm2m:5:1.1 refers to Object Id 5 in version 1.1 of the oma lwm2m

pathSegment

5

Current segment of the path

name

Firmware Update

Original name

description

…​

Description of the object

minoccurs

0

Minimal occurrence (0 means optional, 1 means mandatory and at least 1 is required)

maxoccurs

1

Maximal occurrence (0 means infinite instances are allowed (unbounded), 1 means maximum 1 instance is allowed

type

OBJECT_MAP

Type of object. possible values are OBJECT, OBJECT_MAP.

- OBJECT means that this is a single object

- OBJECT_MAP means that this object is a map of objects, and that a path of such an object instance is always using a map index.

In LwM2M, every object is of type OBJECT_MAP (except the root node)

operations

[ "READ", "WRITE" ]

Array of possible operations on the object. Possible values are READ, WRITE.

- READ : when applied on an Object, it means a READ operation for all the available Attributes of the Object.

- WRITE when applied on an Object, it means a WRITE operation on all the Attributes of the Object

parent

urn:oma:lwm2m

The objectDefinitionId of the parent object. All LwM2M objects are direct children of urn:oma:lwm2m.

attributes

[…​, {"pathSegment" : "6", "name" : "PkgName", "minoccurs" : 0, "maxoccurs" : 1, "type" : "STRING", "operations" : [ "READ"] } ]

A list of AttributeDefinition. For example, list of Firmware Update attributes.

7.8.3.2. Model - AttributeDefinition

PkgName Resource is represented by the following AttributeDefinition:

Field Value Comment

pathSegment

6

Current segment of the path

name

PkgName

Original name

description

…​

Description of the attribute

minoccurs

0

Minimal occurrence (0 means optional, 1 means mandatory and at least 1 is required)

maxoccurs

1

Maximal occurrence (0 means infinite instances are allowed (unbounded), 1 means maximum 1 instance is allowed

type

STRING

Type of attribute. Supported values are : STRING, INTEGER, UNSIGNED_INTEGER, BOOLEAN, FLOAT, BASE64, DATETIME.

- STRING : represented as UTF-8 string.

- INTEGER : represented as ASCII signed integer 1, 2,4 or 8 bytes

- UNSIGNED_INTEGER : represented as ASCII unsigned integer 1, 2,4 or 8 bytes

- BOOLEAN : represented as ASCII value 0 or 1

- FLOAT : represented as a 32 or 64-bit floating point values

- BASE64 : represented as a sequence of binary octets

- DATETIME : represented as a Unix Time. A signed integer representing the number of seconds since Jan 1st, 1970 in the UTC time zone

operations

[ "READ", "WRITE", "EXECUTE" ]

Array of possible operations on the attribute. Possible values are READ, WRITE, EXECUTE.

- EXECUTE, only on an attribute, it means a EXECUTE operation on the Attribute of the Object

7.8.3.3. Model management

In the Twin Model, we distinguish two types of models:

  • public models that are defined for the entire LiveObjects platform. For LwM2M, the ObjectIDs can range from 0 to 32768.

  • custom models that are defined per LiveObjects account. For LwM2M, the ObjectIDs are restricted to the 10241 - 42800 range.

For a given ID, the custom model takes precedence over the public model if both exist.
For the LwM2M protocol, models with IDs between 10241 and 32768 are published by the OMA, so care should be taken when defining a custom model in this range as it may override a public model for the account.

More details on the different ObjectID classes defined by the OMA for LwM2M can be found in the LwM2M Registry.

7.8.3.3.1. Public model

Objects from public range are managed by LiveObjects.

A (managed) public object definition :

  • has an empty owner attribute.

Public object definitions can’t be removed.

7.8.3.3.2. Custom model

A customer can extend the model by importing new Custom Object definitions.

This extension is called "Customer defined twin model". This model will apply for all twin devices of the customer account.

Using Twin Model Management API you can import a custom LWM2M OMA compatible XML Files, or delete a given customer model.

See this chapter for examples of Twin Model Management API usage which give you how to manage your custom objects.

7.8.3.3.3. Custom model limits

Some limits on custom models apply :

  • The number of custom model per tenant is limited.

7.8.4. Model API

7.8.4.1. Get Object-Definitions

Read TwinModels by giving an objectDefinitionId :

  • use urn:oma:lwm2m root element to list as children all LwM2M ObjectDefinitions.

  • use a urn:oma:lwm2m:oma:<Id>:<Version> format, and replace Id, Version to get a given LwM2M Object.

For example, urn:oma:lwm2m:oma:5:1.1 will get the Object Id=5 in Version=1.1.

7.8.4.1.1. Request

Endpoint:

GET /api/v1/deviceMgt/twin/model/object-definitions/{objectDefinitionId}

The usage is described here : Swagger API documentation.

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/twin/model/object-definitions/urn:oma:lwm2m:oma:5:1.1
7.8.4.1.2. Response

HTTP Code:

200 OK

Body:

{
  "objectDefinitionId": "urn:oma:lwm2m:oma:5:1.1",
  "pathSegment": "5",
  "name": "Firmware Update",
  "description": "Firmware Update Object",
  "minOccurs": 0,
  "maxOccurs": 1,
  "type": "OBJECT_MAP",
  "operations": [
    "READ",
    "WRITE"
  ],
  "attributes": [
    [.../...]
    {
      "pathSegment": "6",
      "name": "PkgName",
      "description": "Package name",
      "minOccurs": 0,
      "maxOccurs": 1,
      "type": "STRING",
      "operations": [
        "READ"
      ]
    },
    [.../...]
  ],
  "parent": "urn:oma:lwm2m"
}
7.8.4.2. Post Object-Definitions

Import an ObjectDefinition (a custom Twin Model) :

  • set LWM2M format,

  • provide an OMA Compatible XML File,

  • decide whether the definition should be overwritten or not if it already exists.

7.8.4.2.1. Request

Endpoint:

POST /api/v1/deviceMgt/twin/model/object-definitions?inputFormat=lwm2m&override=true

The usage is described here : Swagger API documentation.

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Body (form-data):

file: <XML File>
7.8.4.2.2. Response

HTTP Code:

201 Created

Body:

{
    "objectDefinitionId": "urn:oma:lwm2m:ext:33442",
    "pathSegment": "33442",
    "name": "LwM2M v1.1 Test Object CUSTOM CUSTOM",
    "description": "This object is created by the customer.",
    "minOccurs": 0,
    "maxOccurs": 0,
    [.../...],
    "parent": "urn:oma:lwm2m",
    "owner": "6139d13394f6b376e447ff9d"
}
Notice that the imported model owner attribute is the customer id.
7.8.4.3. Delete Object-Definitions

Remove an ObjectDefinition (a custom Twin Model) :

  • provide an ObjectDefinitionId.

7.8.4.3.1. Request

Endpoint:

DELETE /api/v1/deviceMgt/twin/model/object-definitions/{objectDefinitionId}

The usage is described here : Swagger API documentation.

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json
7.8.4.3.2. Response

HTTP Code:

204 No content

7.8.5. DeviceTwin

LiveObjects DeviceTwin is a Twin representation of the real device:

  • which objects are supported

  • which objects are instantiated

  • which are the instantiated objects last reported attributes values

DeviceTwin overview

Interactive

A DeviceTwin includes :

  • supportedObjects as a list of objectDefinitionId : list Object definitions supported by the device.

  • instantiatedObjects as a list of Object : list of Object implemented by the device.

  • reportedValues as a list of AttributeValue : list of Attributes values reported by the device

In addition, LiveObjects provides three ways to represents a given DeviceTwin :

7.8.5.1. RootObject

RootObject is represented by the following :

Field Value Comment

objectDefinitionId

urn:oma:lwm2m

Parent of the ObjectDefinition identifier.

path

/

Root path

children

[]

Children Object

7.8.5.2. Object

Object is represented by the following :

Field Value Comment

objectDefinitionId

urn:oma:lwm2m:5:1.1

ObjectDefinition identifier.

path

/5

Object path : object (OBJECT_MAP) 5

instances

[]

List of ObjectInstance

7.8.5.3. ObjectInstance

ObjectInstance is represented by the following :

Field Value Comment

objectDefinitionId

urn:oma:lwm2m:5:1.1

ObjectDefinition identifier.

path

/5/0

Object path : object (OBJECT_MAP) 5 instance 0

attributes

[]

List of Attribute

7.8.5.4. Attribute

Attribute is represented by the following :

Field Value Comment

path

/5/0/3

Attribute path : object 5 instance 0 attribute 3. A root Object has an empty path.

/1/4/25/0

Attribute path : object 1 instance 4 multi-instances attribute 25 instance 0.

content

AttributeValue

Single instance attribute

contents

List<AttributeValue>

Multi-instances attributes

When an attribute is a single-instance attribute, his value is reported as content, whereas a multi-instances attribute is reported as contents.

7.8.6. DeviceTwin API

7.8.6.1. Get supported objects

Read DeviceTwin supported objects.

7.8.6.1.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/{deviceId}/twin/supported-objects

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/supported-objects
7.8.6.1.2. Response

HTTP Code:

200 OK

Body:

["urn:oma:lwm2m:oma:1", "urn:oma:lwm2m:oma:2", "urn:oma:lwm2m:oma:3", "urn:oma:lwm2m:oma:4", "urn:oma:lwm2m:oma:5:1.1"]

This response is the list of supported object definition identifiers for a DeviceTwin.

7.8.6.2. Get instantiated objects

Read DeviceTwin instantiated objects.

7.8.6.2.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/{deviceId}/twin/objects

Query parameters:

Name Description

expand

Optional. If 1 then children objects are expanded with their instances. 0 by default

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/objects?expand=1
7.8.6.2.2. Response

HTTP Code:

200 OK

Body:

{
    "objectDefinitionId": "urn:oma:lwm2m",
    "path": "/",
    "children": [
        {
            "objectDefinitionId": "urn:oma:lwm2m:oma:1",
            "path": "/1",
            "instances": [
                {
                    "objectDefinitionId": "urn:oma:lwm2m:oma:1",
                    "path": "/1/0"
                },
                {
                    "objectDefinitionId": "urn:oma:lwm2m:oma:1",
                    "path": "/1/1"
                }
            ]
        },
        {
            "objectDefinitionId": "urn:oma:lwm2m:oma:2",
            "path": "/2",
            "instances": [
                {
                    "objectDefinitionId": "urn:oma:lwm2m:oma:2",
                    "path": "/2/0"
                },
                {
                    "objectDefinitionId": "urn:oma:lwm2m:oma:2",
                    "path": "/2/1"
                }
            ]
        },
        {
            "objectDefinitionId": "urn:oma:lwm2m:oma:3",
            "path": "/3",
            "instances": [
                {
                    "objectDefinitionId": "urn:oma:lwm2m:oma:3",
                    "path": "/3/0"
                }
            ]
        }
    ]
}

This response is a RootObject with the list of children objects (instantiated objects) for a DeviceTwin.

7.8.6.3. Get detailed object

Read DeviceTwin detailed object.

7.8.6.3.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/{deviceId}/twin/objects/{objectId}

Query parameters:

Name Description

expand

Optional. If 1 then instances are expanded with their attributes having reported values. 0 by default

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/objects/1?expand=1
7.8.6.3.2. Response

HTTP Code:

200 OK

Body:

{
    "objectDefinitionId": "urn:oma:lwm2m:oma:1",
    "path": "/1",
    "instances": [
        {
            "objectDefinitionId": "urn:oma:lwm2m:oma:1",
            "path": "/1/0",
            "attributes": [
                {
                    "pathSegment": "5",
                    "path": "/1/0/5",
                    "content": {
                        "reportedValue": "1",
                        "timestamp": "2021-09-30T09:25:06.687Z"
                    }
                },
                {
                    "pathSegment": "25",
                    "path": "/1/0/25",
                    "contents": [
                        {
                            "reportedValue": "v1/1.1.2",
                            "timestamp": "2021-11-15T17:14:06.687Z",
                            "path": "/1/0/25/0"
                        },
                        {
                            "reportedValue": "v1/1.BIS",
                            "timestamp": "2021-11-15T17:14:06.687Z",
                            "path": "/1/0/25/1"
                        }
                    ]
                }
            ]
        },
        {
            "objectDefinitionId": "urn:oma:lwm2m:oma:1",
            "path": "/1/1",
            "attributes": [
                {
                    "pathSegment": "3",
                    "path": "/1/1/3",
                    "content": {
                        "reportedValue": "1",
                        "timestamp": "2021-09-30T09:25:06.687Z"
                    }
                }
            ]
        }
    ]
}

This response is an Object (instantiated objects and reported values) for a DeviceTwin.

7.8.6.4. Get detailed object instance

Read DeviceTwin detailed object instance.

7.8.6.4.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/{deviceId}/twin/objects/{objectId}/{instanceId}

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/objects/1/0
7.8.6.4.2. Response

HTTP Code:

200 OK

Body:

{
    "objectDefinitionId": "urn:oma:lwm2m:oma:1",
    "path": "/1/0",
    "attributes": [
        {
            "pathSegment": "5",
            "path": "/1/0/5",
            "content": {
                "reportedValue": "1",
                "timestamp": "2021-09-30T09:25:06.687Z"
            }
        },
        {
            "pathSegment": "25",
            "path": "/1/0/25",
            "contents": [
                {
                    "reportedValue": "v1/1.1.2",
                    "timestamp": "2021-11-15T17:14:06.687Z",
                    "path": "/1/0/25/0"
                },
                {
                    "reportedValue": "v1/1.BIS",
                    "timestamp": "2021-11-15T17:14:06.687Z",
                    "path": "/1/0/25/1"
                }
            ]
        }
    ]
}

This response is an ObjectInstance (instantiated object and reported values) for a DeviceTwin.

7.8.7. Operations

LiveObjects Twin operation is a representation of a real operation on a device:

  • READ - order the device to report some attributes,

  • WRITE - update or replace some object attributes values,

  • EXECUTE - execute some attributes.

  • WRITE-METADATA - update metadata (set, update, reset).

7.8.7.1. Operation definition

A Twin operation applies to a given device, includes a given type (read,write,execute, write-metadata), with some operation attributes (paths, values, options) and has a unique id (generated by LiveObjects).

Each operation orders a given action (or composite action) on a target device and the result of this action is visible within operation status and operation error attributes.

Example of Twin Operation:

    {
        "id": "b50d094e520a4d58ad367f2fb9afdf6f",
        "type": "READ",
        "paths": [
            "/1/0/0"
        ],
        "status": "OK",
        "created": "2022-03-07T16:03:51.609Z",
        "updated": "2022-03-07T16:04:09.263Z"
    }

This is a success and done READ operation.

Field Value Comment

id

b50d094e520a4d58ad367f2fb9afdf6f

Operation unique id, generated by LiveObjects

type

READ

Type of the operation.

paths

['/1/0/0', '/5/1/3']

Target paths of related device objects or attributes

values

[{"path":"/1/0/3", "value":"x"},
 {"path":"/5/0/3", "value":"y"}]

for WRITE and WRITE-METADATA: Values to set.

writeMode

REPLACE

for WRITE: mode to set. Possible values : UPDATE, REPLACE

contextToken

OPBIS123

Free custom tag on the operation

status

OK

Current status of Twin Operation

options

{"lwm2m": {"contentFormat": {"response": "SENML_JSON"} } }

Options of Twin Operation, cf. Operation options section.

policy.attempts

1

Number of attempts allowed for this operation (default value is 1 that means there is no retry).

error.code

OPERATION_INVALID

status FAILED only: Error code of Twin Operation.

error.details

details here

status FAILED only: Error details of Twin Operation.

error.deviceCode.value

404

status FAILED, error.code DEVICE_ERROR only: Device error value.

error.deviceCode.reason

404 not found

status FAILED, error.code DEVICE_ERROR only: Device error reason.

created

2022-02-24T16:30:06.687Z

When the operation were created.

updated

2022-02-24T17:01:00.122Z

When the operation were updated. In case of status OK, this is when the device responds.

======= WRITE-METADATA Operation details

Live Objects supports all LwM2M 1.1 notification attributes (named metadata in current chapter).

Those metadata define the conditions when notification on an objet or attribute is sent.

metadata Description

pmin

The Minimum Period metadata indicates the minimum time in seconds the LwM2M Client MUST wait between two notifications

pmax

The Maximum Period metadata indicates the maximum time in seconds the LwM2M Client MAY wait between two notifications

gt

This Greater Than metadata defines a threshold high value. When this metadata is present, the LwM2M Client MUST notify the Server each time the Observed Attribute value crosses this threshold

lt

This Less Than metadata defines a threshold low value. When this metadata is present, the LwM2M Client MUST notify the Server each time the Observed Attibute value crosses this threshold

st

This Step metadata defines a minimum change value between two notifications

epmin

The Minimum Evaluation Period metadata indicates the minimum time in seconds the LwM2M Client MUST wait between two evaluations of reporting criteria

epmax

The Maximum Evaluation Period metadata indicates the maximum time in seconds the LwM2M Client MAY wait between two evaluations of reporting criteria

7.8.7.2. Operation options

Operation options apply on the following use-cases:

Scope Key Possible values Comment

Lwm2m operation

lwm2m.contentFormat

TLV, JSON, SENML_JSON, SENML_CBOR, TEXT, OPAQUE, CBOR

content format requested by the customer for the operation (request, response)

7.8.7.3. Operation examples
Name Operation extract Details

READ all objects

{
   "type":"READ",
   "paths":["/"]
}

Read all objects

READ one object

{
   "type":"READ",
   "paths":["/5"]
}

Read object 5

READ one object instance

{
   "type":"READ",
   "paths":["/5/0"]
}

Read object 5 instance 0

READ one attribute

{
   "type":"READ",
   "paths":["/5/0/3"]
}

Read object 5 instance 0 attribute 3

READ one multi-instances attribute instance

{
  "type":"READ",
  "paths":["/1/4/11/4"]
}

Read object 1 instance 4 attribute 11 attribute instance 4

READ composite two objects, and one multi-instances attribute instance

{
   "type":"READ",
   "paths":["/3","/5","/1/4/11/4"]
}

Read objects 3, 5 and an attribute instance /1/4/11/4

WRITE one attribute in update mode

{
   "type":"WRITE",
   "writeMode":"UPDATE",
   "paths":["/1/0"],
   "values":[
       {"path":"/1/0/7", "value":"sample1"}
   ]
}

Write sample1 into object 1 instance 0 attribute 7. An WRITE operation requires one and only one path value in paths.

WRITE one multi-instances attribute instance in update mode

{
   "type":"WRITE",
   "writeMode":"UPDATE",
   "paths":["/1/4"],
   "values":[
       {"path":"/1/4/11/4", "value":"sample2"}
   ]
}

Write sample2 into attribute instance /1/4/11/4

WRITE two multi-instances attribute instances in update mode

{
   "type":"WRITE",
   "writeMode":"UPDATE",
   "paths":["/1/0/11"],
    "values":[
      {"path":"/1/0/11/0", "value":"sampleA"},
      {"path":"/1/0/11/2", "value":"sampleB"}]
}

Write sampleA into attribute instance /1/0/11/0, and sampleB into attribute instance /1/0/11/2

WRITE two multi-instances attribute instances in replace mode

{
   "type" : "WRITE",
   "writeMode":"REPLACE",
   "paths":["/1/0/11"],
   "values" : [
      { "path": "/1/0/11/0", "value":"sampleA" },
      { "path": "/1/0/11/2", "value":"sampleB" }
   ]
}

Write target /1/0/11 in replace mode : write sampleA into attribute instance /1/0/11/0, and write sampleB into attribute instance /1/0/11/2, and remove other /1/0/11 attributes.

WRITE multiple attributes on object instance in update mode

{
  "type":"WRITE",
  "writeMode":"UPDATE",
  "paths":["/1/0"],
  "values":[
     { "path": "/1/0/7", "value":"sampleD" },
     { "path": "/1/0/11/2", "value":"sampleE" },
     { "path": "/1/0/11/0", "value":"sampleF" }
  ]
 }

Write in update mode /1/0/7, /1/0/11/2, /1/0/11/0 values, and only them.

WRITE multiple attributes on object instance in replace mode

{
  "type": "WRITE",
  "writeMode":"REPLACE",
  "paths": [ "/1/0" ],
  "values":[
     { "path": "/1/0/7", "value":"sampleD" },
     { "path": "/1/0/11/2", "value":"sampleE" },
     { "path": "/1/0/11/0", "value":"sampleF" }
  ]
}

Write /1/0 in replace mode : set /1/0/7, /1/0/11/2, /1/0/11/0 values, and remove other /1/0 attributes.

WRITE composite multiple attributes on different objects in update mode

{
  "type": "WRITE",
  "writeMode":"UPDATE",
  "paths": [ "/" ],
  "values":[
      { "path": "/2/1/6", "value":"sampleX" },
      { "path": "/1/0/7", "value":"sampleY" },
      { "path": "/1/0/4/1", "value":"sampleZ" }
  ]
}

Write in update mode /2/1/6, /1/0/7, /1/0/4/1 values, and only them. It’s a composite WRITE because target paths scope different objects instances : /2/1 and /1/0

WRITE composite multiple attributes on different object instances

{
  "type": "WRITE",
  "writeMode":"UPDATE",
  "paths": [ "/" ],
  "values":[
     { "path": "/1/0/7", "value":"sampleV" },
     { "path": "/1/1/7", "value":"sampleW" }
  ]
}

Write in update mode /1/0/7, /1/1/7 values, and only them. It’s a composite WRITE because target paths scope different objects instances : /1/0 and /1/1

EXECUTE execute a given attribute

{
  "type": "EXECUTE",
  "paths" : [ "/1/0/8" ]
}

Execute /1/0/8 attribute. An EXECUTE operation requires one and only one path value in paths.

WRITE-METADATA update metadata

{
  "type": "WRITE-METADATA",
  "values": [
    {
      "path": "/1/0/7",
      "metadata": [
        {
          "name": "pmin",
          "value": "20"
        },
        {
          "name": "gt",
          "value": "50"
        },
        {
          "name": "lt"
        }
      ]
    }
  ]
}

Update metadata on /1/0/7 (set or update pmin and gt and reset lt metadata)

A WRITE-METADATA operation requires one and only one path that could identify an object, an object instance, an attribute or an attribute instance.

7.8.7.4. Operation lifecycle

A Twin operation is created using API and the result of an operation will be available via API too.

Once created, the operation is executed asynchronous as soon as the device become twin capable (ex. the device connect and his interface become online).

TwinOperation sequence diagram

Interactive

API allow to monitor the status of the operation waiting for a final state by using a given operation id, and polling the GET API.

TwinOperation status and state machine

Interactive

status Comment

PENDING

Operation is created and ready to be sent.

SENT

Operation has been emitted from Twin Service to the connector then the device.

RETRYING

Operation didn’t succeed but the reason of the error allows a retry.

CANCELLED

A pending operation has been cancelled by user (via API). It is a final state.

EXPIRED

A pending or sent operation has remained in the same state for too long. It is a final state.

FAILED

For some reason, the operation didn’t succeed. The reason why it failed is described by error fields. It is a final state.

OK

Operation succeed. It is a final state.

The following expiration delay applies:

origin status Schema reference Comment

from PENDING

x

If a device never registers, a PENDING operation moves to EXPIRED after 3 days.

from SENT

y

If a response is not received after 25 minutes, a SENT operation moves to RETRYING if max attempt is not reached else the SENT operation moves to EXPIRED.

from RETRYING

x

If a device never registers, a RETRYING operation moves to EXPIRED after 3 days.

7.8.7.5. Operation retry policy

For errors that are considered as unrecoverable (e.g device rejected the request), there will be only one attempt to send an operation.

For other errors there will be additional attempts limited to the number of attempts provided by the end user. For instance, we can mention a 5xx response or a time-out.

The operation is executed asynchronously as soon as the device becomes twin capable (ex. the device connects and its interface becomes online).

TwinOperation retrying sequence diagram

Interactive

7.8.7.6. Operation limits

Some limits apply in terms of :

  • actives operations per device : operations having PENDING, SENT, RETRYING status. Other this limit, an operation creation attempt will fail (with 403 status).

  • final operations per device : operations having UNKNOWN, CANCELLED, EXPIRED, FAILED or OK status. Other this limit, at creation of new operation time, older operations will be removed.

7.8.8. Operations API

This section includes API call examples for the Twin Operations management.

7.8.8.1. Create an operation

Create a new DeviceTwin operation.

According to the operation lifecycle, this will create a PENDING operation.

Different kinds of Twin operation are described by twin operation definition and twin operation examples.

Example:

POST /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/operations
{
"type":"READ",
"paths":["/1/0"],
"contextToken" : "this is a simple READ"
}

Response

201 CREATED
{
    "id": "f9b9877c7679454ea56e568b31ee7c48",
    "type": "READ",
    "paths": [
        "/1/0"
    ],
    "contextToken": "this is a simple READ",
    "status": "PENDING",
    "created": "2022-02-25T09:32:55.248Z",
    "updated": "2022-02-25T09:32:55.248Z"
}

A pending DeviceTwin READ instance /1/0 operation has been created.

7.8.8.2. Cancel a pending operation

Cancel a PENDING DeviceTwin operation.

Example:

PUT /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/operations/f2ed1637ec10466089064804ed68e351/status
"CANCELED"

Response

200 OK

This response confirm that Twin Operation status has been set to CANCELED.

7.8.8.3. Get an operation

Get one DeviceTwin operation.

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/operations/a1ca9551754d48d09e31fd30d36b88d1

Response

200 OK
{
    "id": "a1ca9551754d48d09e31fd30d36b88d1",
    "type": "READ",
    "paths": [
        "/1/0"
    ],
    "contextToken": "ABC123",
    "status": "OK",
    "created": "2022-02-11T16:16:05.073Z",
    "updated": "2022-02-11T16:16:23.492Z"
}

This is a Twin Operation details.

7.8.8.4. List operations

List DeviceTwin operations.

Some filter could apply to restrict the results :

parameter description

status

<list> restrict to operations having this status

contextToken

restrict to operations having this contextToken (exact match)

type

<list> restrict to operations having this type

path

restrict to operations having at least one time this path in his definition (exact match)

Number of result is constraint by Twin operations limits.

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/operations?status=OK&status=FAILED&status=EXPIRED&type=READ

Response

200 OK
[
    {
        "id": "f2ed1637ec10466089064804ed68e351",
        "type": "READ",
        "paths": [
            "/1/0"
        ],
        "contextToken": "ABC123",
        "status": "OK",
        "created": "2022-02-11T16:16:05.073Z",
        "updated": "2022-02-11T16:16:23.492Z"
    },
    {
        "id": "25a65010ab9b4c38a925c2dc7f16a7c8",
        "type": "READ",
        "paths": [
            "/1/0/200",
            "/1/0/7"
        ],
        "status": "FAILED",
        "error": {
            "code": "OPERATION_INVALID",
            "details": "The details here"
        },
        "created": "2022-02-16T15:20:24.142Z",
        "updated": "2022-02-16T15:20:34.252Z"
    }
 ]

This response is the list of Twin Operations of a DeviceTwin

  • having status in [OK, FAILED, EXPIRED],

  • having type in [READ].

7.8.9. Observations

7.8.9.1. Observation definition

An Observation allows Live Objects to be notified when some Attributes change on the device. It can target:

  • a specific Attribute

  • an Object Instance

  • all Object Instances of an Object

  • several Attributes (Observation Composite)

Example of an Observation targeting an Object Instance:

{
    "id": "631f1190d4135d0066541e8b",
    "paths": [
        "/6/0"
    ],
    "status": "PENDING",
    "name": "Observation on the location Object",
    "created": "2022-09-12T11:02:29.811Z"
}
Field Example Comment

id

631f1190d4135d0066541e8b

Observation unique id, generated by Live Objects

paths

['/6/0']

Target paths of related device objects or attributes to observe

status

PENDING

Current status of the Observation among PENDING, OBSERVING and FAILED

name

Observation on the location Object

User-defined name for the Observation

created

2022-09-12T11:02:29.811Z

Observation creation date

7.8.9.2. Observation Lifecycle

An Observation is created using the API and its status will be available via the API too.
Once created, the Observation is sent immediately if the device is ONLINE or the next time the device sends an Update or Register otherwise.
Depending on the type of error, Observations that have failed can be automatically re-sent at the next Update. The number of attempts is nevertheless limited.
When a LwM2M device goes offline (de-registration or the lifetime of the registration expires), the Observations on Live Objects for this device go back to the PENDING state. They will be automatically re-sent when the device sends a Register, regardless of their status.
An Observation can be cancelled. Upon the user cancellation request, a Cancel Observation operation is sent to the device if it is ONLINE. Otherwise, the cancellation occurs at the next Notify.

Observation sequence diagram

Interactive

Observation state machine

Interactive

status Comment

PENDING

The Observation has been created and is ready to be sent.

FAILED

The Observation has not succeeded after the maximum number of attempts.

OBSERVING

The Observation is active on the device.

7.8.9.3. Observation retry policy

For errors that are considered as unrecoverable, there will be only one attempt to send an Observation. The following errors fall in this category:

  • The device responded with a 4xx code

  • The device rejected the request

For other errors there will be 5 attempts. For instance, we can mention a 5xx response or a time-out.

7.8.9.4. Observation configuration

The parameters related to an Observation can be configured by the Write-Metadata operation.

7.8.9.5. Observation limits

The number of Observations per device is limited regardless of their status.

7.8.10. Observations API

This section includes API call examples for the Observations management.

7.8.10.1. Create an Observation

Create a new Observation.

According to the Observation lifecycle, this will create a PENDING Observation.

Example:

POST /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/observations
{
    "paths": [
        "/6/0"
    ],
    "name": "Observation on the location Object"
}

Response

201 CREATED
{
    "id": "631f1190d4135d0066541e8b",
    "paths": [
        "/6/0"
    ],
    "status": "PENDING",
    "name": "Observation on the location Object",
    "created": "2022-09-12T11:02:29.811Z"
}

A pending Observation has been created.

7.8.10.2. Cancel an Observation

Cancel an Observation.

Example:

DELETE /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/observations/631f1190d4135d0066541e8b

Response

204 NO CONTENT

This response confirm that the Observation has been removed and will be cancelled on the device.

7.8.10.3. Get an Observation

Get one Observation.

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/observations/631f1190d4135d0066541e8b

Response

200 OK
{
    "id": "631f1190d4135d0066541e8b",
    "paths": [
        "/6/0"
    ],
    "status": "OBSERVING",
    "name": "Observation on the location Object",
    "created": "2022-09-12T11:02:29.811Z"
}

This is an Observation details.

7.8.10.4. List Observations

List Observations.

The number of result is constraint by Twin Observations limits.

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:lwm2m:mydevice/twin/observations

Response

200 OK
[
    {
        "id": "62d6c3230d0685589727902e",
        "paths": [
            "/3303/0"
        ],
        "status": "FAILED",
        "name": "Observation on the temperature Object",
        "created": "2022-07-19T14:43:47.023Z"
    },
    {
        "id": "631f1190d4135d0066541e8b",
        "paths": [
            "/6/0"
        ],
        "status": "OBSERVING",
        "name": "Observation on the location Object",
        "created": "2022-09-12T11:02:29.811Z"
    }
]

This response is the list of Observations of a DeviceTwin

7.8.11. DataRules

LiveObjects Twin data rule is a representation of a rule that can be used to trigger a new data message from device reported values.

7.8.11.1. DataRule definition

A Twin data rule applies to a given tenant, includes a given type, with some rule attributes (paths) and has a unique id (generated by LiveObjects).

A tenant data rule presence drives the way twin message will be generated.

Twin data rule type are:

  • PASSTHROUGH - order twin to forward all values that match paths as new data message.

Example of Twin data rule:

    {
        "id": "6250072f5297c340e68f7bad",
        "name": "my passthrough",
        "type": "PASSTHROUGH",
        "paths": [
            "/"
        ],
        "created": "2022-04-08T09:58:07.843Z"
    }

This is a PASSTHROUGH data rule that triggers all values (having path starting with /).

Field Value Comment

id

6250072f5297c340e68f7bad

Data rule unique id, generated by LiveObjects

type

PASSTHROUGH

Type of the rule.

paths

['/']

Target paths of related rule

created

2022-04-08T09:58:07.843Z

When the rule were created.

7.8.11.2. Data rules limits

For now, you can only create one PASSTHROUGH rule for your tenant.

7.8.12. Data rules API

Data rules management API are available at following endpoint: /api/v1/deviceMgt/twin/data/rules and are documented on Swagger.

7.8.13. Data Message

When a LWM2M device reports value changes, a data message that includes this change is generated by LiveObjects under certain conditions:

  • the report must be at the device initiative (send, or notify but not read response),

  • the report must match a given data rule of the tenant.

When all these conditions are met, a message is generated.

Today the generation model used for the message is twin_json.

7.8.13.1. DataMessage common attributes

A Twin data message as other LiveObjects messages, will embed some common attributes: id, streamId, etc.

The value part of the message will embed the device reported values representation, depending on the model used.

Example of a fill Twin data message having twin_json model:

{
  "id": "6254192e1a52727da422dfdf",
  "streamId": "urn:lo:nsid:lwm2m:simulator",
  "timestamp": "2022-04-11T12:03:58.695Z",
  "model": "twin_json",
  "value": {
    "device": {
      "0": {
        "deviceType": "Demo",
        "utcOffset": "Z",
        "serialNumber": "LT-500-000-0001",
        "timezone": "Etc/UTC",
        "memoryFree": 6278,
        "errorCode": {
          "0": 0
        },
        "supportedBindingAndModes": "U",
        "manufacturer": "Leshan Demo Device",
        "currentTime": "2022-04-11T12:03:58Z",
        "batteryStatus": 6,
        "memoryTotal": 19400,
        "modelNumber": "Model 500",
        "hardwareVersion": "1.0.1",
        "firmwareVersion": "1.0.0",
        "softwareVersion": "1.0.2",
        "batteryLevel": 44
      }
    }
  },
  "tags": [
    "lwm2m-simulator",
  ],
  "extra": {},
  "metadata": {
    "source": "urn:lo:nsid:lwm2m:simulator",
    "group": {
      "id": "root",
      "path": "/"
    },
    "connector": "lwm2m",
    "network": {
      "lwm2m": {
        "ep": "urn:lo:nsid:lwm2m:simulator"
      }
    }
  },
  "created": "2022-04-11T12:03:58.725Z"
}

This message is generated by the urn:lo:nsid:lwm2m:simulator lwm2m endpoint and embed a twin_json representation of some device instance 0 attributes (reported values).

7.8.13.2. DataMessage TWIN_JSON format

A TWIN_JSON data message is a JSON representation of reported values that include camel case human-readable entity names.

In a TWIN_JSON data message, each value is embedded in an object, plus an attribute container.

Reminder: Object, Attribute definitions are part of the TwinModel.

For a simple attribute the JSON message will be generated according the following design:

  • camel case name of the object,

  • pathSegment id of the object,

  • camel case name of the attribute,

  • reported raw value of the attribute.

For example, for a given [/3/0/1, /3/0/9] reported values, associated twin model definitions are:

  • Object 3 : Device - Instance 0

  • Attribute 1: Model Number.

  • Attribute 9: Battery Value.

Related TWIN_JSON of these values will be:

{
  "device": {
    "0": {
      "modelNumber": "Model 500",
      "batteryLevel": 44
    }
  }
}
7.8.13.3. DataMessage metadata enrichment

A Twin data message as other LiveObjects messages, may embed some metadata.

They are extracted from reported values.

Currently, extracted metadata are:

Metadata Description Source Target

location

location of the device

\6\0\0 to \6\0\3

Object 6 : Location - Instance 0

  • Attribute 0: Latitude

  • Attribute 1: Longitude

  • Attribute 2: Altitude

  • Attribute 3: Radius (Accuracy)

see location provided by the device chapter

Unresolved directive in lo_manual.adoc - include::/builds/liveobjects/documentation/lo-manual/target/checkout/target/asciidoc/lo_manual_v2/bootstrap/adoc/bootstrap.adoc[]

Unresolved directive in lo_manual.adoc - include::/builds/liveobjects/documentation/lo-manual/target/checkout/target/asciidoc/lo_manual_v2/twin/adoc/twin.adoc[]

8. Device management

8.1. Device group

8.1.1. Principle

A group enables to bring devices together. Groups can be used to :

  • ease browsing and sorting on Live Objects web portal.

  • using inventory explorer, count and aggregate your devices fleet, select a sub set (group) of your devices fleet by criterias to manage it.

  • apply different forwarding rules on the data collected from the devices (Cf. "Notifications" section).

  • apply different event processing and alarming rules (Cf. "Alarming" chapter).

Groups behave mostly like directories in a filesystem (considering devices are files): a Group can include other groups and devices. For instance a device can only belong to one group at a time. There are however some exceptions to this analogy (see group deletion rules).

Each tenant has a default root group. A group, except root group, must have a parent group and can have subgroups. In the same tenant, the complete path of each group must be unique but several groups can have the same local identifier (pathNode). The complete path enables to have the tree view of your group.

Group object model:

JSON Params Description

id

group unique identifier

pathNode

Optional. local group id in path

path

complete group path

parentId

Optional. parent group identifier

description

Optional. detailed description of the group

created

creation date of the device

updated

last update date of the device

The group id is fixed, but the group path is calculated because he depends on both the pathNode and the location of the group in the tree. Moving a group in the tree logically leads to a modification of the group path.

Example:

{
    "id": "u1z1k8",
    "pathNode": "lyon",
    "path": "/france/lyon",
    "parentId": "P2112f",
    "description": "City of Lyon",
    "created": "2018-02-14T16:53:54.515Z",
    "updated": "2018-02-14T16:53:54.515Z"
}
Groups tree view

Interactive

8.1.2. Create a new group

8.1.2.1. Request

Endpoint:

POST /api/v1/deviceMgt/groups

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Body:

JSON Params Description

pathNode

group local identifier in path (unique for groups with the same parent)

parentId

Optional. reference to group parent (id). Root group by default.

description

Optional. detailed description of the group

Example:

POST /api/v1/deviceMgt/groups
{
    "pathNode":"lyon",
    "parentId":"P2112f",
    "description":"City of Lyon"
}
8.1.2.2. Response

HTTP Code:

201 CREATED

Body:

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

401

UNAUTHORIZED

Authentication failure.

403

GENERIC_ACTION_FORBIDDEN_ERROR

Request forbidden.

404

DM_GROUP_NOT_FOUND

Group not found

409

DM_GROUP_DUPLICATE

Conflict on group path

Example:

{
    "id": "u1z1k8",
    "pathNode": "lyon",
    "path": "/france/lyon",
    "parentId": "P2112f",
    "description": "City of Lyon",
    "created": "2018-02-14T16:53:54.515Z",
    "updated": "2018-02-14T16:53:54.515Z"
}

8.1.3. Update a group

The path change of a group does not change its content (Devices, Groups).

8.1.3.1. Request

Endpoint:

PUT /api/v1/deviceMgt/groups/<id>

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Body:

JSON Params Description

pathNode

Optional. group local id in path (unique for groups with the same parent)

parentId

Optional. reference to group parent (id). Root group by default

description

Optional. detailed description of the group

Example:

PUT /api/v1/deviceMgt/groups/u1z1k8
{
    "pathNode":"paris",
    "parentId":"P2112f",
    "description":"City of Paris"
}
8.1.3.2. Response

HTTP Code:

200 OK

Body:

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

401

UNAUTHORIZED

Authentication failure.

403

GENERIC_ACTION_FORBIDDEN_ERROR

Request forbidden.

404

DM_GROUP_NOT_FOUND

Group not found

Example:

{
    "id": "u1z1k8",
    "pathNode": "paris",
    "path": "/france/paris",
    "parentId": "P2112f",
    "description": "City of Paris",
    "created": "2018-02-14T16:53:54.515Z",
    "updated": "2018-02-15T10:31:26.667Z"
}

8.1.4. List groups

8.1.4.1. Request

Endpoint:

GET /api/v1/deviceMgt/groups

Query parameters:

Name Description

limit

Optional. maximum number of groups in response. 20 by default.

offset

Optional. the number of entries to skip in the results list. 0 by default.

parentId

Optional. filter list by group’s parent. When a parent is set, only direct children are returned (one level).

groupPath

Optional. filter list by group’s path. When a full path is set, only nodes matching exactly this path are returned. In order to return nodes matching a path and all descendants, you must end the groupPath with /* (ex. /spain/*). In order to return direct children nodes -only- of a path, the groupPath must end with /*/ (ex. /spain/*/).

List Groups Query samples:

QueryParams Returned nodes

?groupPath=/france

/france

?groupPath=/*

/france, /france/lyon,/france/paris, /italia

?groupPath=/france/*

/france, /france/lyon,/france/paris

?groupPath=/france/*/

/france/lyon,/france/paris

?parentId=root

/france, /italia

?parentId=P2112f&groupPath=/*

/france/lyon,/france/paris

?parentId=P2112f&groupPath=/france/*

/france/lyon,/france/paris

?parentId=root&groupPath=/france/*

no result

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json
X-Total-Count: <boolean>

For more info about X-Total-Count, see "API v1 paging" section.

Example:

GET /api/v1/deviceMgt/groups?limit=20&offset=0
8.1.4.2. Response

HTTP Code:

200 OK

Body:

Example:

[
    {
        "id": "root",
        "path": "/",
        "created": "2017-11-03T15:23:22.771Z",
        "updated": "2017-11-03T15:23:22.771Z"
    },
    {
        "id": "P2112f",
        "pathNode": "france",
        "path": "/france",
        "parentId": "root",
        "description": "",
        "created": "2018-02-14T16:47:37.318Z",
        "updated": "2018-02-14T16:47:37.318Z"
    },
    {
        "id": "u1z1k8",
        "pathNode": "paris",
        "path": "/france/paris",
        "parentId": "P2112f",
        "description": "City of Paris",
        "created": "2018-02-14T16:53:54.515Z",
        "updated": "2018-02-15T10:31:26.667Z"
    }
]

8.1.5. Get a group

8.1.5.1. Request

Endpoint:

GET /api/v1/deviceMgt/groups/<id>

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/deviceMgt/groups/u1z1k8
8.1.5.2. Response

HTTP Code:

200 OK

Body:

Error case:

HTTP Code Error code message

404

DM_GROUP_NOT_FOUND

Group not found

Example:

{
    "id": "u1z1k8",
    "pathNode": "paris",
    "path": "/france/paris",
    "parentId": "P2112f",
    "description": "City of Paris",
    "created": "2018-02-14T16:53:54.515Z",
    "updated": "2018-02-15T10:31:26.667Z"
}

8.1.6. Delete a group

You can’t delete a group which has devices.

8.1.6.1. Request

Endpoint:

DELETE /api/v1/deviceMgt/groups/<id>

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

DELETE /api/v1/deviceMgt/groups/u1z1k8
8.1.6.2. Response

HTTP Code:

204 NO CONTENT

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

401

UNAUTHORIZED

Authentication failure.

403

DM_GROUP_UNDELETABLE

Group can’t be deleted: contains devices or sub-groups

404

DM_GROUP_NOT_FOUND

Group not found

8.2. Configuration

Currently, APIs allow to manage configuration only for MQTT connector.

8.2.1. Principle

A device can declare one or many parameters: a parameter is identified by a string "key" and can take a typed value (binary, int32, uint32, timestamp).

Live Objects can track the changes of the current value of a device parameters, and allow users to set different target values for those parameters. Live Objects will then try to update the parameters on the device once it’s connected and available.

Device configuration sync steps

Interactive

  • (before) :

    • device initiates MQTT connection with Live Objects,

    • device subscribes in MQTT to a private topic, where it will receive later the configuration update requests,

  • step 0 : device notifies Live Objects that it is connected and available for configuration updates on a specific topic,

  • step 1 : device notifies Live Objects of its current configuration,

  • step 2 : Live Objects compares the current and target configuration for this device. If they differ:

    • step 3 : Live Objects sends to the device, on the topic indicated at step 0, the list of parameters to update, with their target value,

    • step 4 : device handles the request, and tries to apply the change(s),

    • step 5 : device respond to the change request with the new configuration,

    • step 6 : Live Objects saves the new configuration. Parameters that have been successfully updated now have the status "OK" and the others the status "FAILED".

Device configuration sync states

Interactive

If your device is connected in Device mode, please refer to the MQTT device mode part for messages that your device can send or receive.

8.2.2. Get device configuration parameters

To retrieve the details of the configuration map of the device we can use the GET API.

8.2.2.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/<deviceId>/config/parameters

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/config/parameters
8.2.2.2. Response

HTTP Code:

200 OK

Body:

For each parameter, the following information is available :

{
  "{paramKey}": {
    "reported": {
        "type": {paramType},
        "value": {paramValue},
        "timestamp": {timestampsValue}
    },
    "requested": {
        "type": {paramType},
        "value": {paramValue},
        "timestamp": {timestampsValue}
    },
    "syncStatus": {paramStatus}
}

With:

paramKey

string uniquely identifying the device configuration parameter

paramType

indicates the config parameter type between: INT32, UINT32, BINARY, STRING or FLOAT

paramValue

value requested for the parameter

timestampsValue

update date of the parameter

paramStatus

parameter update status: NONE, PENDING, SENT, CANCELED, OK or FAILED

The section reported is present when the device has answered and corresponds to parameter configuration returned by the device, the paramStatus could be OK or FAILED.

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

404

DM_DEVICE_NOT_FOUND

Device not found

Example:

{
  "param1" : {
    "requested" : {
      "type" : "INT32",
      "value" : 1,
      "timestamp" : "2018-08-23T08:10:01.029Z"
    },
    "syncStatus" : "PENDING"
  },
  "param2" : {
    "requested" : {
      "type" : "UINT32",
      "value" : 4321,
      "timestamp" : "2018-08-01T14:39:16.216Z"
    },
    "syncStatus" : "PENDING"
  },
  "param3" : {
    "reported" : {
      "type" : "FLOAT",
      "value" : 3.2,
      "timestamp" : "2018-04-26T08:16:33.681Z"
    },
    "requested" : {
      "type" : "FLOAT",
      "value" : 3.2,
      "timestamp" : "2019-06-17T12:52:20.930Z"
    },
    "syncStatus" : "OK"
  },
  "param4" : {
    "requested" : {
      "type" : "BINARY",
      "value" : 11001,
      "timestamp" : "2018-08-01T14:37:52.579Z"
    },
    "syncStatus" : "CANCELED"
  },
  "param5" : {
    "reported" : {
      "type" : "STRING",
      "value" : "my data",
      "timestamp" : "2018-03-29T08:48:20.810Z"
    },
    "requested" : {
      "type" : "STRING",
      "value" : "info",
      "timestamp" : "2018-03-29T08:48:20.813Z"
    },
    "syncStatus" : "FAILED"
  }
}

8.2.3. Set device configuration parameters

8.2.3.1. Request

Endpoint:

POST /api/v1/deviceMgt/devices/<deviceId>/config

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Body:

JSON Params Description

parameters

list of device configuration update

notifyTo

Optional. topic where configuration change/sync events must be published to

Each parameter to update must have the following structure:

"{paramKey}": {
    "type": {paramType},
    "value": {paramValue}
}

With:

paramKey

a string uniquely identifying the device configuration parameter. Should not start with $ character

paramType

indicates the config parameter type between

"INT32"

the value must be an integer from -2,147,483,648 to 2,147,483,647,

"UINT32"

the value must a positive integer from 0 to 4,294,967,295,

"BINARY"

the value is a base64 encoded binary content,

"STRING"

the value is a UTF-8 string,

"FLOAT"

the value is float (64 bits) value.

Example:

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/config
{
    "parameters": {
        "MyParamINT32" : {
            "type" : "INT32",
            "value" : -333
        },
        "MyParamSTRING" : {
            "type" : "STRING",
            "value" : "My sentense"
        }
    },
    "notifyTo": "fifo/configUpdateFifo"
}
8.2.3.2. Response

HTTP Code:

200 OK

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

If the device does not exist, it will be auto-provisionned.

8.2.4. Get a description of the device configuration

8.2.4.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/<deviceId>/config

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/config
8.2.4.2. Response

HTTP Code:

200 OK

Body:

JSON Params Description

parameters

list of device configuration update

notifyTo

Optional. topic where configuration change/sync events must be published to

For each parameter, the following information is available :

{
  "parameters" : {
      "{paramKey}": {
          "reported": {
              "type": {paramType},
              "value": {paramValue},
              "timestamp": {timestampsValue}
          },
          "requested": {
              "type": {paramType},
              "value": {paramValue},
              "timestamp": {timestampsValue}
          },
          "syncStatus": {paramStatus}
      }
  }
  "notifyTo": ""
}

With:

paramKey

string uniquely identifying the device configuration parameter

paramType

indicates the config parameter type between: INT32, UINT32, BINARY, STRING or FLOAT,

paramValue

value requested for the parameter,

timestampsValue

update date of the parameter,

paramStatus

parameter update status; NONE, PENDING, SENT, OK or FAILED.

The section reported is present when the device has answered and corresponds to parameter configuration return by the device, the paramStatus could be OK or FAILED.

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

404

DM_DEVICE_NOT_FOUND

Device not found

Example:

{
    "parameters": {
        "MyParamFLOAT": {
            "requested": {
                "type": "FLOAT",
                "value": 1245,
                "timestamp": "2018-03-07T10:55:21Z"
            },
            "syncStatus": "PENDING"
        },
        "MyParamBINARY": {
            "requested": {
                "type": "BINARY",
                "value": "Nzg3ODY4Ng==",
                "timestamp": "2018-03-07T10:54:55.948Z"
            },
            "syncStatus": "SENT"
        },
        "MyParamINT32": {
            "reported": {
                "type": "INT32",
                "value": -333,
                "timestamp": "2018-03-07T10:53:21.934Z"
            },
            "requested": {
                "type": "INT32",
                "value": -333,
                "timestamp": "2018-03-07T10:53:21.937Z"
            },
            "syncStatus": "OK"
        }
    },
    "notifyTo": "fifo/configUpdateFifo"
}

8.2.5. Get state of a specific device configuration parameter

8.2.5.1. Request

Endpoint:

GET /api/v1/deviceMgt/devices/<deviceId>/config/parameters/<paramKey>

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Example:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/config/parameters/MyParamFLOAT
8.2.5.2. Response

HTTP Code:

200 OK

Body:

JSON Params Description

reported

Optional. reported configuration parameter value

requested

requested configuration parameter value

syncStatus

parameter update status; NONE, PENDING, SENT, CANCELED, OK or FAILED

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

404

DM_DEVICE_CONFIG_PARAM_NOT_FOUND

Device configuration parameter not found

Example:

{
    "requested": {
        "type": "FLOAT",
        "value": 1245,
        "timestamp": "2018-03-07T10:55:21Z"
    },
    "syncStatus": "PENDING"
}

8.3. Commands

This section describe how to set up command requests before sending them to the devices.

The Concepts and API described in this chapter allows to manage commands for MQTT, LoRa®, SMS and external connector interfaces.

8.3.1. Principle

A command request is a downlink message that Live Objects sends to the device, with acknowledgement mechanism. Depending on the interface (protocol & connectivity) used, a command response can be sent by the device to Live Objects.

You can register commands targeting a specific device: as soon as an interface for this device is available for commands, Live Objects will send them one by one, waiting for an acknowledgment for each command before sending the next one.

There is a limitation of 10 queued commands for a specific device.

Live Objects keeps a record of every registered command with its status, and possible response after processing by device.

The command control mechanism consists of two sub-mechanisms :

  • an application sub-mechanism that manages the displayed command statuses for the buisness applications and apply command cancel if need.

  • an additional sub-mechanism that manages the command delivery status to the device using the connectors.

8.3.2. Command status

The commands can have the following states:

Status Description

PENDING

The command is recorded and waiting for processing

RETRYING

The command has encountered an error, and will be retried. (same behaviour as PENDING)

PROCESSING

The command is being processed by the dedicated interface (waiting for an acknowledge)

PROCESSED

The command has reached its final acknowledgement level (FINAL STATE)

ERROR

An error occurred during the processing of the command (FINAL STATE)

CANCELED

The command was canceled before reaching PROCESSED state (FINAL STATE)

EXPIRED

The command could not be processed within the time limit (expirationTimeoutInSecond) (FINAL STATE)

Here is a status diagram with possible transitions:

Device commands states

Interactive

8.3.3. Command status summary table

Table 3. Here is the list of possible command statuses provided by each connectivity

Command Status \ Connector

LoRa®

MQTT

SMS

External Connector

PENDING

PROCESSING

PROCESSED

EXPIRED

CANCELED

RETRYING

ERROR

8.3.4. Delivery status

During the PROCESSING state, the device manager exposes an additional information: the delivery status. The delivery status provides more detailed information on the processing step of the command, based on the acknowledgement information available, depending on the connectivity used.

Device commands delivery states

Interactive

8.3.5. Acknowledgement level

The acknowledgement level determines the transition from the PROCESSING state to the PROCESSED state of a command.

The device manager offers three different levels of acknowledgement:

  • NONE : The device manager only listens to the internal acknowledgement that notifies the sending of the command. The command is output from Live Objects. Equivalent to the delivery status SENT

  • NETWORK : The device manager waits for protocol acknowledgment. Equivalent to the delivery status DELIVERED

  • APPLICATIVE : The device manager waits for an applicative acknowledgement, with potentially a response. Equivalent to the delivery status REPLIED

For each connector, the acknowledgement level implies a specific delivery status as described in MQTT acknowledge/status, LoRa® acknowledge/status, SMS acknowledge/status, External connector acknowledge/status.

8.3.6. Expiration Timeout

In most cases, the device availability cannot be accurately predicted, due to connectivity reason for example. In some cases, we need the command to be executed in a near future or not at all.

Let’s return to the example of our connected lock: when we send an "unlock" command, we want that the command will be executed within the next two minutes, not in three hours due to a connectivity issues.

The command API proposes the expiration timeout (default: 7 days, min: 5 seconds, max: 30 days). This is the maximal amount of time allowed to reach the status PROCESSING. If this value is exceeded, the status of the command goes to the status EXPIRED.

8.3.7. Acknowledgement Timeout

The command API proposes the acknowledgement timeout. This is the maximal amount of time allowed to reach the status PROCESSED when command is being processed (status PROCESSING). If this value is exceeded, the status of the command goes to the status ERROR with the error code ACK_TIMEOUT.

For each connector, the acknowledgement level implies a specific delivery status as described in MQTT ack timeout value, LoRa® ack timeout value, External connector ack timeout value.

A command with NONE acknowledgement cannot have acknowledgement timeout. For the other cases, an acknowledgement timeout is enforced.
Do not hesitate to customize this value. A value adjusted to your needs allows for better error detections, as well as a better reactivity of the command process

8.3.8. Attempts number

For some reasons (network issues, or acknowledgement default), a command can reach the acknowledgement timeout. In this case, we may have to retry sending command. This is the purpose of the attempts field in the command policy.

If another attempt can be made, instead of ERROR, the command status is set to RETRYING, equivalent to the PENDING status, but showing that it’s not the first attempt. Then, the command is treated normally.

If all attempts have been used, the command status is set to ERROR.

The default value of attempts is 1, which means there will be no retries. The maximum value is 5 (first attempt + 4 retries)
If the command status is RETRYING and the expiration timeout is reached, the new attempts is abort, and the command status is set to EXPIRED (same behavior as PENDING). It is advisable to define an expiration timeout upper than (acknowldegement timeout x (attempts - 1))

8.3.9. Command object model

We will detail the command object model of the device manager, as used in API v1.

All possible operations on this object are detailed in the swagger.

Here is an unrealistic example, using a blank interface :

{
    "id": "ae49129f-9ce4-4782-82c4c6a2",
    "targetDeviceId": "urn:lo:nsid:sensor:2327398",
    "request": {
        "connector": "...",
        "value": {
            [...]
        }
    },
    "response": {
      [...]
    },
    "status": "PROCESSED",
    "deliveryStatus": "REPLIED",
    "errorCode": "INVALID_COMMAND_REQUEST",
    "policy": {
        "expirationInSeconds": 120,
        "ackTimeoutInSeconds": 180,
        "ackMode": "APPLICATIVE",
        "attempts" : 1
    },
    "history": [
        {
            "timestamp": "2017-12-06T11:32:25.055Z",
            "status" : "PENDING"
        }, {
            "timestamp": "2017-12-06T11:38:22.481Z",
            "status": "PROCESSING",
            "deliveryStatus": "SENT",
            "errorCode": "INVALID_COMMAND_REQUEST",
            "nodeId": "2327398"
        }, {
            "timestamp": "2017-12-06T11:38:24.124Z",
            "status": "PROCESSED",
            "deliveryStatus": "REPLIED",
            "nodeId": "2327398",
        }
    ],
    "created": "2017-12-06T11:32:25.055Z",
    "updated": "2017-12-06T11:38:24.124Z"
}

The root fields are as follows:

JSON Params Description

id

Unique id of the command

targetDeviceId

Targeted device identifier

request

Command request (Cf. command request format)

response

Optional. Command response from device

status

Status of the command. Please refer to Command status for more details.

deliveryStatus

Optional. Delivery status of the command. Please refer to Delivery status for more details.

errorCode

Optional. Error code encountered during command processing.

policy

Policy for the command (Cf. Policy format)

history

Contains the history of changes in the status of the command. (Cf. Command history)

created

Registration date of the command

updated

Last "status" update date of the command.


The format of a command request is the following:

JSON Params Description

connector

connector/protocol to use to forward the command. Allowable values: mqtt, lora, sms or x-connector.

value

command value (protocol/connector-dependant) (Cf. MQTT value, LoRa® value, SMS value, External connector value)


The format of the policy for a command is the following:

JSON Params Description

expirationInSeconds

Optional. expiration in seconds since command creation date. (Cf. Expiration Timeout).

ackTimeoutInSeconds

Optional. acknowledgement timeout in seconds since command is being processed. Default depends on connectiviy. Min value is 10 seconds (Cf. Acknowledgement Timeout).

ackMode

Optional. Ack mode for this command. Please refer to Acknowledgement level for more details.

attempts

Optional. Number of attempts in case of ERROR. Default to 1 Please refer to Attempts number for more details.


The format of the history for a command is an array of this:

JSON Params Description

timestamp

Timestamp of this event

status

Status of the command at that moment

deliveryStatus

Optional. Delivery status of the command at that moment

errorCode

Optional. Error code encountered during command processing.

nodeId

Optional. NodeId of the interface used to process the command


8.3.10. Command registering by connector

For each kind of connectivity, the command registering uses specific values, the final delivery status is also different according to acknowledgement level.

8.3.10.1. Case of MQTT
To see how the commands are processed by device and to learn more, see the command section "device mode"
8.3.10.1.1. Delivery status behaviour according to acknowledgement level
Acknowledgment NONE (just sent the command) APPLICATIVE (waiting for response to validate)

Description

MQTT connector sent the command through open connection

Applicative response from device (default value)

Sequence of events & evolution of the statuses

Interactive

Interactive

Final Success Delivery Status

SENT

REPLIED

Default acknowledgement timeout

-

24h (7 days with v0 API), and the maximal value is 7 days.

8.3.10.1.2. Values for command registration

Value field can be any valid JSON Interactive

JSON Params Description

req

the command in string format

arg

List of parameters. Should not contain field name with . character or start with $ character

Example: Let’s take the case of a command recorded for a device with an online MQTT interface, with an APPLICATIVE acknowledgement level.

{
    "request": {
        "connector": "mqtt",
        "value": {
            "req": "reboot",
            "arg": {
                "delay": 1000
            }
        }
    },
    "policy": {
        "expirationInSeconds": 120,
        "ackMode": "APPLICATIVE"
    }
}

Please refer to the MQTT device mode part for messages that your device can send or receive.

To see an example, go to MQTT Command Example section.
8.3.10.2. Case of LoRa®
8.3.10.2.1. Delivery status behaviour according to acknowledgement level
Acknowledgment NONE (just sent the command) NETWORK (waiting for network/protocol ack)

Description

Downlink report received (default value)

Downlink acknowledge received

Sequence of events & evolution of the statuses

Interactive

Interactive

Final Success Delivery Status

SENT

DELIVERED

Default acknowledgement timeout

-

For LoRa®, the acknowledgement rely on a double mechanism: - first correlated with the device traffic: the LoRa® connector waits maximum 3 uplinks to get an ACK bit set to 1. Beyond 3 uplinks without ACK bit acknowledgement timeout is reached. - second is acknowledgement timeout delay: default: 7 days, max is 7 days.

8.3.10.2.2. Values for command registration

Interactive

Value field in request command sets the following parameters:

JSON Params Description

data

hexadecimal raw data of the command

port

port of the device on which the command will be sent (1 to 254)

Example:

{
    "request": {
            "connector":"lora",
            "value":{
                    "data": "A1FF20",
                    "port": 1
            }
    },
    "policy": {
            "expirationInSeconds" : 200,
            "ackMode": "NONE"
    }
}
To see an example, go to LoRa® Command Example section.
8.3.10.3. Case of SMS
8.3.10.3.1. Delivery status behaviour according to acknowledgement level
Acknowledgment NONE (just sent the command)

Description

Message sent (default value)

8.3.10.3.2. Values for command registration

Interactive

Value field in request command sets the following data:

JSON Params Description

payload

message to send

TEXT : size max 160 characters and GSM 7 compatible characters (for more information, see GSM 03.38 standard or chapter 6.2.1 of www.etsi.org/deliver/etsi_gts/03/0338/05.00.00_60/gsmts_0338v050000p.pdf)

BINARY : size max 260 characters (140 octets) and hexadecimal characters

serverPhoneNumber

server phone number. Must be defined in the offer settings

type

message format in TEXT or BINARY

Example:

{
    "request": {
            "connector": "sms",
        "value": {
            "payload": "Hello Live Objects!",
            "type": "TEXT",
            "serverPhoneNumber": "20406"
        }
    },
    "policy": {
            "expirationInSeconds" : 30,
            "ackMode": "NONE"
    }
}
To see an example, go to SMS Command Example section.
8.3.10.4. Case of External connector
8.3.10.4.1. Delivery status behaviour according to acknowledgement level
Acknowledge required NONE (just sent the command) APPLICATIVE (waiting for response to validate)

Description

External connector sent the command through open connection

Applicative response from device (default value)

Sequence of events & evolution of the statuses

Interactive

Interactive

Final Success Delivery Status

SENT

REPLIED

Default acknowledgement timeout

-

For External connector, the default value of acknowledgement timeout is 24h, and the maximal value is 7 days. Beyond that, the acknowledgement timeout is reached

8.3.10.4.2. Values for command registration

Interactive

Value field in request command can be any valid JSON. It can contain a map of 100 entries maximum. Each entry can contain 255 characters maximum.

Example: Let’s take the case of a command recorded for a device with an online external connector interface, with an APPLICATIVE acknowledgement level.

{
    "request": {
      "connector": "x-connector",
      "value": {
        "myCommand": "turn on",
        "myParams": {
          "device": "6"
        }
      }
    },
    "policy": {
      "expirationInSeconds": 60,
      "ackMode": "APPLICATIVE"
    }
  }

8.3.11. Command examples by connector

8.3.11.1. Example for Mqtt

Let’s take the example of a smart lock, connected to Live Objects with an MQTT interface.

8.3.11.1.1. Description

From your smartphone, you want to unlock your door for a family member who forgot his keys. The application on your phone will create a command on Live Objects, who will send it to the door

  • You want to know if your unlock request has been well executed.

  • You need to set the maximum waiting time for your order to be executed : 2 minutes here, not three hours due to a connectivity issues.

To do this, you must :

  • Have smartphone business application connected to LO.

  • A smart lock system online who subscribe to the topic dev/cmd on Live Objects

  • Your device must support command capability (check the device before beginning).

Then apply this steps :

  • Send a command request.

  • Wait the processing time

  • Check the result from your smartphone.

8.3.11.1.2. Command request details

Your smartphone have to send the following request to LO :

API : POST /api/v1/deviceMgt/devices/<deviceId>/commands

Request sample :

{
    "request": {
        "connector": "mqtt",
        "value": {
            "req": "unlock",
            "arg": {
                "delay": 1000
            }
        }
    },
    "policy": {
        "expirationInSeconds": 120, (1)
        "ackMode": "APPLICATIVE"    (2)
        "ackTimeoutInSeconds": 180, (3)
    }
}
1 When you register a command you must set the expiration timeout, to fix a limit delay for PENDING/RETRYING status, this means that once the command has been registred, Live Objects will wait for a device subscription to the corresponding topic under this delay. Once this delay exceeded without new event from the device, the command status change automatically to EXPIRED.
2 Depending on the acknowledgement level you have set, Live Objects will wait for a response from the smart lock.
3 If you have set the ackMode to applicative, you can also override the acknowledgement timeout to limit the maximum response time allowed to the device. In this case, we choose an APPLICATIVE acknowldegment level, so a response from the device is mandatory.
8.3.11.1.3. Process of the successful case

Interactive

8.3.11.1.4. Timeouts during the process

Two kind of timeouts can happen : Expiration & Acknowledgment timeouts.

Interactive

8.3.11.1.5. Check the status of the command

At anytime during process, you can check the command status or get the whole command

Interactive

API : GET /api/v1/deviceMgt/commands/{commandId}/status

Response :

{
"content": "PROCESSED"
}

Response for the entire command, the request is the same but use another endpoint

API : GET /api/v1/deviceMgt/commands/<commandId>

Response :

{
    "id": "ae49129f-9ce4-4782-82c4c6a2",
    "targetDeviceId": "urn:lo:nsid:smartlock:123456",
    "request": {
        "connector": "mqtt",
        "value": {
            "req": "unlock",
            "arg": {
                "delay": 1000
            }
        }
    },
    "response": {
        "done": true
    },
    "status": "PROCESSED",
    "deliveryStatus": "REPLIED",
    "policy": {
        "expirationInSeconds": 120,
        "ackTimeoutInSeconds": 180,
        "ackMode": "APPLICATIVE"
    },
    "history": [
        {
            "timestamp": "2017-12-06T11:32:25.055Z",
            "status" : "PENDING"
        }, {
            "timestamp": "2017-12-06T11:38:22.481Z",
            "status": "PROCESSING",
            "deliveryStatus": "SENT",
            "nodeId": "abcd123456"
        }, {
            "timestamp": "2017-12-06T11:38:24.124Z",
            "status": "PROCESSED",
            "deliveryStatus": "REPLIED",
            "nodeId": "abcd123456"
        }
    ],
    "created": "2017-12-06T11:32:25.055Z",
    "updated": "2017-12-06T11:38:24.124Z"
}
8.3.11.2. Example for LoRa®

Let’s take the example of a smart sensor of water metering, connected to Live Objects with LoRa® interface.

8.3.11.2.1. Description

The objective is to monitor a water usage monthly. To do this, you must :

  • Send a "reset to zero" command to the water meter at the end of the month.

    • The command will be sent in a binary format supported by LoRa® connectivity.

  • Have water meter system connected to Live Objects with LoRa® interface.

Then apply this steps :

  • Register command through Live Objects portal or your business application.

  • Follow the command status during the operation.

  • Check the result

The LoRa® devices has a low energy consumption as well as sleeping time is relatively long. So, the command request takes time to be processed. The expiration timeout must be set with high values.
8.3.11.2.2. Command processing policy

-Set your command processing policy before registering_

POST /api/v1/deviceMgt/devices/urn:lo:nsid:lora:watermeter123/commands

{
    "request": {
        "connector": "lora",
        "value": {
            "data": "44D2F0",
            "port": "125"
        }
    },
    "policy": {
        "expirationInSeconds": 28800,  (1)
        "ackMode": "NETWORK"           (2)
    }
}
1 The expiration timeout can be setted to replace the default limit delay for PENDING/RETRYING status.
2 Depending on the acknowledgement level setted, Live Objects will wait for a response from the water meter. In this case, we choose a NETWORK acknowldegment level, so a response from the LoRa® network is mandatory.

The acknowledgment timeout can’t be setted by the customer

8.3.11.2.3. Process of the successful case

Interactive

8.3.11.2.4. Timeouts during the process

Two kind of timeouts can happen : Expiration & Acknowledgment timeouts.

Interactive

8.3.11.3. Example for SMS

We return to the example presented previously of a smart lock with the MQTT interface, in this example we have connected our Unlock system to Live Objects with an SMS interface.

Now we register a command through an SMS interface and Live objects will be sent this command with an SMS message to connected device.

8.3.11.3.1. Register command
POST /api/v1/deviceMgt/devices/urn:lo:nsid:sms:unlock123/commands
{
    "request": {
      "connector": "sms",
      "value": {
        "payload": "unlock",
        "type": "TEXT"
      }
    },
    "policy": {
        "expirationInSeconds": 60,  (1)
        "ackMode": "NONE"           (2)
    }
 }
1 When you register a command you must set the expiration timeout, to fix a limit delay for PENDING/RETRYING status, this means that once the command has been registred, Live Objects will wait until the request was sent. Once this delay exceeded, the command status change automatically to EXPIRED. (This can happen if you have paused your SMS interface for exemple) In this case, after 60 seconds waiting, Live Objects change the status of the command at EXPIRED.
2 When your device use SMS interface, only ackMode NONE is supported.
8.3.11.3.2. Register a binary command

The same example with a binary command

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sms:unlock123/commands
{
    "request": {
      "connector": "sms",
      "value": {
        "payload": "756e6c6f636b", (1)
        "type": "BINARY"           (2)
      }
    },
    "policy": {
        "expirationInSeconds": 60,
        "ackMode": "NONE"
    }
 }
1 Payload in hex format, converted from string = "unlock".
2 Payload type must be set with value = BINARY

8.4. Resources

8.4.1. Principle

LiveObjects offers a resource feature that allow customers to follow devices reported resources, manage new resource versions, and update device resource with fresh version.

The main goal is to provide resource update facility, where the update principle is :

  • The Device connects and exchanges with LiveObjects.

  • The Customers defines some resources for his tenant,

  • The Customers asks LiveObjects to update device resource versions for some devices.

  • The Device communicate with LiveObjects to process the update.

  • LiveObjects reports to the Customer the current state of updates and device resources.

8.4.1.1. Manage and follow resource update

LiveObjects provides to the Customer DM resource related API in order to:

Manage resource inventory for his tenant :

  • add, update, remove resource versions,

Manage device resources :

  • get device resources reported versions,

  • set, or reset device resources requested versions,

Follow and manage update operations :

  • create device resource update operation.

  • cancel an update.

  • get, or list device updates states,

Manage and follow resource update

Interactive

Here is an example of Customers in-sequence actions :

  • create a new resource version for his tenant,

  • async trigger an update by setting a requested versions for a given device,

  • get latest device update to track update operation state.

8.4.1.2. Resource versions management

A resource is a versioned binary content (for example a device firmware). You can manage a repository of resources in your tenant account.

For each resource you can manage multiple resource versions.

Live Objects can track the current versions of resources on a specific device.

Customers can plan an update by setting a requested version for a given device resource version, or can order immediately an update.

Device resource requested versions Device resource versions updated

Interactive

Interactive

Optional compatibility restrictions can be configured between versions to avoid compatibility issues when switching from a version to another.

Live Objects will refuse a resource update request that don’t match the compatibility restrictions.

8.4.1.3. Different kind of updates

As today, Live Objects supports two kind of updates:

  • a resource update that rely on http-updater updater (with mqtt devices):

LiveObjects provides the resource in the form of a secure (https) or insecure (http) URL. Then the Device will decide when to act as http client and query that URL to retrieve the content.

  • a resource update that rely on lwm2m-updater updater with Lwm2m devices (Beta):

LiveObjects rely on Twin to send LwM2M operations, and will send the resource to the Device via downlink operation (ex. Twin write).

Here is a summary of resource updates mode compatibility and feature matrix

Updater Connectivity Update trigger

http-updater

MQTT

* set requested version * or create update

lwm2m-updater

LwM2M

* create update

8.4.2. Resources inventory

8.4.2.1. Resources and versions definitions

Customer defines for his tenant a set of resources.

A resource is

  • a resourceId : a unique identifier (ex. X113DevFirmware, EPROM7300_V12).

  • a connector,

  • some meta-data,

  • (option) some aliases.

For each resource, Customer then defines one or more resource versions.

A resource version is:

  • a given unique version identifier (ex. 1.0, 1.1a),

  • a file content,

  • a checksum of the file content,

  • an optional list of the compatible versions from which you can update to this firmware.

8.4.2.2. Resources aliases

You can configure zero, one or several aliases on a resource to help you manage your resource update operations.

An alias can be used to replace with a string of your choice a resource version when requesting a new target for a resource.

For example you could create an alias preprod to refer or target the 1.1a resource version.

You can use up to 5 aliases per resource.

A same version can be used in several aliases. An alias key must be unique.

8.4.2.3. Resources versions compatibility

When a resource version includes at least one or more compatible versions, LiveObjects must check that the current device resource reported version is compatible in order to target an update to this resource version.

When a resource version compatible versions is empty or missing, LiveObjects is able to target an update to this resource version without version check.

For example, if 1.1a compatible versions are [0.8, 1.0, 1.1], then

  • a device which reports 0.8 as current version is compatible

  • whereas a device which didn’t report current version, or which reports 0.9 (or 1.2) version is NOT compatible and cant be updated to 1.1a.

8.4.2.4. Resource definition API examples

Create a new resource

POST /api/v0/rm/X113DevFirmware
{
  "connector": "http-updater",
  "resourceId": "X113DevFirmware",
  "label": "X113 DEV",
  "description": "X113 firmware of box, in DEV mode.",
  "metadata": {
    "BoxSeriesSuffix": "FF1Fxx42"
  }
}

Response

{
    "tenantId": "5ae04ef29a92790fd7f2a5e4",
    "resourceId": "X113DevFirmware",
    "label": "X113 DEV",
    "description": "X113 firmware of box, in DEV mode.",
    "connector": "http-updater",
    "metadata": {
        "BoxSeriesSuffix": "FF1Fxx42"
    },
    "creationTs": 1677496010873,
    "updateTs": 1677496010873
}

Remove a given resource

DELETE /api/v0/rm/X113DevFirmware

Create a new resource version

POST /api/v0/rm/X113DevFirmware/version
{
  "file": "iVBORw0KGgoAAAANSUh...UVORK5CYII=",
  "checksum": "9WeAuNlX/WaappCx4sSMYQ==",
  "resourceVersionId": "1.0",
  "compatibleVersions": ["0.5","0.8","0.9"]
}

This sample adds a new X113DevFirmware firmware resource version 1.0. This version is compatible with following versions: 0.5, 0.8, 0.9.

  • file attribute is base64 encoded file content (abbreviates in the example above).

  • checksum is md5 of the raw firmware content encoded in base64.

Example of generating md5 checksum :

  import com.google.common.hash.Hashing;
  import com.google.common.io.BaseEncoding;
  import java.io.File;
  import java.nio.file.Files;
  import org.apache.commons.io.FileUtils;
  import org.junit.Test;

  // ...

  File file = new File("C:/tmp/myFirmware.bin");

  byte[] fileBytes = FileUtils.readFileToByteArray(file);
  String fileB64 = BaseEncoding.base64().encode(fileBytes);

  byte[] fileMd5Sum = Hashing.md5().hashBytes(fileBytes).asBytes();
  String fileB64OfMd5Sum = BaseEncoding.base64().encode(fileMd5Sum);

  System.out.println("::fileB64> " + fileB64);
  System.out.println("::checksum> " + fileB64OfMd5Sum);

Remove a given resource version

DELETE /api/v0/rm/X113DevFirmware/version/1.0

This sample removes X113DevFirmware firmware resource version 1.0.

8.4.3. Version management

8.4.3.1. Device declaration

Depend of the protocol, the device could report the current version of his resources.

This device initiated declaration is mandatory when relying on resources with compatibility restrictions.

But LiveObjects is also able to execute update operation without device declaration when relying on resources with NO compatibility restrictions.

  • For MQTT, please refer to Current Resources publication section.

  • For LwM2M, as today there is no device declaration, and so update must rely on resources without compatibility restrictions.

8.4.3.2. Version operation
8.4.3.2.1. Set or Reset requested version

Customer can set requested versions on devices :

In order to plan an update, Customer can record some intention : set a requested versions on one or more device resources.

This way represent an asynchrone trigger of the update operation because the update operation is created at LiveObjects initiative: when we know that the device is compatible, and when the device is ready to accept a new update (cf. conditions bellow).

Customer can reset requested versions on devices :

To remove any update intention, the reset operation will clean the requested version.

In that case, there is a chance that the update were already created/started : in that case LiveObjects will cancel related update too.

8.4.3.2.2. Create an update

Customer can create an update operation on devices :

In order to immediately trigger an update, LiveObjects let you create a device update directly. This way represent a synchrone trigger of the update operation: the update operation is started at Customer initiative.

This operation may be immediately rejected in some case:

  • we already know that the device is not compatible,

  • an update is already in progress on that device.

When the device is not ready, or when we don’t know if he is compatible, then the update will stay in his initial state(PENDING), and will progress later.

8.4.3.2.3. Update trigger

Here is a summary of updates conditions

Updater Connectivity Update conditions

http-updater

MQTT

Mqtt connection is established, the device is listening resource update requests, and the compatibility restrictions (if any) are fulfilled.

lwm2m-updater

LwM2M

LwM2M device is connected, the device supports and instantiate the first Firmware Object (/5/0), and the target resource has no compatibility restrictions

8.4.3.3. Version management API examples
8.4.3.3.1. Set device resource requested version

Request

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/resources/MyResource001
{
    "version": "1.1",
    "metadata" : {
        "secured" : true
    }
}

Response

{
  "reported": {
    "version": "1.0",
    "timestamp": "2020-03-12T10:43:18.350Z"
  },
  "requested": {
    "version": "1.1",
    "timestamp": "2020-07-23T14:53:03.959Z"
  }
}
JSON Params Description

reported

current device resource status

requested

requested resource status

version

resource version

timestamp

date of resource version association

metadata

metadata associated with this device (if any)

8.4.3.3.2. Set device resource version using alias

Configure an alias

Request

PUT /api/v0/rm/MyResource001
{
  "connector": "http-updater",
  "metadata": {
    "secured": true
  },
  "versionAliases" : {
      "prod" : "1.1",
      "preprod" : "1.2"
  }
}

Response

{
  "resourceId" : "MyResource001",
  "connector" : "http-updater",
  "metadata" : {
    "secured" : "true"
  },
    "versionAliases" : {
      "prod" : "1.1",
      "preprod" : "1.2"
  },
  "creationTs" : 1563191282476,
  "updateTs" : 1595594676082
}

Set requested version alias

Request

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/resources/MyResource001
{
    "version": "prod",
    "metadata" : {
        "secured" : true
    }
}

Response

{
  "reported": {
    "version": "1.0",
    "timestamp": "2020-03-12T10:43:18.350Z"
  },
  "requested": {
    "version": "1.1",
    "timestamp": "2020-07-23T14:53:03.959Z"
  }
}

The requested alias must exist and meet the compatibility restrictions

8.4.3.3.3. Reset device resource version

Request

DELETE /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/resources/MyResource001/requested

This DELETE call will remove the requested version of the device resource MyResource001 if related update has not been triggered.

If an update already exists for this device resource, then requested version is untouched. If the update is active, internally, a soft cancel is done.

8.4.3.3.4. Create resource update

Request

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/resources/MyResource001/updates
{
  "requestedVersion": "1.0",
  "connector": "http-updater",
  "metadata": {
    "secured": true
  }
}

Response

{
    "id": "5f3bf1ecb23f3277805478a7",
    "resourceId": "MyResource001",
    "created": "2023-03-02T15:21:16.128Z",
    "updated": "2023-03-02T15:21:16.128Z",
    "initialVersion": "0.8",
    "requestedVersion": "1.0",
    "connector": "http-updater",
    "status": "PENDING",
    "metadata": {
      "secured": true
    }
 }
JSON Params Description

resourceId

device resource to update

created

resource update creation date

updated

resource update update date

initialVersion

device resource initial version

requestedVersion

device resource requested version

connector

updaterConnector to use. Can be http-updater OR lwm2m-updater

metadata

metadata associated to this update

8.4.4. Update Operation

8.4.4.1. Update states

Customer can get, or list resource updates.

This is different states values for a resource update :

State Description

PENDING

This is update operation initial state. The device is not yet ready or didn’t report his current version.

PREPARING_CONNECTOR

The update operation is now in progress and related update connector is initializing (internal).

PREPARING_ASSET

verify the device state or ask to the device to accept update.

WAITING_TRANSFER_INFO

waiting the device to accept the update

TRANSFER_PENDING

resource transfer is ready to start

TRANSFER_IN_PROGRESS

resource transfer is in progress

TRANSFER_SUCCESS

resource transfer is just done with success

CANCELED

The update operation has been canceled. This is a final state.

ERROR

The update operation has failed. This is a final state.

DONE

The update operation is done successfully. This is a final state.

8.4.4.2. Update timeouts

An active update has 2 timeout windows:

  • after the resource update request (LiveObjectsDevice request with http-updater update).

  • for the overall update (for http-updater, and lwm2m-updater updates).

After the resource update request:

  • the device does not confirm the resource update request and does not download or report the version. After 5 minutes, the update returns to the PENDING state.

  • the device accepts the resource update request but does not download or report the version. After 5 minutes, the update will end with a timeout error (ERROR state).

For the overall update

  • an active update (update with a state not in DONE,CANCELED,ERROR) MUST NOT be older than 24 hours. After 24 hours, the update will end with a timeout error (ERROR state).

8.4.4.3. Cancel an update

There is multiple ways to cancel an update :

  • reset device resource requested version to cancel a set requested version,

  • soft cancel a resource update.

  • hard (aka. force) cancel a resource update.

The "reset" method will clean an expected requested version. If the update has already been triggered and is always active, a soft cancel is internally done.

The "soft" cancel update method will interrupt an active update in the following state : PENDING, PREPARING_CONNECTOR.

The "hard" cancel update method will interrupt an active update in the following state : PENDING, PREPARING_CONNECTOR, PREPARING_ASSET,WAITING_TRANSFER_INFO, TRANSFER_PENDING, TRANSFER_IN_PROGRESS, TRANSFER_SUCCESS.

8.4.4.4. Update API examples
8.4.4.4.1. Cancel resource update

Request

POST /api/v1/deviceMgt/devices/urn:lo:nsid:sensor:temp001/resources/updates/MyResource001/status?force=true
CANCELED

Response

HTTP Code:

200 OK

8.4.5. Updaters

In order to send the binary content to a device, Live Objects is built to provide different type of transfert protocols.

Those protocols are handled by updaters.

Updaters can support configuration parameters called metadata.

  • Http-updater

Live Objects provides a http-updater updater that allows the device to download the resource using HTTP protocol.

http-updater supports the following metadata:

Meta-data Description

secured

To enable https link for resources update, the default value is set to false (i.e. http link). It’s possible to set this "secured" metadata from device resource metadata, resource metadata, or update operation metadata.

  • Lwm2m-updater

Live Objects provides a lwm2m-updater updater connector that rely on LWM2M Specifications to process an update.

As today lwm2m-updater supports the "in-band" mode and rely on "Firmware(5)" object to read device firmware status, write, then execute firmware package and read firmware update result.

lwm2m-updater has no specific metadata:

8.4.5.1. http-updater resource update

Currently, APIs allow to manage resource http-updater update only for MQTT connector.

Live Objects will prepare the resource on public available endpoint and send update information to the device.

The device is responsible to download the resource, and then report his state to LiveObjects .

Trigger

How to trigger an out-of-band update:

  • You can set the requested version of resources for a specific device in Live Objects that will then try to update the resources on the device as soon as the device is available for resource update.

  • You can trigger by creating an update directly.

step 1 - Resource update context

If your device is connected in "Device mode", please refer to the MQTT device mode part for messages that your device can send or receive. There is some practical examples in Resources update section like Current Resources publication.

step 1) Device resource update context

Interactive

step 2 - New update

  • customer creates an update directly via API. cf. create resource update example.

  • or Live Objects automatically triggers an update for not honored requested resource versions set.

Pre-requisites: a new update is activated when

  • the device is ready to receive resource update (resource capability is available),

  • there is no update in progress.

When there is compatibility restrictions, then the device resource current version MUST be known.

Device resource update steps

Interactive

step 3 - Prepare connector

  • Live Objects prepares the resource version binary and generates a download link.

step 4 - Prepare asset

  • Live Objects sends the download link and resource version id to the device

  • optional the device can respond to indicate whether it accepts the new resource version or not.

  • optional the device can send a customized error. The operation will be stated as failed

step 5 - Transfer

  • the device can download the binary.

  • optional at anytime, the operation can be cancelled. In this case Live Objects will remove the download link. cf. the section dedicated to cancellation.

  • when the device does not start the download, then timeout can occur cf. section dedicated to timeout.

  • when the device has not responded to the request and does not start the download, the update returns to the PENDING state.

step 6 - Final

  • download is done

  • the device can check the file integrity using the provided md5, and perform internal updates.

  • to acknowledge the binary reception and the update, the device sends a new current resources message.

  • Live Objects compares the current and expected resource version and updates the operation status accordingly.

http-updater resource update states

Device resource update states

Interactive

8.4.5.2. lwm2m-updater resource update - (Beta)

APIs allow to manage lwm2m-updater resource update only for LWM2M connector.

Live Objects will prepare te resource and send it to the device with a downlink operation.

The device MUST be compliant with related standard to accept the resource, and report his state to LiveObjects.

Trigger

How to trigger an lwm2m-updater update:

  • You can trigger by creating an update directly.

step 1 - Resource update context

  • the customer defines some resources, and some resource versions.

As today, you must use resource without compatibility restrictions.

step 2 - New update

Pre-requisites: a new update is activated when

  • the device is ready to receive resource update (resource capability is available) : Lw device is connected and instantiate object /5/0,

  • there is no update in progress.

Device resource update steps

Interactive

step 3 - Prepare resource

  • LiveObjects internally prepares the requested resource version content to send.

step 4 - Prepare device: await device initial state

  • LiveObjects will use Twin operations to ask to the device the Firmware state (/5/0/3).

  • In order to start a firmware update sequence, the device state MUST be 0:IDLE.

  • On unexpected initial state, the update state is moved back to PENDING. So the update will be retried later.

  • On issue while reading this state, the update is moved to ERROR.

option - Interruption

During an update in progress, some interruptions can occur:

NOTE: once the update request (step 4 - prepare device) has been sent, the cancel or timeout interruption impacts only on the update state. Customer can order a new update that will overwrite current residual update operation and restart a fresh update from scratch.

step 5 - Transfer : in-band write operation

  • Live Objects sends the firmware package to the device.

  • Live Objects will rely on Twin WRITE operation to In-band write/send the content of the resource to the device.

step 6 - Transfer verify result

  • resource is moving on device side

  • the device is responsible to update his internal state (ex. from 1:DOWNLOADING to 2:DOWNLOADED)

  • Live Objects will rely on Twin READ operation to get back Firmware state (/5/0/3) and Firmware update result state (/5/0/5).

  • Live Objects expects state to be 2:DOWNLOADED and result state to be 0:INITIAL.

  • Live Objects reads state retries in the limit of max retries : cf. DM Resource limitations

  • on success, the transfer is considered as a success and the update moves to the next step,

  • on read issue or unexpected states after max retries, the update moves to ERROR state.

step 7 - Execute firmware update

  • Live Objects will rely on Twin EXECUTE operation Firmware update execute (/5/0/2).

  • resource is already on device side

  • the device can perform internal operations, updates, reboot, etc.

  • to acknowledge the binary reception and the update operation, the device is responsible to update his internal Firmware update result state.

step 7 - Await device update result state

  • update is in progress, then done on device side

  • the device is responsible to update his internal Firmware update result state (/5/0/5) to 1:UPDATED_SUCCESSFULLY

  • Live Objects will rely on Twin READ operation to get back Firmware update result state (/5/0/5).

  • Live Objects expects state to be 1:UPDATED_SUCCESSFULLY.

  • Live Objects reads update result retries in the limit of max retries : cf. DM Resource limitations

  • on success, the overall update is considered as a success and the update is DONE.

  • on read issue or unexpected states after max retries, the update moves to ERROR state.

lwm2m-updater resource update states

Device resource update states

Interactive

8.5. Campaign management

Campaign management is a Live Objects feature that allows a fleet manager to schedule execution of device management operations on a large number of devices.

The following operations are supported in a campaign definition:

8.5.1. Campaign creation

When creating a campaign, the user must provide the following information:

name

A short name to identify the campaign

description

(optional) Detailed description of the campaign

options

(optional) Set of campaign options.

planning

The scheduling configuration including the start date and the end date for the campaign

targets

Devices targeted: either idList or filterQuery (exclusively). cf. Campaign targets

operations

A sequence of operations that will be executed on each device of the campaign.

Campaigns are created from the REST API by providing a campaign definition with properties described previously.

Campaigns management are available for all types of devices (MQTT, LoRa®, SMS, LwM2M and External connector), for all connectivity, however you must take into consideration the capabilities and the conformity of the configurations, commands and resource that you push in your campaigns. Make sure that the devices support the requests that you send through connectors and through the networks. For normal use, only one connectivity is targeted by the filters or by the list of device id’s.
8.5.1.1. Campaign options

Campaign options section could be empty or omitted.

Example of campaign options:

"options": {
    "dynamicallyAddEligibleDevice": true
  }

Options are:

  • dynamicallyAddEligibleDevice (default: false).

    • Set this option to true to dynamically enroll devices to the campaign. During the campaign planning, new or updated devices could be dynamically enrolled if they match the filterQuery.

    • This option requires a filterQuery target definition.

    • A campaign with dynamicallyAddEligibleDevice option will always be in running state until end date,

whereas others (non-dynamics) campaigns could end as soon as all devices operations ended or end date reached.

8.5.1.2. Campaign operations

A campaign includes one or more operations:

For each device, operations are executed one after the other, each operation waits for the success of the previous operation.

All operations definitions (except TWIN operations) could embed an optional maxRetry attribute:

  • default is 0, and max is 5.

  • In case of operation failure, operation will be retried in the limit of maxRetry.

If an operation fails after maxRetry attempts (or is canceled) for a device, the remaining operations are not executed for this device and the sequence ends in failure (or in canceled status).

8.5.1.3. Config operation

Example of config operation definition:

  {
     "action":"configure",
     "definition":{
        "assetParameters":{
           "param1":{
              "type":"INT32",
              "valueInt32":1234
           }
        },
        "maxRetry": 1
     }
  }
action
  • configure action will send to the device one or many "parameters" to update.

definition
  • assetParameters has the same format as the corresponding unitary device management operation: Device configuration.

  • maxRetry (optional) defines how many retries should be executed in case of failure of the current operation.

The following table shows how the config operation statuses are converted into sequence statuses

Config operation status

Resulting status in the sequence

PENDING

if it is the first operation: PENDING, if not: IN_PROGRESS

SENT

IN_PROGRESS

CANCELED

CANCELED

OK

if it is the last operation: SUCCESS, if not: PENDING and the sequence moves onto the next operation

FAILED

FAILURE

8.5.1.4. Command operation

Example of command version 1 operation definition:

  {
    "action":"command",
    "version":1,
    "definition":{
      "request": {
        "connector": "mqtt",
        "value": {
          "req": "rebootV1",
          "arg": {
             "delay": 1000
          }
        }
      },
      "policy": {
        "expirationInSeconds": 120,
        "ackMode": "APPLICATIVE"
      },
      "maxRetry": 0
    }
  }
action
  • command action will register (and send) a command to the device.

definition
  • this section uses the same format as the corresponding unitary device management operation: Commands.

  • maxRetry (optional) defines how many retries should be executed in case of failure of the current operation.

The following table shows how the command operation statuses are converted into sequence statuses

Command operation status

Resulting status in the sequence

PENDING

if it is the first operation: PENDING, if not: IN_PROGRESS

PROCESSING

IN_PROGRESS

PROCESSED

if it is the last operation: SUCCESS, if not: PENDING and the sequence moves onto the next operation

CANCELED

CANCELED

ERROR

FAILURE

EXPIRED

FAILURE

UNKNOWN

FAILURE

8.5.1.5. Resource operation

Example of resource operation definition:

{
  "action": "resource",
  "definition": {
    "resourceId": "X11_firmware",
    "targetVersion": "2.1",
    "maxRetry": 4,
    "metadata" : {
        "secured" : true
    }
  }
}
action
  • resource action will send a resource update request to the device.

definition
  • resourceId identifies the resource to update

  • targetVersion is the new version of the resource to download and install. Aliases can also be used but the resolution of the version will be made for each operations when sent to the Device Manager. In other words, modifications on an alias that is used in a running campaign can affect the target version of the campaign.

  • maxRetry (optional) defines how many retries should be executed in case of failure of the current operation

  • metadata (optional) is the metadata associated with this resource update request The following table shows how the resource operation statuses are converted into sequence statuses

Resource operation status

Resulting status in the sequence

PENDING

if it is the first operation: PENDING, if not: IN_PROGRESS

PREPARING_CONNECTOR

if it is the first operation: PENDING, if not: IN_PROGRESS

PREPARING_ASSET

IN_PROGRESS

WAITING_TRANSFER_INFO

IN_PROGRESS

TRANSFER_PENDING

IN_PROGRESS

TRANSFER_IN_PROGRESS

IN_PROGRESS

TRANSFER_SUCCESS

IN_PROGRESS

DONE

if it is the last operation: SUCCESS, if not: PENDING and the sequence moves onto the next operation

ERROR

FAILURE

CANCELED

CANCELED

8.5.1.6. LwM2M Twin operations

Campaign supports all Twin operations.

8.5.1.6.1. LwM2M Twin READ operation

Example of twin read operation definition:

  {
    "action": "twin-operation",
    "definition": {
      "type": "READ",
      "paths": [
        "/5"
      ],
      "policy": {"attempts" : 2}
    }
  }
action
  • twin-operation action will send a TWIN operation request to the device.

definition
  • type READ : order the device to report some attributes.

  • paths Target paths of related device objects or attributes.

  • policy.attempts (optional) defines the maximal number of attempts until the operation is successfully completed

8.5.1.6.2. LwM2M Twin EXECUTE operation

Example of twin execute operation definition:

  {
    "action": "twin-operation",
    "definition": {
      "type": "EXECUTE",
      "paths": [
        "/1/0/8"
      ],
      "policy": {"attempts" : 1}
    }
  }
action
  • twin-operation action will send a TWIN operation request to the device.

definition
  • type EXECUTE : execute some attributes.

  • paths Target paths of related device objects or attributes.

  • policy.attempts (optional) defines the maximal number of attempts until the operation is successfully completed

8.5.1.6.3. LwM2M Twin WRITE operation

Example of twin write operation definition:

  {
    "action": "twin-operation",
    "definition": {
      "type": "WRITE",
      "writeMode": "REPLACE",
      "paths": [
        "/1/0"
      ],
      "values": [
        {
          "path": "/1/0/7",
          "value": "sampleD"
        },
        {
          "path": "/1/0/11/2",
          "value": "sampleE"
        },
        {
          "path": "/1/0/11/0",
          "value": "sampleF"
        }
      ],
      "policy": {"attempts" : 3}
    }
  }
action
  • twin-operation action will send a TWIN operation request to the device.

definition
  • type WRITE : update or replace some object attributes values.

  • paths Target paths of related device objects or attributes.

  • options Options of Twin Operation, cf. Operation options section.

  • values Values to set.

  • policy.attempts (optional) defines the maximal number of attempts until the operation is successfully completed

8.5.1.6.4. LwM2M Twin WRITE METADATA operation

Example of twin write metadata operation definition:

  {
    "action": "twin-operation",
    "definition": {
      "type": "WRITE-METADATA",
      "values": [
        {
          "path": "/1/0/7",
          "metadata": [
            {
              "name": "pmin",
              "value": "20"
            },
            {
              "name": "gt",
              "value": "50"
            },
            {
              "name": "lt"
            }
          ]
        }
      ],
      "policy": {"attempts" : 5}
    }
  }
action
  • twin-operation action will send a TWIN operation request to the device.

definition
  • type WRITE-METADATA : update metadata (set, update, reset).

  • values Values to set.

  • policy.attempts (optional) defines the maximal number of attempts until the operation is successfully completed

8.5.1.6.5. LwM2M Twin operation statuses

The following table shows how the twin operation statuses are converted into sequence statuses

Twin operation status

Resulting status in the sequence

PENDING

if it is the first operation: PENDING, if not: IN_PROGRESS

SENT

IN_PROGRESS

RETRYING

IN_PROGRESS

CANCELED

CANCELED

EXPIRED

FAILURE

FAILED

FAILURE

OK

if it is the last operation: SUCCESS, if not: PENDING and the sequence moves onto the next operation

8.5.1.7. LwM2M Twin observations
8.5.1.7.1. LwM2M Twin add observation

Example of twin add observation definition:

  {
    "action": "twin-add-observation",
    "definition": {
      "paths": [
        "/1",
        "/3/0",
        "/3442/0/110",
        "/3442/0/1110/0"
      ],
      "name": "myObservation"
    }
  }
action
  • twin-add-observation action will send a TWIN add observation request to the device.

definition
  • paths Paths of attribute, attribute instance, object instance or all the object instances of an object to observe.

  • name customized name for the observation

The following table shows how the Twin add observation statuses are converted into sequence statuses

Twin observation status

Resulting status in the sequence

PENDING

if it is the first operation: PENDING, if not: IN_PROGRESS

FAILED

FAILURE

OBSERVING

if it is the last operation: SUCCESS, if not: PENDING and the sequence moves onto the next operation

8.5.1.7.2. LwM2M Twin clear observations

Example of twin clear observations definition:

  {
    "action": "twin-clear-observations"
  }
action
  • twin-clear-observations action will send a TWIN clear observation request to the device.

8.5.1.8. Campaign target (idList)

Campaign devices targets: either idList or filterQuery (exclusively).

idList is a flat list of devices identifiers.

Devices are identified using a URN identifier.

The format of this identifier must be urn:lo:nsid:{ns}:{id} with

  • ns the target device identifier namespace

  • id the target device identifier

idList is not compatible with dynamicallyAddEligibleDevice option.

Below is an example of campaign targets definition using idList:

   "targets":{
      "idList":[
         "urn:lo:nsid:namespace:device1",
         "urn:lo:nsid:namespace:device2"
      ]
   }
8.5.1.9. Campaign target (filterQuery RSQL)

filterQuery: Device filter expression to target devices using RSQL notation. Supported device properties are tags, properties, groupId,groupPath, connector . Supported RSQL operators are ==, !=, =in=, =out=, =lt=, =le=, =gt=, =ge=, and, or.

Below is an example of campaign targets definition using filterQuery:

  "targets": {"filterQuery": "groupPath==/"}
Table 4. RSQL Semantic Table
desc syntax

Logical AND

; or and

Logical OR

, or or

Equal to

==

Not equal to

!=

Less than

=lt= or <

Less than or equal to

=le= or

Greater than operator

=gt= or >

Greater than or equal to

=ge= or >=

In

=in=

Not in

=out=

Below are example of filterQuery values.

  • Filter using tags

tags=in=(FUT,TEST1)

For example, devices with at least tags "FUT" and "TEST1" whatever the order or additional tags

  • Filter on properties

properties.mykey=in=(enum1, enum3)
properties.mykey==toto
  • Filter on groups

groupId=in=(1224,1234)
groupId==1234
groupPath=in=(/FR, /EN)
  • Filter on connector

connector==lwm2m
  • Filter with and and or conditions :

groupPath==/France;tags==demo;connector==lwm2m or (connector==x-connector)

For example, devices having /France as path and demo in tags, and (lwm2m or x-connector) as connector

8.5.1.10. Campaign creation examples

Below are examples of campaign definition:

Set parameter "param1" to value 1234 on two devices
POST /api/v0/deviceMgt/campaigns
{
   "name":"campaign1",
   "description":"A campaign that configures parameters",
   "planning":{
      "startDate":"2017-07-01T00:00:00Z",
      "endDate":"2017-07-23T23:59:59Z"
   },
   "targets":{
      "idList":[
         "urn:lo:nsid:namespace:device1",
         "urn:lo:nsid:namespace:device2"
      ]
   },
   "operations":[
      {
         "action":"configure",
         "definition":{
            "assetParameters":{
               "param1":{
                  "type":"INT32",
                  "valueInt32":1234
               }
            }
         }
      }
   ]
}
Send a reset command with a delay parameter for devices with foo tag
POST /api/v0/deviceMgt/campaigns
{
   "name":"campaign2",
   "description":"A campaign that sends a command",
   "planning":{
      "startDate":"2017-07-01T00:00:00Z",
      "endDate":"2017-07-23T23:59:59Z"
   },
   "options": {
    "dynamicallyAddEligibleDevice": true
   },
   "targets": {"filterQuery": "tags=in=(foo)"},
   "operations":[
      {
         "action":"command",
         "definition":{
            "event":"reset",
            "data":{
               "delay":"5000"
            }
         }
      }
   ]
}
Update the resource firmware.bin to version 1.1 (with 2 retries max)
POST /api/v0/deviceMgt/campaigns
{
   "name":"campaign3",
   "description":"A campaign that updates a resource",
   "planning":{
      "startDate":"2017-07-01T00:00:00Z",
      "endDate":"2017-07-23T23:59:59Z"
   },
   "targets":{
      "idList":[
         "urn:lo:nsid:namespace:device1",
         "urn:lo:nsid:namespace:device2"
      ]
   },
   "operations":[
      {
         "action":"resource",
         "definition":{
            "resourceId":"firmware.bin",
            "targetVersion":"1.1",
            "maxRetry": 2,
            "metadata" : {
                 "secured" : true
            }
         }
      }
   ]
}

8.5.2. Campaign reporting

Once a campaign is created, a fleet manager can monitor the state of a campaign.

A campaign can have one of the statuses described below:

SCHEDULED

The campaign has not yet started

RUNNING

The campaign is in progress

COMPLETE

The campaign is finished and all devices ended their sequence in success

INCOMPLETE

The campaign is finished but some devices could not be configured

SERVER_ERROR

An internal error occurred in the platform and the campaign could not be completed

CANCELING

The campaign is waiting for running sequences to end, sequences that have not started yet will not start

CANCELED

The campaign was canceled and some devices might not have been configured

The possible statuses for a device are presented below:

notStarted

No operation executed on the device

pending

The operation is recorded and waiting to be process by the device (soft cancel is still possible)

inProgress

The operation is being processed by the device (soft cancel is no more possible)

success

All operations were successfully executed on the device

failure

One operation of the sequence failed, so the remaining operations (if any) were not executed

canceled

The sequence was canceled before the end of all operations

8.5.2.1. Campaign cancelation

A campaign can be canceled with the following REST API endpoint:

PUT /api/v0/deviceMgt/campaigns/{campaignId}/cancel

If the campaign is already running, canceling it will set its state to CANCELING and the campaign will cancel pending sequences and wait for in progress sequences to end. Then the campaign state will switch to CANCELED.

To abort in progress sequences, the force flag can be used.

PUT /api/v0/deviceMgt/campaigns/{campaignId}/cancel
force = true
8.5.2.2. Campaign deletion

A campaign can be deleted with the following REST API endpoint:

DELETE /api/v0/deviceMgt/campaigns/{campaignId}

If the campaign is in RUNNING or CANCELING state, it cannot be deleted. In this case the force flag can be used to execute a forced cancelation and automatically delete the campaign once it is in CANCELED state.

DELETE /api/v0/deviceMgt/campaigns/{campaignId}
force = true

8.5.3. Global report

The global report indicates the campaign definition, the current status of a campaign and statistics about the number of devices with a given status.

Get global status of a speficied campaign
GET /api/v0/deviceMgt/campaigns/{campaignId}
{
   "name":"campaign1",
   "description":"A campaign that configures parameters",
   "planning":{
      "startDate":"2017-07-01T00:00:00Z",
      "endDate":"2017-07-23T23:59:59Z"
   },
   "targets":{
      "idList":[
         "urn:lo:nsid:namespace:device1",
         "urn:lo:nsid:namespace:device2"
      ]
   },
   "operations":[
      {
         "action":"configure",
         "definition":{
            "assetParameters":{
               "param1":{
                  "type":"INT32",
                  "valueInt32":1234
               }
            }
         }
      }
   ],
   "numberOfTargets":2,
   "totalTargetsPerStatus":{
      "notStarted":0,
      "pending":0,
      "inProgress":1,
      "failed":0,
      "success":1,
      "canceled":0
   },
   "campaignStatus":"RUNNING",
   "created":"2017-06-01T00:00:00Z",
   "updated":"2017-07-01T00:00:00Z"
}

8.5.4. Detailed report

The detailed report gives the status of each device in a campaign. The status property gives the status for the whole sequence of operations. The detailed report also indicates the status of each operation (operation reports are ordered just like in the campaign definition).

operationStatus

Exact status reported by the device manager (the list of possible values depends on the type of operation). A special value notStarted is used when the operation is not yet started.

operationId

Identifier returned by the device manager when the campaign manager created the operation

started

Date when the operation was started

updated

Last time the operation report was updated

ended

Date when the operation was finished

currentRetry
  • (Option) Retry attempt count of the latest operation executed.

  • For example, an operationStatus equals to OK (or DONE) and currentRetry equals to 1 means that operation first failed, but the first retry attempt was a success.

Get global status of a speficied campaign
GET /api/v0/deviceMgt/campaigns/{campaignId}/targets
{
   "page":0,
   "size":10,
   "totalCount":2,
   "data":[
      {
         "device":"urn:lo:nsid:namespace:id1",
         "status":"inProgress",
         "created":"2017-07-01T16:12:21.000Z",
         "updated":"2017-07-01T16:12:21.000Z",
         "operations":[
            {
               "action":"configure",
               "operationStatus":"OK",
               "started":"2017-07-01T16:20:21.000Z",
               "updated":"2017-07-01T16:25:21.000Z",
               "ended":"2017-07-01T16:25:21.000Z"
            },
            {
               "action":"command",
               "operationStatus":"SENT",
               "operationId":"12345",
               "started":"2017-07-01T16:30:21.000Z",
               "updated":"2017-07-01T16:31:21.000Z"
            },
            {
               "action":"resource",
               "operationStatus":"notStarted"
            }
         ]
      },
      {
         "device":"urn:lo:nsid:namespace:id2",
         "status":"success",
         "created":"2017-07-01T16:12:21.000Z",
         "updated":"2017-07-01T16:12:21.000Z",
         "operations":[
            {
               "action":"configure",
               "operationStatus":"OK"
               "started":"2017-07-01T16:20:21.000Z",
               "updated":"2017-07-01T16:25:21.000Z",
               "ended":"2017-07-01T16:25:21.000Z"
            },
            {
               "action":"command",
               "operationStatus":"PROCESSED",
               "operationId":"6789",
               "started":"2017-07-01T16:30:21.000Z",
               "updated":"2017-07-01T16:31:21.000Z"
            },
            {
                "action": "resource",
                "operationStatus": "DONE",
                "operationId": "X11_firmware",
                "started": "2017-07-01T16:30:21.000Z",
                "updated": "2017-07-01T16:38:21.000Z",
                "ended": "2017-07-01T16:38:21.000Z",
                "currentRetry": 1
            }
         ]
      }
   ]
}

9. Devices Inventory Explorer

9.1. Introduction

The inventory explorer present two API :

  • stats: provides a way to count devices or device components within the whole fleet. Results can be filtered and grouped by different criteria, which allows to build various aggregated views on devices data. For instance, a stats query can get the total number of devices with a specific connectivity and within a specific device group, while providing a separate count under each of their possible interface status.


stats-widget-example
Figure 6. Dashboard view of LoRa devices within the "Paris" group, grouped by connectivity status


  • search: provides a way to detail devices or device components within the whole fleet. Results can be filtered by different criteria.

In order to make these views possible, the inventory service maintains an indexed version of the whole fleet, each document representing an enriched version of a Live Objects device. The device’s static properties and most of the events occurring during its lifecycle are saved as part of an extended device state. As a consequence, a latency of a few seconds has to be expected before the current state of the fleet is available in the inventory index, this latency can be longer especially when dealing with very large fleets. However, as with most Live Objects APIs, eventual consistency is guaranteed, meaning that if all activity ceased on devices, the inventory index will eventually end up in sync with the fleet state.

9.2. Common filters

Both inventory explorer APIs use the same kind of filtering by location with geoBounds or globally with queryString.

9.2.1. Filter queries

The format of a query matches the following pattern:

{
    "filters": {
      "geoBounds": {...},
      "queryString": "..."
    }
}

9.2.2. Global filters

Filtering on location

{
    "filters": {
        "geoBounds": {
            "topLeft": {
                "lat": 50.56789,
                "lon": 1.10101
            },
            "bottomRight": {
                "lat": 12.34567,
                "lon": 20.20202
            }
        }
    }
}

Select all devices within the coordinates boundaries.

Filtering using RSQL notation

Filtering expression using RSQL notation and should not exceed 512 characters.

This syntax permits mixing several patterns according to allowed fields (see following table).

Supported fields Description

name

{
    "queryString": "name=='my Device'"
}

device name

id

{
    "queryString": "id==myId"
}

device identifier

group.path

{
    "queryString": "group.path==/foo/bar"
}

group path

group.id

{
    "queryString": "group.id==myGroupId"
}

group identifier

tags

{
    "queryString": "tags=in=(spain, v2)"
}

tags

properties.k

{
    "queryString": "properties.k==myKey"
}

properties key

properties.v

{
    "queryString": "properties.v==myValue"
}

properties value

properties

{
    "queryString": "properties=q='k==myKey and v==myValue'"
}

properties (associated with =q= operator)

property

{
    "queryString": "property.myKey==myValue"
}

properties (associated with key value)

interfaces

{
    "queryString": "interfaces=q='connector==lo*'"
}

interfaces (associated with =q= operator)

interfaces.connector

{
    "queryString": "interfaces.connector==mqtt"
}

interface connector type (Ex: sms, lora, mqtt)

interfaces.nodeId

{
    "queryString": "interfaces.nodeId==myNodeId"
}

interface node identifier

interfaces.enabled

{
    "queryString": "interfaces.enabled==false"
}

interface activation state (true or false)

interfaces.status

{
    "queryString": "interfaces.status!=OFFLINE"
}

interface status (REGISTERED, INITIALIZING, INITIALIZED, REACTIVATED, ONLINE, ACTIVATED, OFFLINE, DEACTIVATED, CONNECTIVITY_ERROR, UNKNOWN)

interfaces.definition.profile

{
    "queryString": "interfaces.definition.profile==Generic_v2"
}

interface profile (for Lora)

activities

{
    "queryString": "activities=q='state!=SILENT or ruleId==ac*'"
}

activities (associated with =q= operator)

activities.ruleId

{
    "queryString": "activities.ruleId==myRuleId"
}

activities rule identifier

activities.state

{
    "queryString": "activities.state==ACTIVE"
}

activities state (UNKNOWN, SILENT, ACTIVE)

aggregatedActivityState

{
    "queryString": "aggregatedActivityState==ACTIVE"
}

activity state (UNKNOWN, SILENT, ACTIVE) aggregated all activities state of the device

network.lora.lostMessagesRangeLabel

{
    "queryString": "network.lora.lostMessagesRangeLabel==10-20%"
}

Buckets (0-10%, 10-20%, 20-30%, 30-100%) corresponding to the percentage of lost messages by the device with Lora connectivity (computed with lostMessagesRatio )

This syntax permits mixing several filters according to allowed logical and comparison operators (see the following table).

Supported operators Description

==

{
    "queryString": "name=='my Device'"
}

equality

==<value>*

{
    "queryString": "id==my*"
}

means search for all id starting with 'my' characters

equality with prefix

!=

{
    "queryString": "group.path!=/foo/bar"
}

means search for all group paths different from '/foo/bar'

different

=q=

{
    "queryString": "properties=q='k==myKey and v==myValue'"
}

means search for all properties with key equals to 'myKey' and value equals 'myValue'.

equality only for activities, interfaces, properties nested fields

=in=

{
    "queryString": "tags=in=(spain, v2)"
}

means search for all tags equals to 'spain' or 'v2'.

group of possible values (corresponding to several 'or' operators)

and

{
    "queryString": "properties.k==myKey and tags!=demo"
}

logical and

;

{
    "queryString": "properties.k==myKey;tags!=demo"
}

identical to 'and' operator (other syntax)

or

{
    "queryString": "properties.k==myKey or tags!=demo"
}

logical or

,

{
    "queryString": "properties.k==myKey,tags!=demo"
}

identical to 'or' operator (other syntax)

RSQL complex syntax using (), '', " " can be executed:

We can regroup fields using parenthesis (by default 'and' operation is always rated first).

{
    "filters": {
        "queryString": "(tags==myTag or name==awesome*) and (group.path==/foo/* or properties=q='k==Version and v==\"my complete value\"' and interfaces.connector==lora)"
    }
}

The apostrophe character can be set using the \\.

{
    "filters": {
        "queryString": "tags=='Aujourd\\'hui'"
    }
}

All fields and values are case sensitive.

When search needs prefix value, only equality operator is accepted in this case.

Combinations of filters

Combining filters is supported. A "filters" section with multiple entries will result in all filters being applied concurrently during devices selection (by performing a logical AND between conditions).

{
    "filters": {
        "queryString": "interfaces.connector==lora",
        "geoBounds": {
            "topLeft": {
                "lat": 50.56789,
                "lon": 1.10101
            },
            "bottomRight": {
                "lat": 12.34567,
                "lon": 20.20202
            }
        }
    }
    }
}

Select all LoRa devices located inside the requested boundaries.

9.2.3. Device internal representation

As a reminder, the public model of a device, as exposed by the device management APIs, is fully described Cf. device object model. The inventory service maintains a slightly different version of this model, in order to provide additional information on devices and facilitate complex queries on their structure.

{
    "id": "urn:lo:nsid:lora:0004A30B001FE084",
    "name": "my device",
    "description": "this is my device",
    "tags": [
        "spain",
        "v2"
    ],
    "properties": [
        {
            "key": "prop1",
            "value": "val1"
        },
        {
            "key": "prop2",
            "value": "val2"
        }
    ],
    "groupId": "uyVhhN",
    "groupPath": "/foo/bar",
    "interfaces": [
        {
            "connector": "lora",
            "nodeId": "0004A30B001FE084",
            "definition" : {                        // Definition content is connectivity dependent
                "devEUI" : "0004A30B001FE084",
                "activationType" : "OTAA",
                "profile" : "Microchip RN2483",
                "encoding" : "StartKit",
                "connectivityOptions" : {
                    "ackUl" : false,
                    "tdoa" : false
                }
            },
            "enabled": true,
            "status": "ACTIVATED"
        }
    ],
    "connectors": ["lora"],
    "config": [],
    "resources": {},
    "location": {
        "lat": 48.8541822991324,
        "lon": 2.3463792646484762,
        "alt": 0.5,
        "accuracy": 10.0,
        "provider": "GPS",
        "lastUpdate": "2020-08-26T09:53:25.308Z",
    },
    "activityStates": [
        {
            "rule": {
                "id": "ec8a3217-7b3f-4020-b37b-133a65ad6384",
                "tags": [
                    "spain",
                    "v2"
                ]
            },
            "timestamp": "2020-08-26T09:53:25.308Z",
            "state": "SILENT"
        }
    ],
    "aggregatedActivityState": "SILENT",
    "lastDataCollected": "2020-08-27T09:51:25.301Z",
    "defaultDataStreamId": "stream1",
    "network": {
        "lora": {
            "lostMessageRangeRatio": 0.024
       }
    }
}

Note that a few fields have been added or modified with respect to the view provided by the device management services:

  • "connectors" is a flat list of all interfaces connectors

  • "lastDataCollected" marks the reception date of the most recent data received from the device

  • "properties" have been reorganized as a list of objects, so that their "key"s and "value"s can be accessed as fields

  • "activityStates" is a more complete view of the device’s activity.All states are available when the device is targeted by several activity rules.

  • "groupPath" is an alias for "group.path".

  • "groupId" is an alias for "group.id".

  • "location" is a record of the last known location of the device that can be either the static location set by a user, or a location published by the device, or a location given by the network, with additional metadata.

  • "aggregatedActivityState" is a simplified activity state which regroups the list of activity rules (present in 'activityStates' field) in an unique state with the following logical :

Aggregated state

Description

SILENT

At least one activity rule is set to SILENT

ACTIVE

At least one activity rule is set to ACTIVE and none is set to SILENT

UNKNOWN

At least one activity rule is set to UNKNOWN and none is set neither to ACTIVE nor to SILENT

  • "network" contains network traffic information relative to device. Data are sorted according to the connectivity (only lora is available for now) (ex : network.lora.lostMessagesRatio) :

Field

Description

lostMessagesRatio

Ratio of messages lost by the device over a 14-day window (with a limit of 10,000 messages). Its value is between 0 and 1 (1 if all messages are lost). Available only if device analytics option is activated.


This version of device representation is not accessible by the API, but you can use the search API from the inventory explorer to get your device representation of inventory explorer version.

Example

POST /api/v1/deviceMgt/explorer/search
{
    "filters": {
        "queryString": "id==urn:lo:nsid:lora:0004A30B001FE084"
    }
}

Response

{
    "bookmark": [
        "urn:lo:nsid:lora:0004A30B001FE084"
    ],
    "devices": [
        {
            "id": "urn:lo:nsid:lora:0004A30B001FE084",
            "name": "my device",
            "description": "this is my device",
            "group": {
                "id": "uyVhhN",
                "path": "/foo/bar"
            },
            "tags": [
                "spain",
                "v2"
            ],
            "properties": [
                {
                "key": "prop1",
                "value": "val1"
            },
            {
                "key": "prop2",
                "value": "val2"
            }
        ],
        "interfaces": [
            {
            "connector": "lora",
            "nodeId": "0004A30B001FE084",
            "definition" : {
                "devEUI" : "0004A30B001FE084",
                "activationType" : "OTAA",
                "profile" : "Microchip RN2483",
                "encoding" : "StartKit",
                "connectivityOptions" : {
                    "ackUl" : false,
                    "tdoa" : false
                }
            },
            "enabled": true,
            "status": "ACTIVATED"
            "capabilities": {
                "configuration": {
                    "available": false
                },
                "command": {
                    "available": false
                },
                "resource": {
                    "available": false
                }
            },
            "activity": {
                "lastDlFcnt": 140,
                "lastUlFcnt": 12799,
                "lastDeactivationTs": "2019-10-23T09:06:10.898Z",
                "lastActivationTs": "2019-10-23T09:06:35.549Z",
                "lastSignalLevel": 1,
                "avgSignalLevel": 1
            },
            "lastContact": "2019-11-28T03:58:38.429Z",
            "created": "2019-09-11T15:26:19.157Z",
            "updated": "2020-08-27T09:51:25.301Z"
            }
        ],
        "activities": [
            {
                "ruleId": "ec8a3217-7b3f-4020-b37b-133a65ad6384",
                "state": "SILENT"
            }
        ],
        "location": {
            "lat": 44.888841,
            "lon": 4.8854379999999935,
            "alt": 123.0,
            "provider": "static",
            "lastUpdate": "2020-08-27T09:51:25.301Z"
        },
        "created": "2019-09-11T15:26:19.157Z",
        "updated": "2020-08-27T09:51:25.301Z",
        "network": {
            "lora": {
                "lostMessageRangeRatio": 0.018
             }
        }
    }]
}

9.3. Statistics API

9.3.1. REST Endpoint

POST /api/v1/deviceMgt/explorer/stats

9.3.2. Filter queries

In addition to queries detailed in common filters, the format of a stats query matches the following pattern:

{
    "filters": {
      ...
    },
    "groupBy": {
      ...
    }
}

The global "filters" part retains only a matching subset of devices, and the groupBy clause contains the criteria that will provide the grouping keys for the aggregated sub-counters. When grouping by interface status, a typical response would look like this:

{
    "devices": 100,                     // devices count after applying global filters
    "fieldAggregation": {
        "count": 100,                   // total number of elements in aggregation buckets, here interfaces
        "devices": 100,                 // total number of devices in aggregation buckets
        "buckets": [
            {
                "key": "ONLINE",        // possible value of group key, here "interface status"
                "count": 85,            // elements count in this bucket
                "devices": 85           // devices count in this bucket
            },
            {
                "key": "OFFLINE",
                "count": 15,
                "devices": 15
            }
        ]
    }
}

The response contains several counters at three different levels:

  • global level: a total of all selected devices after filtering

  • aggregation level: the total number of devices and elements in all buckets

  • bucket level: the total number of devices and elements within each bucket

Note that each bucket contains two counters ("count" and "devices") that may hold different values depending on the grouping criterion. "Count" can hold the number of devices, interfaces, properties or activity states. For instance when grouping by interface status, "count" holds the number of interfaces matching the bucket key, while "devices" holds the effective number of devices with matching interfaces. This is because a given device may contain several interfaces, each with its own status. A device with two ONLINE interfaces would therefore contribute to the "devices" counter by 1, and to the "count" counter by 2.

This may happen each time an aggregation is requested on a nested component of the device. When this is not the case, "devices" is always equal to "count".

9.3.3. Global filters

The main filtering use the requests described in common filters chapter. The topmost "filters" clause selects a subset of devices, prior to any further aggregation.

9.3.4. Aggregations

9.3.4.1. Aggregation types

Two types of aggregations are supported: field aggregations and geolocation aggregations. In a field aggregation, the values of the bucket keys are taken from the possible values of the selected device’s field.

Field aggregation on tags

{
    "groupBy": {
        "field": "tags"
    }
}

Result

{
    "devices": 100,
    "fieldsAggregation": {
        "count": 100,
        "devices": 100,
        "buckets": [
            {
                "key": "spain",       // A tag value appearing in 25 devices within the fleet
                "count": 25,
                "devices": 25
            },
            ...
        ]
    }
}

A geolocation aggregation creates zone buckets. The size of each zone depend on the requested precision. A location bucket key is a coordinate object that marks the centroid of the bucket, i.e. the mean position of all the devices in the zone.

Geolocation aggregation

{
    "groupBy": {
        "location": {
            "precision": 5
        }
    },
    "options": {
      "includeGeoBoundsInBuckets": true
    }
}

Result

{
    "devices": 100,
    "geoAggregation": {
        "devices": 100,
        "buckets": [
            {
                "geoKey": {                     // centroid of devices positions within this bucket
                    "lat": 48.85418222285807,
                    "lon": 2.346379179507494
                },
                "geoBounds": {                  // if includeGeoBoundsInBuckets, geobound including all devices coordinates of the bucket
                    "topLeft": {
                        "lat": 48.85418226476759,
                        "lon": 2.3463791574827945
                    },
                    "bottomRight": {
                        "lat": 48.85418221085362,
                        "lon": 2.3463792633265257
                    }
                },
                "devices": 50
            },
           ...
        ],
      ...
    }
}
9.3.4.2. Aggregation levels

The API supports up to two levels of aggregations, which allows to break down the fleet using two different criteria. For instance the devices can be grouped by geographic zones, with interface status information being attached to the average position of each group.


2-levels-widget-example
Dashboard view of interface status by geographic zones


Nested aggregations

{
    "groupBy": {
        "location": {          // Field or geolocation aggregation
            "groupBy": {
                "interfaces": {           // Field aggregation only
                    "field": "status"
                }
            }
        }
    },
    "options": {
      "includeGeoBoundsInBuckets": true
    }
}

Result

{
    "devices": 30,
    "geoAggregation": {             // Top level geolocation aggregation
        "count": 30,
        "devices": 30,
        "buckets": [
            {
                "geoKey": {
                    "lat": 48.85418222285807,
                    "lon": 2.346379179507494
                },
                "geoBounds": {
                    "topLeft": {
                        "lat": 48.85418226476759,
                        "lon": 2.3463791574827945
                    },
                    "bottomRight": {
                        "lat": 48.85418221085362,
                        "lon": 2.3463792633265257
                    }
                },
                "devices": 30,
                "fieldAggregation": {       // Inner aggregation on interfaces status
                    "count": 30,
                    "devices": 30,
                    "buckets": [
                        {
                            "key": "ACTIVATED",
                            "count": 22,
                            "devices": 22
                        },
                        {
                            "key": "DEACTIVATED",
                            "count": 4,
                            "devices": 4
                        },
                        {
                            "key": "CONNECTIVITY_ERROR",
                            "count": 4,
                            "devices": 4
                        }
                    ]
                }
            }
        ],
        ...
    }
}

Note that field aggregations may appear at both levels, while geolocation aggregations may only appear at the topmost level.

9.3.5. Field aggregations

According to the internal model , the following aggregations can be used.

9.3.5.1. Supported aggregations

Field aggregations are only possible on a subset of the device’s fields, typically when these fields can hold common values among a number of devices.


Aggregation syntax Field names
{
    "groupBy": {
        "field": "<field name>"
    }
}

description, tags, group.path, aggregatedActivityState, network.lora.lostMessagesRangeLabel

{
    "groupBy": {
        "compositeField": "<field name>"
    }
}

connectors

{
    "groupBy": {
        "interfaces": {
            "field": "<field name>"
        }
    }
}

interface fields:

connector, status, definition.profile

{
    "groupBy": {
        "activityStates": {
            "field": "<field name>"
        }
    }
}

activityState fields:

state, rule.id

{
    "groupBy": {
        "properties": {
            "field": "<field name>"
        }
    }
}

property fields:

key, value

Note than when a field is located in a nested object (such as rule.id or definition.profile), both dot notation and object notation are supported. For instance, these notations are equally valid:

{
    "groupBy": {
        "activityStates": {
            "field": "rule.id"
        }
    }
}
{
    "groupBy": {
        "activityStates": {
            "rule": {
              "field": "id"
            }
        }
    }
}


9.3.5.2. Aggregations on lists

A regular field aggregation on a list will result in the creation of one bucket per element in the list. For instance a field aggregation on tags will build two buckets when processing a device with two tags.

A device with two tags

{
    "id": "urn:lo:nsid:foo:bar",
    "tags": [
        "spain",
        "v2"
    ],
    ...
}

Field aggregation on tags

{
    "groupBy": {
        "field": "tags"
    }
}

Result

{
    "devices": 1,
    "fieldAggregation": {
        "count": 1,
        "devices": 1,
        "buckets": [
            {
                "key": "spain",
                "count": 1,
                "devices": 1
            },
            {
                "key": "v2",
                "count": 1,
                "devices": 1
            }
        ]
    }
}

However, it is sometimes desirable for the buckets to reflect the actual values of devices lists, rather than their sparsed elements. For instance it should be possible to classify devices according to the combination of their interfaces, in order to differentiate mono-interfaces devices from multi-interfaces ones.

These composite buckets can be built by setting the "compositeField" property in the field aggregation.

Composite field aggregation on interface connectivities

{
    "groupBy": {
        "compositeField": "connectors"
    }
}

Result

{
    "devices": 7,
    "fieldAggregation": {
        "count": 7,
        "devices": 7,
        "buckets": [
            {
                "key": [
                    "lora"
                ],
                "count": 5,
                "devices": 5
            },
            {
                "key": [
                    "lora",
                    "sms"
                ],
                "count": 1,
                "devices": 1
            },
            {
                "key": [],
                "count": 1,
                "devices": 1
            }
        ]
    }
}

In this case buckets keys are list of values instead of simple strings. Among the 7 devices in the fleet, 5 are pure LoRa devices, 1 is a multi-interfaces LoRa+SMS device, and one has no declared interface so far.

9.3.6. Nested components

Some components of the device structure require a specific treatment within the aggregation API. Interfaces, properties, activityStates are all lists of objects detained by each device. Elements of these lists are referred to as nested components.

Aggregations on nested components fields

As a user of the aggregation API, one might expect two types of result when requesting an aggregation on a nested component field. For each result bucket, the API can count the number of devices that hold at least one nested component matching the bucket key. Alternatively, for each result bucket, the API can count the number of nested components matching the bucket key. For instance a device with two ONLINE interfaces can be counted once or twice in the aggregation result depending on these expectations. Actually, the inventory API does both, by providing two dedicated counters in its response.

Given the following aggregation:

{
    "groupBy": {
        "interfaces": {
            "field": "status"
        }
    }
}

If the whole fleet contains currently a single device with two ONLINE interfaces, the result would be:

{
    "devices": 1,
    "fieldAggregation": {
        "count": 2,
        "devices": 1,
        "buckets": [
            {
                "key": "ONLINE",
                "count": 2,
                "devices": 1
            }
        ]
    }
}

"count" is related to the number of interfaces, while "devices" is the effective number of devices. The same pattern applies to all other nested components.

9.3.7. Filters and nested components

Filters on nested components (interfaces, properties, activityStates, see global filters section) can be applied globally through queryString. When applied globally, these filters select all devices holding at least one matching nested component. If a device is selected, all its nested components contribute to the construction of response buckets, even if they dont match the filter individually.

Device with multiple properties

{
    "id": "urn:lo:nsid:foo:bar",
    "name": "my device",
    "properties": [
        {
            "key": "prop1",
            "value": "val1"
        },
        {
            "key": "prop2",
            "value": "val2"
        }
    ],
  ...
}

Using a global filter on a matching property key selects this device and all its properties.

Global filter on property key

{
    "filters": {
        "queryString": "properties.k==prop1"
    },
    "groupBy": {
        "properties": {
            "field": "value"
        }
    }
}

Aggregation response after global filtering

{
    "devices": 1,
    "fieldAggregation": {
        "count": 2,
        "devices": 1,
        "buckets": [
            {
                "key": "val1",
                "count": 1,
                "devices": 1
            },
            {
                "key": "val2",
                "count": 1,
                "devices": 1
            }
        ]
    }
}

The device is selected because one of its properties matches the filter, but all of them appear in the aggregation response. The count values account for both device’s properties. In order to keep only the matching properties in the response, the filter must be moved at nested components level.

Nested level filter on property key

{
    "groupBy": {
        "properties": {
            "field": "value",
            "filter": {
                "key": "prop1"
            }
        }
    }
}

Aggregation response after nested filtering

{
    "devices": 1,
    "fieldAggregation": {
        "count": 1,
        "devices": 1,
        "buckets": [
            {
                "key": "texttest",
                "count": 1,
                "devices": 1
            }
        ]
    }
}

Nested level filter on property value

{
    "groupBy": {
        "properties": {
            "field": "key",
            "filter": {
                "value": "val1"
            }
        }
    }
}

Aggregation response after nested filtering

{
    "devices": 10639,
    "fieldAggregation": {
        "count": 2,
        "devices": 2,
        "buckets": [
            {
                "key": "111",
                "count": 1,
                "devices": 1
            },
            {
                "key": "test",
                "count": 1,
                "devices": 1
            }
        ]
    }
}

The aggregation response contains a single bucket, accounting for the matching property only.

This pattern applies to all nested components. In short, global filtering applies to devices, while nested filtering applies to nested components.

Select all devices with at least a LoRa interface.

Nested level filter on interfaces connectivity

{
    "groupBy": {
        "interfaces": {
            "field": "status",
            "filter": {
                "connector": "lora"
            }
        }
    }
}

Aggregation response after nested filtering

{
    "devices": 10639,
    "fieldAggregation": {
        "count": 264,
        "devices": 259,
        "buckets": [
            {
                "key": "DEACTIVATED",
                "count": 205,
                "devices": 202
            },
            {
                "key": "REGISTERED",
                "count": 34,
                "devices": 34
            },
            {
                "key": "REACTIVATED",
                "count": 22,
                "devices": 20
            },
            {
                "key": "ACTIVATED",
                "count": 2,
                "devices": 2
            },
            {
                "key": "INITIALIZED",
                "count": 1,
                "devices": 1
            }
        ]
    }
}

Select all devices with at least an interface with the requested status.

Nested level filter on interfaces status

{
    "groupBy": {
        "interfaces": {
            "field": "connector",
            "filter": {
                "status": "ONLINE"
            }
        }
    }
}

Aggregation response after nested filtering

{
    "devices": 10639,
    "fieldAggregation": {
        "count": 68,
        "devices": 68,
        "buckets": [
            {
                "key": "sms",
                "count": 57,
                "devices": 57
            },
            {
                "key": "x-connector",
                "count": 9,
                "devices": 9
            },
            {
                "key": "mqtt",
                "count": 2,
                "devices": 2
            }
        ]
    }
}

Select all devices with at least an interface which definition contains the requested profile.

Nested level filter on interfaces definitions

{
    "groupBy": {
        "interfaces": {
            "field": "status",
            "filter": {
               "definition": {
                    "profile": "myProfile"
                }
            }
        }
    }
}

Aggregation response after nested filtering

{
    "devices": 10639,
    "fieldAggregation": {
        "count": 49,
        "devices": 49,
        "buckets": [
            {
                "key": "DEACTIVATED",
                "count": 40,
                "devices": 40
            },
            {
                "key": "REACTIVATED",
                "count": 7,
                "devices": 7
            },
            {
                "key": "REGISTERED",
                "count": 2,
                "devices": 2
            }
        ]
    }
}

Select all devices with a "SILENT" or "UNKNOWN" activity state.

Nested level filter on activity states

{
    "groupBy": {
        "activityStates": {
            "field": "state",
            "filter": {
                "states": ["SILENT", "UNKNOWN"]
            }
        }
    }
}

Aggregation response after nested filtering

{
    "devices": 40,
    "fieldAggregation": {
        "count": 53,
        "devices": 40,
        "buckets": [
            {
                "key": "SILENT",
                "count": 42,
                "devices": 31
            },
           {
                "key": "UNKNOWN",
                "count": 11,
                "devices": 9
            }
        ]
    }
}

Select all devices with an activity state related to the requested activity rule.

Nested level filter on activity states using triggering rule id

{
    "groupBy": {
        "activityStates": {
            "field": "rule.id",
            "filter": {
                "rule": {
                    "id": "myRuleId"
                }
            }
        }
    }
}

Aggregation response after nested filtering

{
    "devices": 40,
    "fieldAggregation": {
        "count": 40,
        "devices": 40,
        "buckets": [
            {
                "key": "myRuleId",
                "count": 40,
                "devices": 40
            }
        ]
    }
}

9.3.8. Geolocation aggregations

A geolocation aggregation is calculated from the values of the devices location fields. The set of response buckets divide space into a number of areas. The cells of this underlying grid are indexed using geoHash codes, which length depend on the requested precision. Precision is expressed as a number in a range of 1 to 12.

Correspondance between precision and effective cells size is approximated below. Note that the cell width reduces moving away from the equator, up to 0 at the poles.

Geohash length Cell width Cell height

1

5000 km

5000 km

2

1250 km

625 km

3

156 km

156 km

4

39.1 km

19.5 km

5

4.9 km

4.9 km

6

1.2 km

0.61 km

7

153 m

153 m

8

38.2 m

19.1 m

9

4.8 m

4.8 m

10

1.2 m

0.596 m

11

14.9 cm

14.9 cm

12

3.7 cm

1.9 cm


Location aggregation

{
    "groupBy": {
      "location": {
          "precision": 3      // optional precision, defaults to 5.
      }
    },
    "options": {
      "includeGeoBoundsInBuckets": true
    }
}

Result

{
    "devices": 10,
    "geoAggregation": {
        "count": 10,
        "devices": 10,
        "buckets": [
            {
                "geoKey": {                       // weighted mean position of devices in this bucket
                    "lat": 48.85418222285807,
                    "lon": 2.346379179507494
                },
                "geoBounds": {                   // coordinates of the smallest enclosing window for all devices of the bucket
                    "topLeft": {
                        "lat": 48.85418226476759,
                        "lon": 2.3463791574827945
                    },
                    "bottomRight": {
                        "lat": 48.85418221085362,
                        "lon": 2.3463792633265257
                    }
                },
                "devices": 8
            },
            {
                "geoKey": {
                    "lat": 44.840204967185855,
                    "lon": -0.560115147382021
                },
                "geoBounds": {
                    "topLeft": {
                        "lat": 44.840204967185855,
                        "lon": -0.560115147382021
                    },
                    "bottomRight": {
                        "lat": 44.840204967185855,
                        "lon": -0.560115147382021
                    }
                },
                "devices": 2
            }
        ],
        "geoBounds": {                          // coordinates of the smallest enclosing window for all devices (for all buckets)
            "topLeft": {
                "lat": 48.85418226476759,
                "lon": -0.5601150635629892
            },
            "bottomRight": {
                "lat": 44.840204967185855,
                "lon": 2.3463792633265257
            }
        }
    }
}

The "geoKey" property is the bucket’s key, showing the weighted mean position (centroid) of all devices in the bucket. More over, for each bucket a "geoBounds" property defines a minimal enclosing box for its devices.

Additionally, the response provides a "geoBounds" property that defines a minimal enclosing box for all devices appearing in response buckets.

9.3.9. Query options

9.3.9.1. Total number of buckets

A stats response can contain up to 50 buckets, shown in descending order of the number of devices in the bucket. Thus, if there are more than 50 buckets, the response contains only the ones that have the most devices. In this case, a client can request a count of the total number of buckets, by setting the "includeTotalKeys" option.

Field aggregation on tags

{
    "groupBy": {
        "field": "tags"
    },
    "options": {
        "includeTotalKeys": true
    }
}

The result contains an additional information showing the total number of bucket keys, including the ones that did not make it to the response.

Result

{
    "devices": 1000,
    "fieldAggregation": {
        "count": 1000,
        "devices": 1000,
        "buckets": [
          ...               // contains the first 50 buckets
        ],
        "keys": 120         // Total number of bucket keys (distinct tag values)
    }
}
9.3.9.2. Missing devices

When a device has no value related to the requested aggregation key, it does not appear in any bucket of the response. In order to track the number of all missing devices, an "includeMissingDevicesCount" option is available.

Field aggregation on tags

{
    "groupBy": {
        "field": "tags"
    },
    "options": {
        "includeMissingDevicesCount": true
    }
}

Result

{
    "devices": 6,
    "fieldAggregation": {
        "count": 6,
        "devices": 6,
        "buckets": [
            {
                "key": "spain",
                "count": 5,
                "devices": 5
            }
        ],
        "missing": 1            // 1 device without any tag
    }
}

Among the 6 devices in the fleet, 5 hold the same tag, while a single one has no tag at all.

In nested components, the missing field does not count devices with no nested component (properties, interfaces or activityStates) as they are filtered out. It only counts devices that hold the requested nested component without the requested aggregation key, as shown in the example below.

Field aggregation on interface profiles

{
    "groupBy": {
        "interfaces": {
            "definition": {
                "field": "profile"
            }
        }
    },
    "options": {
        "includeMissingDevicesCount": true
    }
}

Result

{
    "devices": 10,
    "fieldAggregation": {
        "count": 8,
        "devices": 6,
        "buckets": [
            {
                "key": "Generic_classA_RX2SF12",
                "count": 4,
                "devices": 4
            }
        ],
        "missing": 2
    }
}

There are 10 devices in the fleet, and 6 of them have at least one interface, for a total of 8 interfaces. Among them, 4 interfaces have the same profile, meaning they are LoRa interfaces, and 2 devices have no profile at all, meaning they are not LoRa interfaces.

Apart from interfaces profiles, all other supported nested aggregation keys are mandatory, so the missing value is always 0.

9.3.9.3. Include GeoBounds in buckets

For a location based aggregation:

Location aggregation

{
    "groupBy": {
      "location": {
          "precision": 3
      }
    },
    "options": {
      "includeGeoBoundsInBuckets": true
    }
}

each result bucket will include weighted mean position of devices in this bucket (under geoKey).

Bucket centroid is always returned

       "geoKey": { // weighted mean position of devices in this bucket
           "lat": 48.85418222285807,
           "lon": 2.346379179507494
       },

If includeGeoBoundsInBuckets option is set to true, then location based aggregation result buckets will include coordinates of the smallest enclosing window for all devices of the bucket (under geoBounds).

Bucket GeoBounds is returned when "includeGeoBoundsInBuckets"

        "geoBounds": { // coordinates of the smallest enclosing window for all devices of the bucket
            "topLeft": {
                "lat": 48.85418226476759,
                "lon": -0.5601150635629892
            },
            "bottomRight": {
                "lat": 44.840204967185855,
                "lon": 2.3463792633265257
            }
        }

9.4.1. REST Endpoint

POST /api/v1/deviceMgt/explorer/search

9.4.2. Filter queries

The queries are entirely detailed in common filters.

The format of a search query matches the following pattern:

{
    "query": "...",
    "filters": {...},
    "sort": [...],
    "bookmark": [...],
    "size": ...
}

The global request uses the following description :

JSON Params Description

query

Optional. partial search allows to find devices by indicating partial values. It is searched among the following fields: id, name, group.path, tags, properties.key, properties.value. It is a string format, case-insensitive and if there are multiple words they are filtered with the OR operator. At least 3 characters are needed to find words of more than 3 characters. Smaller words can be found by indicating their complete value. 256 characters maximum

filters

Optional. identical criteria described in common filtering chapter

size

Optional. maximum number of devices to return

sort

Optional. array of sort elements which accepts "group.path", "name", "interfaces.status", "interfaces.enabled", "interfaces.lastContact", "lastCommunication", "created", "updated", "relevance", "network.lora.lostMessagesRatio", "id". "id" must be set at the end. Per default, when array is empty or the "id" is not set, the sort will be done by ascending "id". More over to indicate a sort on reverse way, a "-" must be set in front of element (Ex: "-id").

bookmark

Optional. array of indexes of the last research (compatible with the sort list in number and order). When it is using, the bookmark corresponding to the "id" must always be set (even if not set in the sort list or sort list is empty).

If "query" and "filters" fields are present, they are processed with AND operator. "bookmark" is used to optimize the search when consecutive requests are made one after the other, in executing the search from the last found device.

According to the internal model, a typical response would look like this:

{
    "bookmark": [
            "/grp1",
            "ONLINE",
            true,
            "2019-08-20T15:05:58.047Z",
            "urn:lo:nsid:myNs:myId"
    ],
    "devices": [
      {
         "id": "urn:lo:nsid:sensor:temp001",
         "name": "mySensor001",
         "description": <<some description>>,
         "activities": [
            {
             "ruleId": "e26309b1-3bb1-4ac6-929b-50d364188c7e",
             "state": "SILENT"
            }
         ],
         "aggregatedActivityState": "SILENT",
         "tags": ["Lyon", "Test"],
         "properties" : {
             <<key>>: <<value>>
         },
         "group": {
             "id": <<id>>,
             "path": <<myPathId>>
         },
         "interfaces": [
               {
                 "connector": <<myConnector>>,
                 "nodeId": <<interface Id>>,
                 "enabled": <<true/false>>,
                 "status": <<the status of the interface>>,
                 "lastContact": <<date>>,
                 "definition": {
                       ........to learn more, see the "Device interface representation" section
                 },
                 "activity": {},
                 "capabilities": {
                       "command": {
                          "version" : <<versionNumber>>,
                          "available": <<true/false>>
                       },
                       "configuration": {
                          "available": <<true/false>>
                       },
                       "resources": {
                          "available": <<true/false>>
                      }
                  }
               }
           ],
           "lastCommunication": <<date>>,
           "created": <<date>>,
           "updated": <<date>>,
           "location": {
               "lat": <<Latitude value>>,
               "lon": <<Longitude value>>,
               "alt": <<Altitude value>>,
               "accuracy":<<accuracy value>>,
               "provider":<<provider value>>,
               "lastUpdate": <<date>>
            },
           "network": {
               "lora": {
                   "lostMessagesRatio": <<float value>>
               }
           }
       }
    ]
}

The response contains lists of :

  • bookmarks : representing the indexes of the last research. These indexes follow the elements set in the sort in number and order. For example, if sort=["created","id"] then bookmark will return [<last index of created>, <last index of id>]

  • inventory devices with the following model description :

JSON Params Description

id

device unique identifier (Cf. device identifier)

description

Optional. detailed description of the device

name

Optional. name of the device

tags

Optional. list of additional information used to tag device messages

properties

Optional. map of key/value string pairs detailing device properties

group

group to which the device belongs. The group is defined by its id and its path

interfaces

Optional. list of device network interfaces (Cf. interface object model)

lastCommunication

Optional. last communication date of the device. Latest date between data message created and interface last contact

created

creation date of the device

updated

last update date of the device

activities

Optional. device activities with state of its activity rule

aggregatedActivityState

Optional. device aggregated activity state of 'activities' field (Cf. aggregated activity state)

location

Optional. the last location of the device returned by data after data message enrichment process.

network

Optional. the last network traffic information relative to the device

And for each interface the model is :

JSON Params Description

connector

connector identifier

nodeId

interface unique identifier

enabled

define if the interface is enabled or disabled

status

interface status

definition

interface definition. The definition depends on connector.

lastContact

Optional. last contact date of the connectivity

activity

interface activity. The activity depends on connector.

capabilities

interface capabilities.

created

registration date of the interface

updated

last update date of the interface

For more information on each connector definition, activity and status, see the appropriate section:

10. Cellular Networks (Beta)

10.1. Principle

Cellular network management APIs allows user to retrieve connectivity information from Orange connectivity management provider. Once the customer account is configured information such as last network attachment, locations, session history, etc. can be retrieved. Retrieved information can vary depending on your provider, region and offer package account.

10.2. Providers

As of today, the only provider available is Orange Malima for the following regions :

Provider Available region

Malima

France, Spain, Poland, Romania, Slovakia

10.2.1. List cellular networks providers (Beta)

10.2.1.1. Request

Endpoint:

GET /api/v1/networks/cellular/providers

HTTP Headers:

X-API-Key: <your API key>
Accept: application/json

Example:

GET /api/v1/networks/cellular/providers
10.2.1.2. Response

HTTP Code:

200 OK

Body:

[
    {
        "id": "63ea4f8aba4c826792df04b8",
        "type": "malima",
        "configuration": {
            "cen": "mycen",
            "instanceId": "OFR"
        },
        "accountName" : "ZZZ My Account Name"
    }
]
JSON Params Description

id

Provider unique identifier

type

Provider type. Allowed values: [malima]

configuration

Provider customer account configuration

accountName

Provider account name

Error case:

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

403

FORBIDDEN

Forbidden request

10.3. Subscriptions

A subscription is a network subscription identified by a subscriptionId. A subscription is linked to a SIM card and contains information such as :

  • The last network interaction

  • Attached device

  • Provider account subscription’s

  • SIM card capabilities and ids

10.3.1. Search cellular networks subscriptions (Beta)

10.3.1.1. Request

Endpoint:

POST /api/v1/networks/cellular/subscriptions/search

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Body:

JSON Params Description

type

Search type of the subscription, allowed types : "msisdn", "imei" or "deviceId"

If you use the "deviceId", Live Objects will look for potential 'imei' or 'msisdn' in your device inventory based on the following fields (in order) :

- "imei" property (Cf. properties in device inventory)

- "msisdn" property (Cf. properties in device inventory)

- "deviceId"

- "nodeId" of your device interfaces for SMS, LwM2M, MQTT or x-connector connectors

value

Search value of the subscription (max 269 characters)

Example:

POST /api/v1/networks/cellular/subscriptions/search
{
    "type" : "msisdn",
    "value" : "337000003543020"
}
10.3.1.2. Response

HTTP Code:

200 OK

Body:

[
    {
        "id": "06361404",
        "msisdn": "337000003543020",
        "imsi": "208017401123509",
        "sim": {
            "status": "ACTIVATED",
            "iccid": "89330129210007850940",
            "serialNumber": "2921000785092",
            "lastUpdate": "2021-02-03T09:45:35Z"
        },
        "device": {
            "imei": "352753093029773",
            "lastUpdate": "2021-02-03T09:45:35Z"
        },
        "provider": {
            "type": "malima",
            "configuration": {
                "cen": "mycen",
                "instanceId": "myInstanceId"
            },
            "accountName" : "ZZZ My Account Name",
            "link": "https://m2mexpress.fr.orange-business.com/mac/customer/fleet/details.do?subId=06361404&category=SIM"
        }
    }
]
JSON Params Description

id

subscription unique identifier

msisdn

Number uniquely identifying a subscription in a Global System for Mobile communications

imsi

International Mobile Subscriber Identity

sim

Sim of the subscription (Cf. Sim format)

device

Device of the subscription (Cf. Device format)

provider

Provider of the subscription (Cf. Provider format)

Error case:_

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

403

FORBIDDEN

Forbidden request

404

CELLULAR_SUBSCRIPTION_NOT_FOUND

Subscription not found

10.3.2. Get cellular networks subscription (Beta)

10.3.2.1. Request

Endpoint:

GET /api/v1/networks/cellular/subscriptions/{subscriptionId}

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Example:

GET /api/v1/networks/cellular/subscriptions/06361407
10.3.2.2. Response

HTTP Code:

200 OK

Body:

{
    "id": "06361404",
    "msisdn": "337000003543020",
    "imsi": "208017401123509",
    "sim": {
        "status": "ACTIVATED",
        "iccid": "89330129210007850940",
        "serialNumber": "2921000785092",
        "lastUpdate": "2021-02-03T09:45:35Z",
        "capabilities" : {
             "smartSim" : true
        }
    },
    "device": {
        "imei": "352753093029773",
        "lastUpdate": "2021-02-03T09:45:35Z"
    },
    "provider": {
        "type": "malima",
        "configuration": {
            "cen": "mycen",
            "instanceId": "myInstanceId"
        },
        "accountName" : "ZZZ My Account Name",
        "link": "https://m2mexpress.fr.orange-business.com/mac/customer/fleet/details.do?subId=06361404&category=SIM"
    },
    "network": {
        "status": "ONLINE",
        "radio": "4G",
        "lastUpdate": "2020-10-28T16:13:04Z",
        "mobileCountry": {
            "code": "208",
            "value": "France"
        },
        "mobileNetwork": {
            "code": "208-01",
            "value": "Orange"
        },
        "lastNetworkInteraction": "DATA"
    }
}
JSON Params Description

id

subscription unique identifier

msisdn

Number uniquely identifying a subscription in a Global System for Mobile communications

imsi

International Mobile Subscriber Identity

sim

Sim of the subscription (Cf. Sim format)

device

Device of the subscription (Cf. Device format)

provider

Provider of the subscription (Cf. Provider format)

network

Network of the subscription (Cf. Network format)


The format of the sim is the following:

JSON Params Description

status

Status of SIM : PRE_ACTIVATED, ACTIVATED, SUSPENDED, CANCELLED …​

iccid

Integrated Circuit Card Identifier

serialNumber

Serial Number of SIM

lastUpdate

Last update date of SIM

capabilities

SIM capabilities (Cf. Sim capabilities format)


The format of the sim capabilities is the following:

JSON Params Description

smartSim

true when SIM supervision localization is available


The format of the device is the following:

JSON Params Description

imei

International Mobile Equipment Identity

lastUpdate

Last update date of device


The format of the provider is the following:

JSON Params Description

type

Provider type. Allowed values: [malima]

configuration

Provider customer account configuration

accountName

Provider account name

link

link to access portal M2M


The format of the network is the following:

JSON Params Description

status

Status of the last network attachment: ONLINE or OFFLINE

radio

Radio type of network attachment: 2G, 3G, 4G, 5G or UNKNOWN

lastUpdate

Last update date of network attachment

mobileCountry

Mobile country (if any)

mobileNetwork

Mobile network (if any)

lastNetworkInteraction

Last interaction of network attachment: DATA or SMS

Error case:_

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

403

FORBIDDEN

Forbidden request

404

CELLULAR_SUBSCRIPTION_NOT_FOUND

Subscription not found

10.4. Location

Last known location of the associated device can be retrieve. This location can be provided by network probes (only available for France) or with SmartSim location service (available for some regions).

Only available for some regions and depends on your network provider option package.

10.4.1. Get cellular networks location (Beta)

10.4.1.1. Request

Endpoint:

GET /api/v1/networks/cellular/subscriptions/{subscriptionId}/location

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Example:

GET /api/v1/networks/cellular/subscriptions/06361407/location
10.4.1.2. Response

HTTP Code:

200 OK

Body:

{
    "lat": "44.8",
    "lon": "3.7",
    "accuracy": "120.0",
    "provider": "network",
    "lastUpdateTs": "2020-10-28T16:13:04Z",
    "link": "https://m2mexpress.fr.orange-business.com/mac/customer/fleet/deviceinfo/localization-details.do?subId=06361407"
}
JSON Params Description

lat

coordinate latitude

lon

coordinate longitude

accuracy

position accuracy in m

lastUpdateTs

date of the position

provider

provider of the location ("network" when supplied by network probes (only available for France) or "smart-sim" when supplied by SmartSim location service)

link

link to access the location tab on the service provider portal

Error case:_

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

403

FORBIDDEN

Forbidden request

404

CELLULAR_SUBSCRIPTION_NOT_FOUND

Subscription not found

10.5. Traffic history

Provide an aggregated view of the session history of the subscription. Max history depth is 30 days.

10.5.1. Get cellular subscription traffic history (Beta)

10.5.1.1. Request

Endpoint:

GET /api/v1/networks/cellular/subscriptions/{subscriptionId}/traffic/history

HTTP Headers:

X-API-Key: <your API key>
Content-Type: application/json
Accept: application/json

Parameters:

HTTP Params Description

limit

(optional) limit the response to the last n elements in the "data" object. 1000> n> 0

interval

(optional) requested aggregation format, "1h"(one hour), "1d"(one day) or "1w"(one week).

timeZone

(optional) time zone for daily or weekly aggregation, with TZ database name ("UTC", "Europe/Paris") or UTC Offset ("-02:00", "%2B04:00").

Example:

GET /api/v1/networks/cellular/subscriptions/06361407/location?limit=1&interval=1h&timeZone=Europe/Paris
10.5.1.2. Response

HTTP Code:

200 OK

Body:

[
    {
      "dataIn": 1096,
      "dataOut": 1096,
      "smsIn": 5,
      "smsOut": 5,
      "timestamp": "2024-02-01T09:00:00+01:00"
    }
]
JSON Params Description

dataIn

Sim data traffic with device as target (in Bytes)

dataOut

Sim data traffic device originated (in Bytes)

smsIn

Sim SMS count with device as target

smsOut

Sim SMS count device originated

timestamp

date time of the beginning of the bucket interval (in UTC)

Error case:_

HTTP Code Error code message

400

GENERIC_INVALID_PARAMETER_ERROR

The submitted parameter is invalid.

403

FORBIDDEN

Forbidden request

404

CELLULAR_SUBSCRIPTION_NOT_FOUND

Subscription not found

11. Data transformation

11.1. Data transformation components and concepts

You can send data to Live Objects using two sources, a device can send data using a supported protocol (LoRa®, SMS, MQTT…​) or a business application by using HTTPS or MQTTS. Each source is processed by one or many components. Data transformation is then relies upon:

  • the data enrichment process which makes the link between Live Objects Data Message and Device Management. Data enrichment is a merge of third-party data model from device source with a Live Objects common data model.

  • the decoding service which process Live Objects message for handling encoded data collected from various networks.

  • the custom pipeline service which process Live Objects Data Messages to perform various enrichment steps

Data journey

Interactive

11.2. Data Message Enrichment process

11.2.1. Overview

The Live Objects Data Message pipeline goes through an enrichment process that applies the following logic. This pipeline concerns messages coming from LoRa® and MQTT protocols.

11.2.1.1. Enrichment logic

The enrichment logic uses Device Management repository to enrich a DataMessage with Live Objects device information .

  • when using LoRa® protocol a device is retrieved by using devEUI.

  • when using MQTT protocol a device is retrieved by using clientId.

Table 5. Data Message fields modified by Enricher Logic

streamId

if not provided, will be set to Live Objects urn

tags

will be enriched by merging this fields with the device tags

extra

will be enriched by merging with the device properties

metadata.group

will be set with the device group

metadata.encoding

will be set with the device’s interface definition.encoding value. It will override the value from the original data message.

The enrichment process is executed before the decoding process

11.3. Decoding service

11.3.1. Overview

The data messages sent to the Live Objects platform can be encoded in a customer specific format. For instance, the payload may be a string containing an hexadecimal value or a csv value.

The data decoding feature enables you to provision your own decoding grammar. On receiving the encoded message, the Live Objects platform will use the grammar to decode the payload into plain text JSON fields and record the JSON in the Store service. The stored message will then be searchable with the Advanced Search service.

A "template" option allows to perform mathematical operations on the decoded fields or to define an output format.

A "model" option allows to override original data 'model' field.

The decoding feature is not activated by default.

11.3.2. Binary decoding

11.3.2.1. Decoder provisioning

The custom decoder describes the grammar to be used to decode the message payload. The Live Objects API to manage the decoders are described in the swagger documentation: https://liveobjects.orange-business.com/swagger-ui/index.html.

The binary decoding module uses the Java Binary Block Parser (JBBP) library in version 1.2.1.
You must use the JBBP DSL language to describe the binary payload format for your decoder.

Additional types

the float and utf8 are additional types that can be used in the grammar (see decoding examples).

Field names

Each field can have case insensitive name which must not contain '.' (reserved for links to structure field values) and '#'(reserved for internal library use). A field name must not be started with either number or chars '$' and ''. Keep in mind that field names are case insensitive!_

Naming fields to avoid :

myString =/= mystring

Prohibited field names examples :

Not authorized : my.string, my#string, $mystring,_my.string,

11.3.2.1.1. Basic decoder

Example: create a binary decoder with the REST API:

POST /api/v0/decoders/binary
X-API-Key: <your API key>
Accept: application/json
{
"encoding":"twointegers",  (1)
"enabled":true,  (2)
"format":"int pressure;int temperature;", (3)
"template":"{\"pressure\":{{pressure}},
  \"temperature\" : \"{{#math}}{{temperature}}/10{{/math}} celsius\"}", (4)
"model":"model_twointegers"  (5)
}
1 identifies the decoder. This name will be associated to the devices during the provisioning and will be present in the data message.
2 activation/deactivation of the decoder.
3 describes the payload frame (cf. JBBP DSL language). The name of the fields will be found in the resulting decoded payload JSON.
4 optional parameter describing a post-decoding template format. In this example, the output temperature will be divided by 10 and stored in a string format including its unit. More information on templates.
5 optional parameter that will override the 'model' field in decoded data. If empty, the original value of 'model' field of the encoded data will be used. More information on model field
11.3.2.1.2. When to change the model in the decoder ?
  • The "model" field is set in order to enable elasticsearch (ES) indexing and queries on the decoded value.

  • If the "model" field is not set when provisioning the decoder, the data message will still be stored but it will not be searchable with ES queries.

  • The "model" must be changed when the type of a field already indexed in ES is modified. Example :

    • Suppose you have created a binary decoder with the following payload description "format":"utf8[4] field1; int field2;"

    • You have defined a model named "my_model_v0" associated with this decoder.

    • You start using this decoder with your devices. Data messages are stored and indexed in Live Objects.

    • Then, you can perform searches in your data messages using the model. See search examples.

    • If, after checking your decoded data, you find out that field1 is a float, not a UTF8 string, you may modify your decoder format. "format":"float field1; int field2;"

    • In this case, if you want your new messages to be stored and indexed properly in elasticsearch, you must change the model name in your decoder (for instance "my_model_v1"). Otherwise, "field1" will still be mapped as String and the message will be rejected by elasticsearch.

11.3.2.1.3. Endianness

The decoding service uses the big-endian order (the high bytes come first). If your device uses little-endian architecture, you can use the < character to prefix a type in your format description.

Example: create a binary decoder for a device sending data in little-endian format:

POST /api/v0/decoders/binary
X-API-Key: <your API key>
Accept: application/json
{
"encoding":"my_little_endian_encoding",
"enabled":true,
"format":"<float temperature;" (1)
}
1 : float means 32-bit float sent in little-endian.
11.3.2.1.4. How to test the binary decoder format?

The Live Objects API provides a "test" endpoint which takes a payload format and a payload value as input and provides the decoded value in the response body, if the decoding is successful. Optionally, you can provide a post-decoding template which will describe the output format.

In the following example, the decoded value for the pressure will remain unchanged, while the decoded value for temperature will be divided by 10.
The test endpoint is described in swagger.

Request:

POST /api/v0/decoders/binary/test
X-API-Key: <your API key>
Accept: application/json
{
"binaryPayloadStructure":"int  pressure; int temperature;",
"binaryPayloadHexString":"000003F5000000DD",
"template":"{\"pressure\":{{pressure}}, \"temperature\" : \"{{temperature}}/10\"}"
}

Response:

{
   "parsingOk": true,
   "decodingResult":    {
      "temperature": 22.1,
      "pressure": 1013
   },
   "descriptionValid": true
}
11.3.2.1.5. How to customize the fields once the payload has been decoded?

The fields resulting of a decoded payload might need to be processed using a template description, in order to change their output format. More information on templates.

11.3.2.2. Message decoding

The data message is decoded using the decoder previously provisioned and the decoded fields are added to the value. The encoded raw payload is kept in the decoded message. Once the message has been decoded and stored, "Advanced Search" requests can be performed using the newly decoded fields.

Table 6. Examples :
Frame format Payload example Decoded payload (JSON)
int temperature;

000000DD

{
  "value": {
    "payload" : "000000DD",
    "temperature": 221
  }
}
ubyte temperature;

DD

{
  "value": {
    "payload" : "DD",
    "temperature": 221
  }
}
utf8 [17] mystring;

2855332e3632542b323144323235503029

{
  "value": {
    "payload" : "2855332e3632542b323144323235503029",
    "mystring": "(U3.62T+21D225P0)"
  }
}
byte is_led_on;
float pressure;
float temperature;
float altitude;
ubyte battery_lvl;
byte[6] raw_gps;
ushort altitude_gps;

00
447CE000
41CEF5C3
45CAB8CD
38
00000000000
0FFFF

{
  "value": {
    "payload" : "00447CE00041CEF5C345CAB8CD38000000000000FFFF",
    "is_led_on": 0,
    "pressure": 1011.5,
    "temperature": 25.87,
    "altitude": 6487.1,
    "battery_lvl": 56,
    "raw_gps_list": [0,0,0,0,0,0],
    "altitude_gps": 65535
  }
}
float pi;
measure[2] {
  int length;
  utf8 [length] name;
  float value;
}

4048F5C3
0000000B
C2A955544638537472696E67
41480000
00000012
C2A9616E6F7468657255544638537472696E67
447D4000

{
  "value": {
    "payload" : "4048F5C3
      0000000BC2A955544638537472696E6741480000
      00000012C2A9616E6F7468657255544638537472696E67447D4000",
    "pi": 3.14,
    "measure_list":[
      {
        "length":11,
        "name":"©UTF8String",
        "value":12.5
      },
      {
        "length":18,
        "name":"©anotherUTF8String",
        "value":1013.0
      }
    ]
  }
}

The binary decoding feature can handle long type (i.e 64-bit integer). Nevertheless, when displayed in a web portal, the long number might be rounded unaccurately due to javascript limitations (max safe integer = 2^53-1 in javascript).

Table 7. JSON fields

value.payload

a string containing the encoded payload in hexadecimal (raw value)

metadata.encoding

contains the decoder name

model

remains unchanged after decoding if model field of decoder is empty; else it will be set with the value of model field in the decoder

additional LoRa® fields (lora port, snr…​) in the value

remain unchanged after decoding.

11.3.3. Csv decoding

11.3.3.1. Decoder provisioning

The custom decoder describes the columns format and options to be used to decode the message csv payload. The Live Objects API to manage the decoders are described in the swagger documentation : https://liveobjects.orange-business.com/swagger-ui/index.html.

When provisioning a csv decoder, you must specify an ordered list of column names and their associated type. Three column types are available : STRING, NUMERIC or BOOLEAN.
Several options (column separator char, quote char, escape char…​) may be set to customize the csv decoding.

A template option enables you to provide a post-decoding output format including mathematical evaluation. More information on templates.

Column types
  • STRING column may contain UTF-8 characters

  • NUMERIC column may contain integer (32 bits), long (64 bits), float or double values. The values may be signed.

  • BOOLEAN column must contain true or false.

Table 8. Available options
name default definition example

quoteChar

double-quote "\""

character used for quoting values that contain column separator characters or linefeed.

"pierre, dupont",25,true will be decoded as 3 fields.

columnSeparator

comma ","

character used to separate values.

lineFeedSeparator

"\n"

character used to separate data rows. If the message payload contains several rows, only the first one will be decoded.

the decoding result for pierre,35,true\nmarie,25,false will be 3 fields containing pierre, 35 and true.

useEscapeChar

false

set to true if you want to use an escape char.

escapeChar

backslash "\\"

character used to escape values.

skipWhiteSpace

false

if set to true, will trim the decoded values (white spaces before and after will be removed).

Example 1: create a simple csv decoder with the REST API:

POST /api/v0/decoders/csv
X-API-Key: <your API key>
Accept: application/json
{
    "encoding":"my csv encoding", (1)
    "enabled":true, (2)
    "columns": [ (3)
        {"name":"column1","jsonType":"STRING"},
        {"name":"column2","jsonType":"NUMERIC"},
        {"name":"column3","jsonType":"BOOLEAN"}
    ],
    "model":"model_csv_decoded"  (4)
}
1 identifies the decoder. This name will be associated to the devices during the provisioning and will be present in the data message.
2 activation/deactivation of the decoder.
3 an ordered list of column descriptions.
4 optional parameter that will override the 'model' field of decoded data. If empty, the original value of 'model' field of the encoded data will be used. More information on model field.

Example 2: create a csv decoder with options, using the REST API:

POST /api/v0/decoders/csv
X-API-Key: <your API key>
Accept: application/json
{
    "encoding":"my csv encoding with options",
    "enabled":true,
    "columns": [
        {"name":"unit","jsonType":"STRING"},
        {"name":"temperature","jsonType":"NUMERIC"},
        {"name":"normal","jsonType":"BOOLEAN"}
    ],
    "options" : {
        "columnSeparator": "|",
        "quoteChar": "\"",
        "lineFeedSeparator": "/r/n"
    }
}
In the POST request, you can provide only the options you wish to modify. The other options will keep the default values.
11.3.3.1.1. How to customize the fields once the payload has been decoded?

The fields resulting of a decoded payload might need to be processed using a template description, in order to change their output format. More information on templates.

11.3.3.1.2. How to test the csv decoder ?

The Live Objects API provides a "test" endpoint which takes a csv format description and a payload value as input and provides the decoded value in the response body, if the decoding is successful. The test endpoint is described in swagger.

Request:

POST /api/v0/decoders/csv/test
X-API-Key: <your API key>
Accept: application/json
{
    "columns": [
        {"name":"unit","jsonType":"STRING"},
        {"name":"temperature","jsonType":"NUMERIC"},
        {"name":"threasholdReached","jsonType":"BOOLEAN"}
    ] ,
    "options":{
        "columnSeparator": ","
    },
    "csvPayload":"celsius,250,true",
    "template":"{\"temperature\" : \"{{temperature}}/10\",
      \"unit\":\"{{unit}}\", \"thresholdReached\":\"{{thresholdReached}}\"} "
}

Response:

{
   "parsingOk": true,
   "decodingResult":    {
      "unit": "celsius",
      "thresholdReached": "true",
      "temperature": 25
   },
   "descriptionValid": true
}
  • The csv decoding feature can handle long type (i.e 64-bit integer) but numbers above 2^31-1 are displayed in exponential notation (2147483648 will be displayed as 2.147483648E9). The decoding of very large numbers might lead to inaccurate rounding when the precision is above 15 digits.

Example : 9007199254740997 is displayed as 9.007199254740996E15.

  • For large numbers above 16 digits, you should use the STRING type when decoding your payload to avoid any rounding issue. Please note also that using string type for a number has impact on indexing/searching in Elasticsearch (data search feature). Since the data will be indexed and stored as string, it will not be possible to do aggregations or calculations.

11.3.3.2. Referencing a decoder in a LoRa® device

When provisioning a LoRa® device, you may reference the decoder to be used for the device so that Live Objects will automatically decode all the payloads received from this device, using the referenced decoder.

11.3.3.3. Message decoding

The data message is decoded using the decoder previously provisioned and the decoded fields are added to the value. The csv encoded raw payload is kept in the decoded message. Once the message has been decoded and stored, "Advanced Search" requests can be performed using the newly decoded fields.

Example in https:

Request
POST /api/v0/data/streams/{streamId}
X-API-Key: <your API key>
Accept: application/json
{
  "value": {"payload":"celsius,25,true"},
  "model": "temperature_v0",
  "metadata" : {"encoding" : "my csv encoding"}
 }

The data message will be stored as:

{
      "id": "585aa47de4b019917e342edd",
      "streamId": "stream0",
      "timestamp": "2016-12-21T15:49:17.693Z",
      "model": "temperature_v0",
      "value":       {
         "payload": "celsius,25,true",
         "normal": true,
         "unit": "celsius",
         "temperature": 25
      },
      "metadata": {"encoding": "my csv encoding"},
      "created": "2016-12-21T15:49:17.750Z"
}
Table 9. JSON fields

value.payload

a string containing the csv encoded payload (raw value)

metadata.encoding

contains the decoder name

model

remains unchanged after decoding if model field of decoder is empty; else it will be set with the value of model field in the decoder

11.3.4. Templating

The Live Objects provides, for the decoder creation and the decoder test APIs, an optional parameter named "template". This parameter is a string field describing the target output fields in a mustache-like format.

Table 10. Available functions :

{{#math}}{{/math}}

performs mathematical operations on a field

{{#toUpperCase}}{{/toUpperCase}}

converts a string to upper case

{{#toLowerCase}}{{/toLowerCase}}

converts a string to lower case

The following examples shows, for the same raw binary payload, the output if you are not using any template, or if you define a custom template.

Request (WITHOUT the template parameter)
POST /api/v0/decoders/binary/test
X-API-Key: <your API key>
Accept: application/json
{
"binaryPayloadStructure": "byte:1 led; ushort pressure; ushort temperature; ushort altitude; ubyte battery; byte[6] raw_gps; ushort altitude_gps;",
"binaryPayloadHexString":"0027830a1bfd6738000000000000ffff"
}
Response
{
   "parsingOk": true,
   "decodingResult":{
      "led": 0,
      "pressure": 10115,
      "temperature": 2587,
      "altitude": 64871,
      "battery": 56,
      "raw_gps": [0, 0, 0, 0, 0, 0],
      "altitude_gps": 65535
   },
   "descriptionValid": true
}
Request (WITH the template parameter)
POST /api/v0/decoders/binary/test
X-API-Key: <your API key>
Accept: application/json
{
  "binaryPayloadStructure":"byte:1 led; ushort pressure; ushort temperature;ushort altitude; ubyte battery; byte[6] raw_gps; ushort altitude_gps;",
  "binaryPayloadHexString":"0027830a1bfd6738000000000000ffff",
  "template":"{\"pressure\": \"{{pressure}} / 10\",\"temperature\": \"{{temperature}} / 100\",\"altitude\": \"{{altitude}} / 10\",\"view\": {\"Pressure\": \"{{#math}}{{pressure}}/10{{/math}} hPa\",\"Temperature\": \"{{#math}}{{temperature}}/100{{/math}} C\",\"Altitude\": \"{{#math}}{{altitude}}/100{{/math}} m\",\"GPSAltitude\": \"{{altitude_gps}} m\",\"Battery\": \"{{battery}} %\"}}"
}
Response
{
   "parsingOk": true,
   "decodingResult":    {
      "altitude": 6487.1,
      "view":       {
         "Pressure": "1011.5 hPa",
         "Temperature": "25.87 C",
         "Altitude": "648.71 m",
         "GPSAltitude": "65535 m",
         "Battery": "56 %"
      },
      "temperature": 25.87,
      "pressure": 1011.5,
      "led": 0,
      "battery": 56,
      "raw_gps": [0, 0, 0, 0, 0, 0],
      "altitude_gps": 65535
   },
   "descriptionValid": true
}

Please do not use dot-separated fields in the template.

Example:

`"template":"{\"field.with.dot\": {{temperature}}/10}"` will be rejected.

The {{#math}}{{/math}} template is needed only if you wish to evaluate a mathematical expression within a string.

Example for a template containing:

\"Temperature\": \"{{temperature}}/100 celsius\" (1)
\"Temperature\": \"{{#math}}{{temperature}}/100{{/math}} celsius\" (2)
\"Temperature\": \"{{#math}}{{temperature}}/100{{/math}}\" (3)
\"Temperature\": \"{{temperature}}/100\" (4)
1 the output will be like Temperature": "2587/100 celsius" (the division is not evaluated).
2 the output will be like Temperature": "25.87 celsius" (a string output. the division is evaluated).
3 the output will be like Temperature": 25.87 (a numeric). In this case, the {{#math}} function is not needed.
4 the output will be like Temperature": 25.87 (a numeric).

You need to specify in the template, all the fields you wish to get in the output, even if they are not modified by the template.

Example:

 `"template":"{\"pressure\":{{pressure}}, \"temperature\" : {{temperature}}/10}"`
If you omit the *pressure* field in the template, it will simply not appear in the output.
location

If the decoded value contains a location field with latitude and longitude, it will override the location field provided in Live Objects at the same JSON level as the value field.

Example:

A LoRa® message contains an encoded payload. The default location in the message is the location provided by the LoRa® network.

  "streamId": "urn:lora:xxxxxxxxxxxx1009!uplink",
  "created": "2019-04-05T14:37:12.047Z",
  "location": {
      "provider": "lora",
      "alt": 0,
      "accuracy": 7500,
      "lon": -3.469017,
      "lat": 48.762119
   },
   "model": "model_yyyy",
   "value": {
      "payload": "01005ca767ee00400810",
   },
   "timestamp": "2019-04-05T14:37:08.489Z",

If the device is a tracker, after decoding the payload, the decoded message may have the following format :

  "streamId": "urn:lora:xxxxxxxxxxxx1009!uplink",
  "created": "2019-04-05T14:37:12.047Z",
  "location": {(2)
        "provider": "device", (3)
        "lon": -3.469020,
        "lat": 48.762120
   },
   "model": "model_yyyy",
   "value": {
      "payload": "01005ca767ee00400810",
      "location": {  (1)
            "lon": -3.469020,
            "lat": 48.762120
        },
      "temperature": {
         "unit": "°C",
         "currentTemperature": {
            "values": [
               20.64
            ]
         }
      }
   },
   "timestamp": "2019-04-05T14:37:08.489Z",
1 if the decoded location has the expected "location" format,
2 the decoded location replaces the location provided by the LoRa® network,
3 and the provider is now "device" instead of "lora"

11.3.5. Javascript decoding

If the payloads are more complex (several payloads, specific calculations/transformations…​), you can develop a scriptable (javascript) decoder. The javascript version must be compliant with ECMA Script 5. We also provide a development framework that can be used with Eclipse or IntelliJ IDE that can ease the development of the decoder. More info in the links below :

11.3.5.1. Split decoding

If your device sends several measures in a single data message, you can use a « split decoder ». It is a special type of javascript decoder that enables you to « split » the original data message into several data messages (typically one per measure). Each resulting data message will then follow the usual data processing path described here.

You will find an example in the scriptable decoders documentation.

  • metadata.transformation.decoder.split.rank is added in the messages produced by a split decoder (it is not present in the other messages). It can be used to filter out the « split » messages from a search query. This is for instance necessary if you want to count the messages sent by your devices (in that case you only want to count one of the « split » messages).

  • The metadata.network section of the message is only preserved in one of the data messages produced by a split decoder (in the one with a « split rank » equal to 0).

11.4. Custom Pipelines service for External enrichment

11.4.1. Overview

The Data Messages sent to Live Objects can be enriched by the Custom Pipelines service.

You can create your own pipeline to perform one or several enrichment steps on specific Data Messages.

Interactive

As described below, a pipeline is composed by a filter section and at least one step section.

Each pipeline targets Data Messages based on its filter configuration, and has a priorityLevel : at most one pipeline can handle a Data Message.

When a Data Message is handled by a pipeline, pipeline id and the status of the execution will be added in the metadata.transformation.pipeline field.

In case of pipeline failure, the original Data Message is stored and an AuditLog message will be sent with failure details.

11.4.2. Pipeline description

pipeline description
{
    "name": "base64 decoding",
    "description": "pipeline to decode base64 encoded message with external transformation",
    "priorityLevel": 10,
    "enabled": true,
    "filter": {
        "connectors": [ "mqtt" ],
        "encodings": [ "base64" ],
        "groupPaths": [ { "path": "/europe", "includeSubPath": true } ],
        "tags": [["PROD"]]
    },
    "steps" : [ {
        "type": "externalTransformation",
        "url": "http://lo-data-transformation.appspot.com:80/base64_decode"
    } ]
}
Field Type Description

name

String

(Mandatory). Name of the pipeline. Max 1000 characters

description

String

(Optional). Description of the pipeline. Max 2000 characters

priorityLevel

Integer

(Mandatory). Used to prioritize pipelines when a Data Message matches with the filter of several pipelines. The pipeline with the lowest priorityLevel value will be selected. In case of equal priorityLevel value, the older pipeline (based on its creation date) will be picked.

enabled

Boolean

(Mandatory). Indicates if the pipeline can apply or not.

filter

Object

(Optional). Define which Data Message can be processed by this pipeline. A null filter means all Data Message can be processed by the pipeline. Criteria in a filter are combined with a AND boolean logic. OR operator is applied between each elements inside filter’s list.

filter.connectors

List<String>

(Optional). If set, then only Data Message sent through one of these connectors (based on its metadata.connector field) will be selected and enter into the pipeline. Possible connectors are: "http", "lora", "mqtt", "sms", "x-connector"

filter.encodings

List<String>

(Optional). If set, then only Data Message with one of these encodings (based on its metadata.encoding field) will be selected and enter into the pipeline.

filter.groupPaths

List<GroupPath>

(Optional). If set, then only Data Message originated from one of these groupPaths (based on its metadata.group field) will be selected and enter into the pipeline.

filter.tags

List<List<String>>

(Optional). If set, then only Data Message with these tags description (based on its tags field) will be selected. There is a match if at least one group of tags is a match. A group of tags is a match if the tags of the message contains all elements of this group. For instance [["HIGH", "ALERT"],["PROD"]] will match any message containing 'PROD' tag; and also any message containing both 'HIGH' and 'ALERT' tags.

steps

List<Steps>

(Mandatory). Define the processing steps of the pipeline (see steps description below).

A dataMessage can only go through one pipeline. (see priorityLevel field for more information). This information is useful when there is overlap between pipeline filters.
A pipeline can have multiple steps. In this case, the steps are executed sequentially

11.4.3. Pipeline Steps description

For now, one type of pipeline steps is available: externalTransformation.

11.4.3.1. "externalTransformation" step

Interactive

This step will POST a http request with a DataMessage as body toward an external webhook url. Additional headers can be set for each request.

The Data Message format is described in the messages data model section, without the id field as it is not yet stored.

The response to this request must be the transformed (decoded, enriched…​) Data Message using the same format.

Live Objects will then manage this transformed Data Message response:

Behavior Fields

The value of these fields is kept from the original dataMessage. i.e. not overriden

  • streamId

  • metadata

  • extra

  • value.payload

  • created

The value of these fields is replaced by the value contained in the response dataMessage. i.e. overriden Even if 'null'

  • model

  • location

  • tags

  • value (except value.payload)

If not null in the response dataMessage, the value overrides the original field

  • timestamp

Ignored by the pipeline

Any other fields

The important fields that the response can override even if null are: model, location, tags and value.
The http status of the response must be of the 2xx success family in order to be taken into account
In order to ensure that all Data Messages are quickly delivered into other services (Data Store, Alarming, Routing) there is no retry mechanism. Also, only a limited number of Data Messages can wait in a pipeline queue. You need to ensure that your webhook server is available and can hold the Data Messages traffic.
externalTransformation step
{
    "type": "externalTransformation",
    "name": "additional identifier enrichment",
    "url": "http://lo-data-transformation.appspot.com:80/enrich",
    "headers" : [ "x-transform-header" : [ "account-1234" ] ]
}
Field Type Description

type

String

(Mandatory). Must be set to 'externalTransformation'.

name

String

(Optional). Name of the step. It will be pushed in the 'x-orange-lo-pipeline-step-name' http header. Max 1000 characters

url

String

(Mandatory). URL to POST the Data Message. Authorized ports are: 80, 443, 8080, 8443 and 9243.

headers

Map<String, List<String>>

(Optional). If present, these headers will be added in the http POST request.

If the external transformation fails (for ex. because the JSON is badly formatted, server responds http 503…​), Live Objects will store the original Data Message, and an AuditLog message will be logged with failure details.

11.4.3.1.1. Example

Implementing a base64 decoder for all dataMessages with 'base64' metadata.decoding:

First, you must deploy your server that will accept POST request and return decoded Data Message.

Then create the following pipeline:

pipeline description
{
    "name": "base64 decoding",
    "priorityLevel": 10,
    "enabled": true,
    "filter": {
        "encodings": [ "base64" ]
    },
    "steps" : [ {
        "type": "externalTransformation",
        "name": "base64 external decoder",
        "url": "http://lo-data-transformation.appspot.com:80/base64_decode"
    } ]
}

The following Data Message is sent by a device:

Data Message sent by a device
{
   "streamId":"device-001-alarm",
   "timestamp":"2019-12-10T13:57:03Z",
   "model":"v1",
   "value":{
      "payload":"bG93IGJhdHRlcnkgYWxhcm0gOiA5JSByZW1haW5pbmc="
   },
   "metadata":{
      "encoding":"base64"
   }
}

This Data Message will arrive into the custom pipeline service and match with the filter of the provisioned pipeline. So, this message will be POST to the url:

POST http request triggered by the DataMessage
POST http://lo-data-transformation.appspot.com:80/base64_decode
'Content-Type': 'application/json'
'x-orange-lo-pipeline-execution-id': '5e9f80ca-6a72-4252-9251-f014b61cf682'
'x-orange-lo-pipeline-step-name': 'base64 external decoder'
{
   "type":"dataMessage",
   "version":1,
   "streamId":"device-001-alarm",
   "timestamp":"2019-12-10T13:57:03Z",
   "model":"v1",
   "value":{
      "payload":"bG93IGJhdHRlcnkgYWxhcm0gOiA5JSByZW1haW5pbmc="
   },
   "metadata":{
      "encoding":"base64"
   }
}

Here is the body response from the remote server (that has performed the payload decoding and has added a tag):

POST http response 200 OK
{
   "model":"v1_base64_decoded",
   "value":{
      "alarm":"low battery alarm : 9% remaining",
      "battery_level":9
   },
   "tags":[
      "ALARM",
      "BASE64_DECODED"
   ]
}

Then the stored Data Message will be:

Stored Data Message
{
   "streamId":"device-001-alarm",
   "timestamp":"2019-12-10T13:57:03Z",
   "model":"v1_base64_decoded",
   "value":{
      "payload":"bG93IGJhdHRlcnkgYWxhcm0gOiA5JSByZW1haW5pbmc=",
      "alarm":"low battery alarm : 9% remaining",
      "battery_level":9
   },
   "tags":[
      "ALARM",
      "BASE64_DECODED"
   ],
   "metadata":{
      "encoding":"base64",
      "transformation":{
         "pipeline":{
            "id":"a07767f6-809e-4943-8b79-5efb96bd1535",
            "success":true
         }
      }
   }
}

12. Devices Analytics (Beta)

12.1. Introduction

Device Analytics service aims to analyse the behaviour of your devices and to provide an aggregated view of your fleet activity.


Interactive
High level view of Device Analytics service


This service is still in BETA; it relies on Machine Learning and some of the algorithms might not be relevant for specific device behaviours.

Only metadata from network info and/or data message will be analysed. Business data are not processed.

Network information may be incomplete.

Once a week, you will receive a report by email with several sections providing insights regarding your fleet.

There is a Premium option that will show additional sections (e.g. fleet’s devices classification : '2 messages per day').

12.2. Analytics Report Email

The weekly email contains several sections, based on fleet connectivity and its traffic analysis.

For instance, for LoRa connectivity, the join request / join accept network messages will be analysed; as well as the correlation between the loss ratio and the Signal-to-Noise Ratio.

For MQTT devices The ONLINE / OFFLINE connectivity will be aggregated and reported.

If you subscribed to a premium option, the communication patterns of your fleet is analysed by a machine learning algorithm.

Attached to the report, an Excel file contains the details, device per device, of the analysis.


device_analytics_report
Sample sections of a report for a LoRa fleet

12.2.1. LoRa: Messages lost

LoRa messages have an incrementing frame counter. When a frame counter is missing, it may indicate that a message has been lost.

This section displays the % of message lost for the fleet’s devices (over a 14-day period) and the link between message loss and network connectivity issue:

  • weak signal strength with a low signal over noise ratio

  • minimal network coverage (limited number of gateways receiving the message).

12.2.2. LoRa: Join anomalies

Some devices have anomalies on the Join Request / Join Accept procedure during the observation period.

  • Join Requests with no Join Accept cycles : the Join Accept / Join Requests ratio is <50%

  • multiple Join Requests and Join Accepts cycles : the number of Join Request/Accept cycles is >1 on average over the period

This issues may come from a low network coverage or bad device configuration and may kill the device battery. If any, they should be resolved.

12.2.3. LwM2M: DTLS packet lost

Available for LwM2M over DTLS. DTLS records (the basic units of data exchange in DTLS) have an incrementing sequence number. When a sequence number is missing, it indicates that a DTLS record has been lost. As there may be retransmissions (at CoAP level), this does not necessarily mean that some application data has been lost.

This section shows the % of DTLS records lost for the fleet devices. It is calculated over a 14-day period and is defined as follows: (number of lost records over the analysis period) / (number of received and lost records over the analysis period)

12.2.4. Traffic analysis

This section shows the fleet’s devices daily message rate. It focuses on devices that sent at least one message during the observation period. For the LwM2M protocol, only the Send and Notify messages are taken into account.

12.2.5. Regular communication pattern analysis

Device communication frequency and regularity are analyzed based on the messages sent by the devices. This analysis is based on a machine learning algorithm. For instance '1 msg / 1h' means that the device sends 1 new message each hour.

'Minor patterns' are the communication patterns that are used by less than 5% of the fleet.

When no regular pattern has been detected for a device, it is defined as 'undetected' and some additional details are provided per device in the attachment file :

  • FEW_INTERARRIVALS : not enough messages have been sent by the device to be able to detect a pattern

  • LORA_TOO_MANY_LOSS : based on frame counters, too many messages have been lost to be able to detect a pattern

  • SPREADED_INTERARRIVALS : the communication pattern seems to be erratic and can not be defined as regular

The evolution of these communication patterns in the fleet is also analyzed. It is interesting to follow over time these trends to monitor the stability of the fleet :

Criticality Transition Previous pattern Current pattern

Critical Critical

Devices gone silent

Any

Silent

Warn Warn

Devices no longer regular

Regular

Undetected

Info Info

Devices changed pattern

Other regular
Silent

Regular
Undetected

Improvement Improvement

Devices no more silent or undetected

Silent
Undetected

Any
Regular

For the LwM2M protocol, command and registration messages are not taken into account.

The email report contains a table with samples from each category.

12.2.6. Outliers analysis

This analysis is focused on the fleet outliers. Outlier devices could be the consequence of low network coverage, hardware/software device issues…​ We consider especially two families:

  • low communicating devices: the devices that sent less than 50% of messages than the lowest rate major communication pattern of the fleet

  • high communicating devices: the devices that sent more than 50% of messages than the highest rate major communication pattern of the fleet

12.2.7. Devices interface status

This section focuses on the fleet’s devices status.

  • LORA, SMS interface: status is the last known status of the interface when the analysis occurred.

  • MQTT interface: status is ONLINE if at least one MQTT connection was successfully established during the last day of the analyzed period, otherwise status is OFFLINE.

  • LwM2M interface: the fleet status analysis is not performed

12.2.8. Analysis details per device (Excel file)

In the 'Alarms & reports' section of the portal you can download an Excel file with information for each fleet’s devices. Parts of this file will also be attached to the email report.

Field Description type Example

device

Device ID

String

urn:lo:nsid:lora:80BBD540F351AC07

groupPath

Device group

String

/site_A

msgs_per_day

Mean Data Messages cout per day over the analysis period

Double

23.4

current_pattern

Only for premium reports. Detected regular communication pattern

String

1 msg every 1h

pattern_transition_from

Only for premium reports. Previous regular communication pattern if it has changed over the last weeks.

String

undetected : FEW_INTERARRIVALS

pattern_transition_trend

Only for premium reports. In case of a recent pattern change, define the trend of the transition.

String

Improving behavior

last_status

Device interface status of the last day of the analysis period

String

ACTIVATED

detected_lost_msgs_per_day

Only for LORA devices. computed with frame counter. Mean value of lost messages per day over the analysis period

Double

0.3

counter_loss_ratio

Only for LORA devices. computed with frame counter. Mean value of lost messages ratio over the analysis period.

Double

0.05

join_request_per_day

Only for LORA devices. Mean join request messages per day over the analysis period.

Double

0.33

join_accept_per_day

Only for LORA devices. Mean join accept messages per day over the analysis period

Double

0.33

missing_join_accept

Only for LORA devices. Missing join accept has been detected for this device

Boolean

false

too_many_join_cycles

Only for LORA devices. Too many join request/join accept cycles have been detected for this device

Boolean

false

snr_mean

Only for LORA devices. Mean Signal-to-Noise Ratio value over the analysis period.

Double (decibel)

1.1

gtw_mean

Only for LORA devices. Mean number of gateways the device is linked to over the analysis period.

Double

3.81

rssi_mean

Only for LORA devices. Mean Received Signal Strength Indicator over the analysis period.

Double

-109.8

sf_mean

Only for LORA devices. Mean Spreading Factor over the analysis period.

Double

10.6

detected_lost_dtls_packet_per_day

Only for LwM2M devices. Average number of lost DTLS packets per day over the analysis period. Lost DTLS packets are detected based on the DTLS sequence number. Note that a lost DTLS packet does not necessarily mean a loss of application data (LwM2M) as there may be retransmissions.

Double

0.3

counter_dtls_loss_ratio

Only for LwM2M devices. Ratio of lost DTLS packets to the received packets over the analysis period. Lost DTLS packets are detected based on the DTLS sequence number. Note that a lost DTLS packet does not necessarily mean a loss of application data (LwM2M) as there may be retransmissions.

Double

0.05

days_used_for_analysis

Number of days of data used to perform analysis.

Integer

14

12.3. Analytics Rule

You can create Analytics Rules that will define :

  • targeted fleet of devices : all targeted devices of a fleet are supposed to have a similar behaviour in order to better categorize and bring out outliers.

  • report email parameters : you will be able to set the language and the recipients of the report

12.3.1. API

You can refer to the swagger documentation to list all available APIs.


Create a new Analytics Rule
POST /api/v1/device-analytics/rules
{
        "name": "...",
        "fleet": {
                "connectors": [...],
                "groupPaths": [...]
        },
        "report": {
                "recipients": {...},
                "language": "..."
        },
        "enabled": ...
}
JSON Params Description

name

Mandatory. user-defined name for the rule, must be unique and not empty.

fleet

Mandatory. defines the targeted devices of a this AnalyticsRule.

fleet.connectors

Mandatory. analyse only devices with these connectivity. 1 and only 1 connector must be defined.

fleet.groupPath

Optional. analyse only devices that belong to this group.

report

Mandatory. defines the analytics report email parameters.

report.recipients

Mandatory. at least one recipient must be set.

report.language

Mandatory. language of the report : either 'en' or 'fr'.

enabled

Optional. activate or deactivate the rule (default is false).

13. Data analysis

13.1. Data store & search components and concepts

After your data sended to Live Objects using data streams, Each source is processed by one or many components. Data storage & search is then relies upon:

  • the store service aims to store data messages from devices (devices, gateways, IoT app collecting data, etc.) as time-series data streams

  • the indexing service aims to index data messages collected from devices (devices, gateways, IoT app collecting data, etc.) by using model field after injected by the previous components.

  • the search service based on the popular open-source Elasticsearch product.

Data journey

Interactive

13.2. Store service

The REST interface allows to add data to a stream and to retrieve data from a stream. A stream could be for example associated to a unique of device (streamID could be therefore a device Identifier) or one type of data coming from a device (streamID could be therefore in this format deviceIdentifier-typeOfData)

13.2.1. Manage your data streams

Every source publishing or injecting the data into Live Objects (Device, gateway or business application), must set the stream which would be where you want to store your data.

In order to be able to use and process the data collected correctly, it is necessary to be able to read it and then store it. The management of the read and write processes in Live Objects is done through data stream channels.

A data stream is associated with each publisher and it can be a device with a single interface or several, you must take into consideration where the published messages will be written.

By default, each provisioned device, Live Objects associates a streamId with the defaulDataStreamId whose value is set automatically by Live Objects. The messages will be written under this stream.

So, to correctly manage the streams of your device, you should either use the stream provided by default or modify it if necessary.

When you want the device to use a particular streamId, the publisher must indicate in each uplink the desired stream. This allows data to be writed and stored as needed.

Data stream options

Interactive

Default data stream payload :

{

    "value": {"temp":23.8},
    "model": "data_model_v1"
}

Your data are stored under the defaultDataStreamId value stream. In this case the value is a device URN (or the value that you set in defaultDataStreamId field).

Custom data stream payload :

{
    "streamId" : "my_stream_1"
    "value": {"temp":24.1},
    "model": "data_model_v1"
}

To change your Custom data stream :

{
    "streamId" : "my_stream_2"
    "value": {"temp":20.1},
    "model": "data_model_v1"
}

13.2.2. Add a data message to a stream

Request:

POST /api/v0/data/streams/{streamId}
X-API-Key: <your API key>
Accept: application/json

body param

description

data

JSON object conforming to data message structure

Warning: the streamId is provided as the last segment of the url.

Example:

POST /api/v0/data/streams/myDeviceTemperature
{
  "value": {"temp":24.1},
  "model": "data_model_v0"
 }

For this example, the "value.temp" field of model "data_model_v0" will be defined as a double type. If a String type is used in the future for "value.temp", a new model must be defined. In case that "value.temp" is set a String type with model "data_model_v0", the message will be dropped by the search service.

13.2.3. Add an encoded data message to a stream

In order to use the decoding capability of Live Objects, a DataMessage must contains additional 'value.payload' and 'metadata.encoding' fields :

Example:

POST /api/v0/data/streams/myDeviceTemperatureAndPressure
{
    "value": {
        "payload": "000003F5000000DD"
    },
    "metadata": {
        "encoding": "twointegers"
    }
}
Field Description

value.payload

(Mandatory). Payload to decode. In case of binary content, HexBinary String representation of the payload to decode.

metadata.encoding

(Mandatory). Encoded format name, that should match the 'encoding' name of the decoder that can process this message.

All other fields of DataMessage (timestamp, model, location, tags…​) can also be set in the encoded DataMessage.

You can also set the encoding property in the device’s interface definition in order to force metadata.encoding value for all data messages sent from this device through its interface.

13.2.4. Add a bulk of data messages

Request:

POST "/api/v0/data/bulk
X-API-Key: <your API key>
Accept: application/json

body param

description

data

JSON array conforming to an array of data message structure

A bulk will be processed if all arrays elements are valid, otherwise the bulk will be rejected. Maximum size of the bulk is 1000.

Warning : the streamId is mandatory for each element of the Bulk. This is a difference with the REST API for adding data to a stream.

Example:

POST /api/v0/data/bulk
[
  {
    "streamId" : "temperature_stream_1"
    "value": {"temp":24.1},
    "model": "data_model_v1"
  },
  {
    "streamId" : "temperature_stream_1"
    "value": {"temp":24.1},
    "model": "data_model_v1"
  },
  {
    "streamId" : "pressure_stream_1"
    "value": {"pressure":1024.0},
    "model": "data_model_v1"
  }
]

13.2.5. Retrieve data from a stream

Request:

GET /api/v0/data/streams/{streamId}
X-API-Key: <your API key>
Accept: application/json

Query params

Description

limit

Optional. max number of data to return, value is limited to 100

timeRange

Optional. filter data where timestamp is in timeRange "from,to"

bookmarkId

Optional. id of document. This id will be used as an offset to access to the data.

Documents are provided in reverse chronological order (newest to oldest).

Example:

GET /api/v0/data/streams/myDeviceTemperature
{
  "id": "57307f6c0cf294ec63848873",
  "streamId": "myDeviceTemperature",
  "timestamp": "2016-05-09T12:15:41.620Z",
  "model": "temperature_v0",
  "value": {
    "temp": 24.1
  },
  "created": "2016-05-09T12:15:40.286Z"
}

13.3. Indexing service

After the data collected it may be associated to a model. The model is a fundamental concept for the search service, it specifies the schema of the JSON "value" object. The model is dynamically updated based on the data injected.

The model concept is necessary to avoid mapping conflicts in the underlying elasticsearch system.

13.3.1. Model field in data message

The model allows to give pattern for the value object, A model can be seen as a "mapping space" in which data types must not conflict. Some precautions must be taken when using model field :

  • If the model is not provided, "value" object will be not indexed by the search service. Nevertheless, the data will be stored in the store service and all information except value object will be indexed in search service.

  • If the value JSON object does not comply with the provided model (for example, a field change from Integer type to String type), the data will be not inserted in the search service. The data message will be only stored in the store service.

Without a model, you will not be able to search or aggregate on any value.* field.

13.3.2. Set model field to index your data

To make the messages sent by devices indexed in data store you must setting your data model with the following steps :

  • when you provision your decoder set "model" field in your data model.

  • when the "model" field is set and elasticsearch (ES) is enable, you can make elasticsearch queries on value fields only after the messages are decoded by your decoder and indexing service done.

  • each field of value collection is indexed by search service. In order to be able to search the message, copy this 'value' in a @model.value field which is analyzed by Elasticsearch. The message is consistent with others messages having the same model.

Max total field number which can be indexed in ES : the limit allowed per tenant is max 1000 fields.

exemple : data message sent by device and shown the indexed fields with values.

{
    "timestamp" : "2018-05-31T16:15:21.288Z,"
    "streamId" : "urn:lo:nsid:mqtt:{deviceId},"
    "model": "my_encoding_model_v0"
    "value": {
      "temp":     12.75,
      "humidity": 62.1,
      "gpsFix":   true,
      "gpsSats":   [12, 14, 21]
    }
}

Indexed field :

Field

type

temp

float

humiditity

float

gpsFix

boolean

gpsSats

integer

The REST request body search API is provided to perform search queries.

To learn more about the search API, read the Exploring your Data section of Elasticsearch: The Definitive Guide.

13.4.1. To perform a search query

13.4.1.1.1. Request
POST /api/v1/data/search
X-API-Key: <your API key>
Accept: application/json

parameter

description

dsl request (body)

elasticsearch DSL request

13.4.1.1.2. Elasticsearch 7

A major upgrade of our search engine from Elasticsearch 5 to Elasticsearch 7 has been made in 2021. The search request DSL body parameter will follow the Elasticsearch 7 one.

There are a few breaking changes compared to the previous one based on version 5, mainly some deprecated operators or changes in naming.

You need to ensure you are not currently using these specific operators before the change will apply.

You will receive a HTTP 400 response in such a case.

Below are the main changes :

  • Queries on boolean fields now strictly parse boolean-like values. This means only the strings "true" and "false" will be parsed into their boolean counterparts.

  • The 'in' query (a synonym for the 'terms' query) has been removed

  • Support for empty query objects ({ }) has been removed from the query DSL

  • The deprecated 'geo_distance_range' query has been removed

  • The 'all_fields' parameter for the 'query_string' and 'simple_query_string' has been removed. Set 'default_field' to '*' instead.

  • The deprecated 'prefix' parameter (a synonym for the 'value' parameter) of the 'prefix' query has been removed.

  • The deprecated 'le' (a synonym for 'lte') and 'ge' (a synonym for 'gte') parameter of the range query have been removed.

The full list can be found here (refer to section 'Search and Query DSL changes') :

The response of /api/v0/data/search request will stay unchanged.

But the new API version /api/v1/data/search uses the new default Elasticsearch 7 behavior : hits.total is limited to 10.000 documents; and the field is now a JsonObject instead of a number :

api/v0 response sample
{
  "hits": {
    "total": 10123,
    ...
  }
}
api/v1 response samples
{
  "hits": {
    "total": {
      "value": 1000,
      "relation": "eq"
    },
    ...
  }
}


{
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"
    },
    ...
  }
}

In this new v1 API, you can also use the query parameter trackTotalHits=true to force a full count (i.e. that can exceed 10.000).

13.4.1.1.3. Example

This query requests statistics from the myDeviceTemperature stream temp field.

Request:

POST /api/v1/data/search
{
  "size": 0,
  "query": {
    "term": {
      "streamId": "myDeviceTemperature"
    }
  },
  "aggs":
  {
    "stats_temperature": {
      "stats": {
        "field": "@temperature_v0.value.temp"
      }
    }
  }
}

If a model has been provided, search query must be prefixed by @<model>: @temperature_v0.value.datapath

Response:

{
  "took": 1,
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    }
  },
  "aggregations": {
    "stats_temperature": {
      "count": 2,
      "min": 24.1,
      "max": 25.9,
      "avg": 25,
      "sum": 50
    }
  }
}

To perform the same search query; but with the 'hits' part extracted and JSON formated as an array of data messages (to use when you are only interested in the 'hits' part of Elasticsearch answer):

13.4.1.2.1. Request
POST /api/v1/data/search/hits
X-API-Key: <your API key>
Accept: application/json

parameter

description

dsl request (body)

elasticsearch DSL request

13.4.1.2.2. Example

This query requests last data for all devices using the model: temperature_v0.

Request:

POST /api/v0/data/search/hits
{
  "size": 10,
  "query": {
    "term": {
      "model": "temperature_v0"
    }
  }
}

Response:

[
  {
    "id": "57308b3b7d84805820b35345",
    "streamId": "myDeviceTemperature",
    "timestamp": "2016-05-09T13:06:03.903Z",
    "model": "temperature_v0",
    "value": {
      "temp": 25.9
    },
    "created": "2016-05-09T13:06:03.907Z"
  },
  {
    "id": "573087777d84805820b35344",
    "streamId": "myDeviceTemperature",
    "timestamp": "2016-05-09T12:49:59.966Z",
    "model": "temperature_v0",
    "value": {
      "temp": 24.1
    },
    "created": "2016-05-09T12:49:59.977Z"
  },
  {
    "id": "5730b1577d84805820b35347",
    "streamId": "myStreamDemo-temperature",
    "timestamp": "2016-05-09T15:48:39.390Z",
    "model": "temperature_v0",
    "value": {
      "temp": 24.1
    },
    "created": "2016-05-09T15:48:39.395Z"
  }
]

13.4.2. Geo Queries

Geo Query can be performed through all fields with name matching location (case insensitive).
In order to geoquery these fields, you must add @geopoint to the location query path: location@geopoint.

Request:

POST /api/v1/data/search/hits
{
  "query": {
     "bool" : {
        "must" : {
          "match_all" : {}
     },
     "filter": {
        "geo_distance": {
          "distance": "10km",
          "location.@geopoint": {
            "lat": 43.848,
            "lon": -3.417
          }
        }
      }
    }
  }
}

Response:

[
  {
    "id": "57308b3b7d84805820b35345",
    "streamId": "myDeviceTemperature",
    "location": {
      "lat": 43.8,
      "lon": -3.3
    }
    "timestamp": "2016-05-09T13:06:03.903Z",
    "model": "temperature_v0",
    "value": {
      "temp": 25.9
    },
    "created": "2016-05-09T13:06:03.907Z"
  }
]

13.4.3. Search Query samples

Here are some query samples that can be used. Aggregations are very useful to retrieve data grouped by any criteria: list all known tags, get all last value per stream, get mean temperature per tag, get the list of streams that have not send data since a date…​ The aggregations results are stored as 'buckets' in the result.
You can also add filters (geoquery, wildcards, terms…​) to all your aggregations query to target specific 'buckets' or data.

13.4.3.1. Give me all you got !

Request:

{
  "query": {
    "match_all": {}
  }
}
13.4.3.2. Give me the list of all known tags

Request:

{
  "size": 0,
  "aggs": {
    "grouped_by_tags": {
      "terms": {
        "field": "tags"
      }
    }
  }
}

Response:

{
  "took": 44,
  "hits": {
    "total": {
      "value": 66,
      "relation": "eq"
    }
  },
  "aggregations": {
    "grouped_by_tags": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "tag_1",
          "doc_count": 53
        },
        {
          "key": "tag_2",
          "doc_count": 13
        }
      ]
    }
  }
}
13.4.3.3. Give me the last value of all my streams

Request:

{
  "size":0,
  "aggs": {
    "tags": {
      "terms": {
        "field": "streamId"
      },
      "aggs": {
        "last_value": {
          "top_hits": {
            "size": 1,
            "sort": [
              {
                "timestamp": {
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

Response:

{
  "took": 19,
  "hits": {
    "total": {
      "value": 11,
      "relation": "eq"
    }
  },
  "aggregations": {
    "tags": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "device_1",
          "doc_count": 7,
          "last_value": {
            "hits": {
              "total": 7,
              "max_score": null,
              "hits": [
                {
                    ...
                }
              ]
            }
          }
        },
        {
          "key": "device_2",
          "doc_count": 123,
          "last_value": {
            "hits": {
              "total": 123,
              "max_score": null,
              "hits": [
                {
                    ...
                }
              ]
            }
          },
         ...
        }
      ]
    }
  }
}
13.4.3.4. Give me the list of devices that have not send data since 2017/03/23 10:00:00

Request:

{
  "size":0,
  "aggs": {
    "tags": {
      "terms": {
        "field": "streamId"
      },
      "aggs": {
        "last_date": {
          "max": {
            "field": "timestamp"
          }
        },
        "filter_no_info_since": {
          "bucket_selector": {
            "buckets_path": {
              "lastdate":"last_date"
            },
            "script": {
              "inline": "lastdate<1490263200000",
              "lang":"expression"
            }
          }
        }
      }
    }
  }
}

Response:

{
  "took": 8,
  "hits": {
    "total": {
      "value": 9,
      "relation": "eq"
    }
  },
  "aggregations": {
    "tags": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "device_12",
          "doc_count": 7,
          "last_date": {
            "value": 1489504105020,
            "value_as_string": "2017-03-14T15:08:25.020Z"
          }
        },
        {
          "key": "device_153",
          "doc_count": 2,
          "last_date": {
            "value": 1489049619254,
            "value_as_string": "2017-03-09T08:53:39.254Z"
          }
        }
      ]
    }
  }
}

14. Message routing

This chapter explains how you can route data messages or device oriented events to an external system, via Live Objects FIFO queues or httpPush (webhooks).

In order to route your messages, you must provision an action policy:

  • which messages you want to route (triggers)

  • how you want to route your messages (actions)

14.1. Action policy

The relationship between a trigger and multiple actions is called an action policy. The action policy must be provisioned in Live Objects with the http API or using the web portal. Once the action policy provisioned and activated (field enabled set to true), your messages will be routed using the chosen action mode (fifo queue or http push).

Prior to provisioning you rule, please make sure:

  • you have created your FIFO in Live Objects if you want to use a FIFO queue

  • your web server is up-and-running if you want to use http push action

Only new data messages are routed once the action policy is provisioned. Existing data messages in your Live Objects data storage are not.

An action policy is composed of 2 main sections:

  • triggers: define what you want to route. Usually, one trigger is defined in one action policy, except for device provisioning events, where you can define a trigger for deviceCreated events, and a trigger for deviceDeleted events, in the same action policy.

  • actions: define how you want to route these messages/events.

The action policy API is detailed in swagger.

14.1.1. Provisioning

To create a new action policy:

Endpoint:

POST /api/v1/event2action/actionPolicies
An action policy for message routing has the following top level data representation:
{
  "name": "some_user_defined_policy_name",
  "enabled": true,
  "triggers": {
    "dataMessage": {
      "version": 1,
      "filter": {
        "connectors": [
          "lora"
        ],
        "groupPaths": [
          {
            "includeSubPath": false,
            "path": "/europe/france"
          }
        ],
        "tags": [
          ["HIGH","ALERT"],["PROD"]
        ]
      }
    }
  },
  "actions": {
    "fifoPublish": [
      {
        "fifoName": "myFifoAlreadyCreatedInLiveObjects"
      }
    ]
  }
}

The policy id is automatically created by Live Objects and will be return in the POST response body

field name is required description

name

optional

Defines a user friendly name for the action policy

enabled

required

Enable or disable the action policy

suspension

optional

In case of abnormal activity on this rule, it can be suspended ('enabled' will be set to false). Read-only : this field is handled by the platform. Once the problem is corrected, use the PUT API with enabled=true to resume the rule.

triggers

required

Defines the type of trigger that will start an action.

Filtering section: criteria in a filter are combined with a AND boolean logic. OR operator is applied between each elements inside filter’s list. The filters depend on the trigger type.

Note: triggers object should have exactly one trigger defined in most of the case (except for deviceCreated & deviceDeleted)

dataMessage

optional

Available filters for data message:
  • connectors: a list of interfaces to be monitored ("http", "mqtt", "lora", "sms", "x-connector")

  • deviceIds: a list of device identifiers (as String)

  • groupPaths: a list of device group paths

  • tags: a list of lists of tags.

deviceStatus

optional

The device status can be one of the following: "ONLINE", "OFFLINE", "REGISTERED", "DELETED", "ACTIVATED"…​ See all the device status in this chapter.

Available filters for the device status events:
  • connectors: a list of interfaces to be monitored ("http", "mqtt", "lora", "sms", "x-connector")

  • groupPaths: a list of device group paths

deviceCreated

optional

Available filters for the device created events:
  • connectors: a list of interfaces to be monitored ("http", "mqtt", "lora", "sms", "x-connector")

  • groupPaths: a list of device group paths

  • tags: a list of lists of tags

deviceDeleted

optional

Available filters for the device deleted events:
  • connectors: a list of interfaces to be monitored ("http", "mqtt", "lora", "sms", "x-connector")

  • groupPaths: a list of device group paths

  • tags: a list of lists of tags

commandStatus

optional

Available filters for the command status events:
  • status: a list of command status to be monitored ("pending", "processed"…​) See more details in the device management chapter.

loraNetwork

optional

Available filter for the network info events from LoRa® devices:
  • messageTypes: a list of LoRa® network info events within six available message types:

    • "UNCONFIRMED_DATA_UP"

    • "CONFIRMED_DATA_UP"

    • "UNCONFIRMED_DATA_DOWN"

    • "CONFIRMED_DATA_DOWN"

    • "JOIN_REQUEST"

    • "JOIN_ACCEPT"

loraGatewayStatus

optional

Sent event when a LoRa® gateway status changes. Status can be "ONLINE", "OFFLINE" or "UNKNOWN".

actions

required

Defines the type of action:

emails

optional

A collection of Email actions (see Email notification section)

sms

optional

A collection of SMS actions (see SMS notification section)

fifoPublish

optional

A collection of FIFO names where the event message will be published (see FIFO notification section)

httpPush

optional

A collection of Http Push actions (see Http Push action section)

azureEventHubs

optional

A collection of Azure Event Hubs actions (see Azure Event Hubs notification section)

To retrieve your action policy:

Endpoint:

GET /api/v1/event2action/actionPolicies/{policyId}

14.1.2. Examples

An example of an action policy with triggering on a new data message for a specific device. The output message is routed to a specific FIFO.
{
    "id": "202ada2a-e267-4427-9d7f-2756c2a2b1dd",
    "name": "push data fifo",
    "enabled": true,
    "triggers": {
        "dataMessage": {
            "version": 1,
            "filter": {
                "deviceIds": ["<your_device_id>"]
            }
        }
    },
    "actions": {
        "emails": [],
        "sms": [],
        "httpPush": [],
        "fifoPublish": [
            {"fifoName": "<your fifo name>"}
        ]
    }
}
The same example of an action policy with triggering on a new data message for a specific device. the output message is pushed to a web site using HTTP Push action.
{
    "id": "202ada2a-e267-4427-9d7f-2756c2a2b1de",
    "name": "Push data message with a webhook",
    "enabled": true,
    "triggers": {
        "dataMessage": {
            "version": 1,
            "filter": {
                "deviceIds": ["<your_device_id>"]
            }
        }
    },
    "actions": {
    "emails": [],
    "sms": [],
    "httpPush": [
    {
        "webhookUrl": "https://webhook.site/....",
        "headers": {
          "authorization": [
            "Bearer 00000000-0000-0000-0000-000000000000"
          ]
        },
        "content": "<text>+<mustache template>",
        "retryOnFailure": true
      }
    ],
    "fifoPublish": []
  }
}

Now that you know how to create an action policy, you can find the format of all public data messages and events in this chapter.

14.2. Triggers

You probably want to route only a subset of your messages. In order to choose which messages to route, the triggers section must be set in the action policy. Triggers enable downstream action execution, passing the event or the message to the specified actions.

14.2.1. Format

Example of a trigger for data message routing
 "triggers": {
    "dataMessage": {                    (1)
      "version": 1,                     (2)
      "filter": {                       (3)
        "connectors": [ "mqtt","sms"],
        "groupPaths": [{
            "includeSubPath": false,
            "path": "/europe/france"
          }]
      }
    }
  }
1 the type of message to be routed : data message, deviceStatus, commandStatus message
2 expected public data message output version
3 filter definition: criterias to choose which messages will be routed
more info on public data message format

14.2.2. Message filtering

Message filtering will select the messages and apply all filters with a "AND" logic operators: groupPaths, connectors, deviceIds, tags. Filters lists are limited to 20 items.

In the previous example, the message will be selected if it has been emitted through the "mqtt" OR "sms" connector, AND belonging to "/europe/france" group.

Filter Available for Description

filter.groupPaths

dataMessage, deviceStatus, deviceCreated, deviceDeleted

Filter the messages based on the group of the device that posted it. The message will pass through the filter when at least one group matches ("OR" logic).

filter.connectors

dataMessage, deviceStatus, deviceCreated, deviceDeleted

Filter the messages based on the network connector ("http", "lora", "mqtt", "sms", "x-connector") used to post it. The message will pass through the filter when at least one connector element matches ("OR" logic).

filter.deviceIds

dataMessage, deviceActivity

Filter the messages based on the deviceId of the device that posted it ('metadata.source' field). The message will pass through the filter when at least one deviceId matches ("OR" logic).

filter.tags

dataMessage, deviceCreated, deviceDeleted

Filter the messages based on its 'tags' field. The message will pass through the filter when all of the tags in at least one of the set of tags matches. For instance :

  • [["HIGH", "ALERT"],["PROD"]] will match any message containing 'PROD' tag;

  • and also any message containing both 'HIGH' and 'ALERT' tags.

filter.status

commandStatus

List of command status : PENDING, PROCESSING, PROCESSED, CANCELED, ERROR, RETRYING, EXPIRED.

filter.ruleId

stateChange, deviceActvity, matchingFired

List of rule ids to filter.

filter.messageTypes

loraNetwork

List of message types: "UNCONFIRMED_DATA_UP", "CONFIRMED_DATA_UP", "UNCONFIRMED_DATA_DOWN", "CONFIRMED_DATA_DOWN", "JOIN_REQUEST", "JOIN_ACCEPT"

14.3. Actions

14.3.1. FIFO publish action

The purpose of this action is to publish to a Live Objects FIFO when a trigger is activated. FIFO publish is a routing feature without mustache templating (i.e. the entire data message or event is published in the FIFO, you can’t template it).

The API to manage FIFO is detailed in swagger.

Representation of a FIFO action
{
    "fifoName": "destinationfifo"
}

fifoName

Name of the FIFO that will receive the triggered message

Example of an action policy routing all new data messages to a FIFO
{
    "name": "push data new to fifo",
    "enabled": true,
    "triggers": {
        "dataMessage": {
        "version": 1
    }
  },
    "actions": {
        "fifoPublish": [{"fifoName":"mydata"}]
    }
}
Example of an action policy sending data messages for a specific device to a FIFO
{
    "name": "push data new to fifo",
    "enabled": true,
    "triggers": {
        "dataMessage": {
        "version": 1,
        "filter": {
            "deviceIds": ["urn:lo:nsid:mqtt:deviceId2"]
        }
    }
  },
    "actions": {
        "fifoPublish": [{"fifoName": "mydata"}]
    }
}

14.3.2. Http Push action

The purpose of this action is to do an HTTP POST to a given URL with custom headers and a custom body. The body can be templated using the Mustache templating syntax.

Depending on the user needs, a retry policy can be enabled to be more resilient to listening endpoint downtimes.

Representation of a Http Push action
{
     "webhookUrl": String,
     "headers": Map of <String,List of String> ({"key": ["value1","value2",...]}),
     "retryOnFailure": boolean,
     "jsonPath": String,
     "content": String
}
field name is required description

webhookUrl

required

defines the location of the webhook (only the secured ports 443, 8443 and 9243 are allowed, the insecure ports ex: 80 or 8080 are not supported).

headers

optional

defines custom headers that are sent along the HTTP POST request.
This can be used to pass authorization headers or any header required to connect to an endpoint.

retryOnFailure

optional

Enables retry on failure policy (see related section)

jsonPath

optional

Select a part of the triggering data using a jsonPath syntax. This selected data will be used as the root of the template datacontext. This field can be omitted when you what to work with the whole data in template.

content

optional

A string representing a Mustache template. This template will be rendered as the request body.

Example of Http Push action on a data message trigger
{
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
        "dataMessage": {
            "version": 1
        }
    },
    "actions": {
        "httpPush": [{
            "webhookUrl": "https://hooks.myservice.com/services/SOMEWEBHOOKREFERENCE",
            "headers": {"authorization": ["Bearer 00000000-0000-0000-0000-000000000000"]},
            "retryOnFailure": true,
            "content": "{\"text\": \"data pushed to stream : {{streamId}}, at {{timestamp}}\"}"
        }]
    }
}
14.3.2.1. Generated headers
x-orange-lo-policy-id

Every Http Push request contains a header with the action policy id.

If the id of an action policy is 6c95837b-251d-41d8-95f1-42facdf8e71e. The http push will have the following header:

x-orange-lo-policy-id:6c95837b-251d-41d8-95f1-42facdf8e71e
x-orange-lo-message-id

Every Http Push request contains a header with an id that identifies that push uniquely (this id will be kept accross retries in case of errors). This id can be used to identify if a message has been delivered multiple times to the webhook.

x-orange-lo-message-id: 00000000-0000-0000-0000-000000000000

Live Objects will try to validate the body of the HTTP POST as JSON object and will set the request Content-Type header accordingly:

  • application/json if the body contains valid JSON object

  • test/plain otherwise

14.3.2.2. Policy and error management

When an error message is sent back by the destination resource, a retry policy will occur (if configured when the Http Push Action was created). The Http Push action will be retried depending on the HTTP error code sent back from the destination resource to Live Objects.

Table 11. Error handling according to HTTP ERROR
HTTP ERROR CLASS Error handling mode

4xx

Unrecoverable error: discard Http Push action

5xx

Recoverable error: retry Http Push action execution (if retryPolicy is true) otherwise discard the Http Push action execution

When enabled, the retry policy will try to regularly post a request to the resource referenced by the Http Push action url parameter. These retries will be attempted over around twenty-four hours. The retry pattern is subject to change, but it currently follows:

Table 12. Retries and delays (in order)
# of retry delay between retry

3

5 seconds

3

5 minutes

12

2 hours

In the case where the retries are unsuccessful, the Http Push action execution is discarded.

If the HttpPush error rate is too high (> 90%) for 7 consecutive days; the ActionPolicy will be disabled. Its suspension field will provide additional details.

14.3.2.3. Message Overflow

If the targeted servers fot HTTP Push (webHook) are down or slow, HTTP push requests will be buffered. The buffer size, mutualized between all your HTTP Push action policies can contain up to 10.000 requests. If this limit is reached, the oldest request will be discarded first and an AuditLog will be recorded.

As a consequence, if more than 10.000 messages are waiting to be pushed to your HTTP servers, then some of them will start to be dropped. The messages pending retry are not included in this amount.

There are 2 typical cases where this can happen :

  • the HTTP server is not available, then each message needs to wait for the 5s timeout before continuing its retry cycle

  • the HTTP server has a slower response time than the rate at which messages are being pushed

If this happens, the number of pending messages will increase up to 10.000 and the overflow mechanism will be triggered.

In order to decrease the risk of congestion and overflow, HTTP Push requests are performed with some parrallelism when several messages are pending (up to 10 concurrent requests).

14.3.2.4. Security considerations

A secure resource endpoint (HTTPS) should always be used. Using a non secure endpoint (HTTP) is a security issue as the data exchange between Live Objects and the resource endpoint will not be encrypted. This is especially true when leveraging the custom headers mechanisms to pass authentication token.

As a general recommendation, when using a custom authorization headers, consider it unsecure and be sure to give the token/credentials the least permissions. It should only be able to do an HTTP POST on the defined resource location.

14.3.2.5. Http Push Results

Each Http Push action with an ERROR will generate an audit log message. This can help analysing traffic problems.

The solution is to:

{
    "tenantId": "httppush550b5cd6-b8c6-49a4-baa9-d3c21a84202d",
    "httpPushRequest": {
        "url": "http://localhost:14567",
        "retryOnFailure": false,
        "headers": null,
        "requestBody": "{\"x\":0}",
        "messageUUID": "b5540f77-bbc8-42c8-9942-35c0b133a689"
    },
    "success": false,
    "responseStatusCode": 400,
    "responseBody": "KO",
    "errorMessage": "an error message"
}
14.3.2.6. About HTTPS certificate

When using https to push data to a webhook, the certification chain must be valid according to the default Java 8 JVM implementation. Any self signed certificate or certificate issued by an unknown orginization (according to the JAVA 8 JVM) presented by a webhook will be refused and the http push action will not be executed.

14.3.2.7. About HTTP/HTTPS authorized ports and reachable IP adress
  • The list of ports authorized by Live Objects during a http push action, are: 443 and 8443 (HTTPS), 80 and 8080 (HTTP), 9243 for ES. Other ports are blocked.

  • The Remote HTTP Servers or domains with IPV6 IP adress are not supported by Live Objects.

If you have a 403 forbidden error, you need to check if you have using a right port number. In the other hand, the remote server must allow the port number that you are using.

14.3.3. Azure Event Hubs action

The purpose of this action is to push a message into Azure Event Hubs service. The body can be templated using the Mustache templating syntax.

Depending on the user needs, a retry policy can be enabled to be more resilient to listening endpoint downtimes.

Error management, message overflow, rate limiting, auditlog, certificate aspects are identical to http push action.

Representation of a Azure Event Hubs action
{
        "eventHubsNamespace": "myEventHubsNamespace",
        "eventHubName":"myEventHubName",
        "sharedAccessKeyName":"mySharedAccessKeyName",
        "sharedAccessKey":"mySharedAccessKey",
        "content": "{\"temperature\": {{temp}} }",
        "jsonPath":"value",
        "retryOnFailure":false
}
field name is required description

eventHubsNamespace

required

The Event Hubs namespace where is located the targeted Event Hub.

eventHubName

required

The name of the targeted Event Hub.

sharedAccessKeyName

required

The name of the shared access policy of the targeted Event Hub.

sharedAccessKey

required

The shared access key of the shared access policy.

jsonPath

optional

The json path to extract from the considered message (or event), it will be taken as the root datacontext object when combined with a mustache template in content.

content

optional

A raw string or a mustache (mustache.github.io/mustache.5.html) template describing the webhook body. If empty, the raw event will be used.

retryOnFailure

required

Indicate if a retry policy should be set up in case of a delivery failure.

14.4. Examples

These examples aim at giving a wide range of example to enable an easy implementation of common use cases for users of the triggers and action service.

14.4.1. Post all your data streams on elastic cloud

Even though Live Objects offers you the ability to store and explore your data leveraging the power of Elastic Search, you may want to keep your data on your dedicated space on Elastic’s Cloud.
This example will demonstrate how to route all your incoming data into your elastic search instance and store only the value part of the data.

Pushing data to elastic search cloud needs to pass credentials through basic auth mechanism. This example will demonstrate how to leverage custom headers mechanism to pass credentials for authentication.

1. Create the dedicated action policy
Given
  • a dedicated Elastic instance at url myinstance.cloud.es.io:9243

  • an elastic cloud username liveobjects with password rocks

  • an elastic search index my_lo_example

  • an elastic search type my_lo_type

Endpoint:

POST /api/v1/event2action/actionPolicies

Body:

{
    "name": "push data to elastic cloud",
    "enabled": "true",
    "triggers": {
        "dataMessage": {
           "version": 1
        }
    },
    "actions": {
        "httpPush": [
            {
                "webhookUrl": "https://myinstance.cloud.es.io:9243/my_lo_example/my_lo_type",
                "headers": {"Authorization": ["Basic bGl2ZW9iamVjdHM6cm9ja3MK="]},
                "jsonPath": "value"
            }]
    }
}

Connecting the http push action to a service requiring a JWT token will only need to change the Authorization header to Bearer and pass the token.

2. Push some data

Endpoint:

POST /api/v0/data/streams/my-stream

Body:

{
    "location": {
      "provider": "lora",
      "accuracy": 10,
      "lon": -122.169846,
      "lat": 37.602902},
   "model": "lora_v0",
   "value": {
      "payload": "ae2109000cf6",
      "customMetadata": { "name": "sensor1" }
   },
   "tags": [
      "San Francisco", "Tracker"
     ]
}
3. Check data on elastic cloud

Curl:

curl -X POST -u liveobjects:rocks https://myinstance.cloud.es.io:9243/my_lo_example/my_lo_type/_search -H 'Content-Type: application/json' -d '{ "query": {"match_all": {}}}'

14.4.2. Send a notification to a FIFO when a device is auto-provisioned in Live Objects

This example will demonstrate how to route your device created events to a FIFO queue in order to update your business application device repository when a device is auto-created (here a MQTT device).

14.4.2.1. How to do the test?
  • Create a FIFO in Live Objects

  • Get a Live Objects API key with BUS_R role to read the data on the FIFO

  • Get another Live Objects API key with DEVICE_ACCESS role to use with a mqtt device or a mqtt client to simulate a device

  • Provision an action policy to notify the creation of a new device.

  • Connect a mqtt client with the API key with BUS_R role and subscribe to the FIFO. You should receive the device created event message.

  • Connect the mqtt device (or mqtt client) to Live Objects with the API key as password and the device identifier as clientId. The device will be auto-provisioned in Live Objects.

  • Read the deviceCreated message in the FIFO queue.

  • Make a REST API call to retrieve the device detailed information: GET /api/v1/deviceMgt/devices/{deviceId}

These actions can be done in the Live Objects portal, or with the API:

1. Create a FIFO to retrieve the events

Endpoint:

POST /api/v0/topics/fifo

Body:

{
  "name": "your_fifo_name",
  "maxLengthBytes": 1048576
}
2. Create an API Key with BUS_R role to read data in MQTT in the FIFO

Endpoint:

POST /api/v0/apiKeys

Body:

{
  "active": true ,
  "parentId":"{{parentId}}",
  "label": "myFIFOKey",
  "roles": [
    "BUS_R"
  ]
}

{{parentId}} can be found in the response of user authentication request POST /api/v0/auth

3. Create an API Key with DEVICE_ACCESS role to use with a mqtt device

Endpoint:

POST /api/v0/apiKeys

Body:

{
  "active": true ,
  "parentId":"{{parentId}}",
  "label": "myMqttDeviceKey",
  "roles": [
    "DEVICE_ACCESS"
  ]
}
4. Provision an action policy to be notified when a device is created

Endpoint:

POST /api/v1/event2action/actionPolicies

Body:

{
    "name": "device_created_notification",
    "enabled": true,
    "triggers": {
       "deviceCreated": {
          "version": 1
       }
    },
    "actions": {
        "fifoPublish": [
            {"fifoName": "your_fifo_name"}
        ]
    }
}

If you want to be notified on both deviceCreated and deviceDeleted events, you can set the 2 triggers in the same action policy.

{
    "name": "device_created_or_deleted_notification",
    "enabled": true,
    "triggers": {
       "deviceCreated": {
          "version": 1
       },
       "deviceDeleted": {
          "version": 1
       }
    },
    "actions": {
        "fifoPublish": [
            {"fifoName": "your_fifo_name"}
        ]
    }
}
5. Connect a MQTT client ro retrieve the deviceCreated message from the FIFO
  • Use your API key with BUS_R role as your mqtt password.

  • Connect your MQTT client to Live Objects in application mode.

landing

  • Subscribe to fifo/your_fifo_name

6. Connect a MQTT client (simulating a MQTT device)
  • Use your API key with DEVICE_ACCESS role as your mqtt password.

  • Enter a device identifier in the client ID field.

  • Connect your MQTT client to Live Objects in device mode. The device will be auto-provisioned.

landing

7. Read the message in the FIFO

The following event is present in the FIFO.

{
    "type": "deviceCreated",
    "version": 1,
    "timestamp": "2019-12-04T10:40:58.990Z",
    "deviceId": "urn:lo:nsid:mqtt:myDevice"
}
8. Get the detailed information related to your device

Endpoint:

GET /api/v1/deviceMgt/devices/urn:lo:nsid:mqtt:myDevice

Response:

{
  "id": "urn:lo:nsid:mqtt:myDevice",
  "name": "Auto-created device (mqtt / myDevice)",
  "description": "This device was auto registered by the connector [mqtt] with the nodeId [myDevice]",
  "group": {
    "id": "root",
    "path": "/"
  },
  "interfaces": [
    {
      "connector": "mqtt",
      "nodeId": "myDevice",
      "enabled": true,
      "status": "OFFLINE",
      "lastContact": "2019-12-04T10:41:00.701Z",
      "capabilities": {
        "configuration": {
          "available": false
        },
        "command": {
          "available": false
        },
        "resource": {
          "available": false
        }
      },
      "activity": {
        "apiKeyId": "5de77767d5d6e23710cfdd9e",
        "mqttVersion": 4,
        "mqttUsername": "json+device",
        "mqttTimeout": 60,
        "remoteAddress": "/127.0.0.1:55656",
        "lastSessionStartTime": "2019-12-04T10:40:58.875Z",
        "lastSessionEndTime": "2019-12-04T10:41:00.700Z",
        "security" : {
          "secured": true,
          "protocol": "TLSv1.2",
          "cipher": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
          "clientCertAuthentication": true,
          "sniHostname": "mqtt.liveobjects.orange-business.com"
        }
      },
      "created": "2019-12-04T10:40:58.942Z",
      "updated": "2019-12-04T10:41:00.714Z"
    }
  ],
  "created": "2019-12-04T10:40:58.944Z",
  "updated": "2019-12-04T10:41:00.714Z",
  "activityState": "NOT_MONITORED"
}

14.4.3. Send a notification to a FIFO on device status modification

14.4.3.1. How to do the test?
  • Create a FIFO in Live Objects

  • Get a Live Objects API key with BUS_READ role to read the data on the FIFO

  • Get a Live Objects API key with DEVICE_ACCESS role to use with a mqtt device or a mqtt client to simulate a device

  • Connect the mqtt device (or mqtt client) to Live Objects with the API key as password and the device identifier as clientId.

  • Provision an action policy to be notified if the device has a modification of status

  • Disconnect the mqtt device

  • Connect a mqtt client with the API key with BUS_READ role and subscribe to the FIFO. You should receive the event status change message.

14.4.3.2. Action policy provisioning

To create a new action policy linked with a device event:

Endpoint:

POST /api/v1/event2action/actionPolicies

Body:

{
    "name": "my_device_status_policy",
    "enabled": true,
    "triggers": {
       "deviceStatus": {
          "version": 1,
          "filter": {
            "groupPaths": [{
               "includeSubPath": false,
               "path": "your_group_path"
            }]
          }
       }
    },
    "actions:" {
        "fifoPublish": [
            {"fifoName": "your_fifo_name"}
        ]
    }
}
Example of a device status change event message notified by the action policy

Event:

{
    "type": "deviceStatus",                                             (1)
    "version": 1,                                                       (2)
    "deviceId": "urn:lo:nsid:mqtt:deviceId2",                           (3)
    "updatedInterface": {                                               (4)
        "connector": "mqtt",
        "nodeId": "your_device_identifier",
        "enabled": true,
        "status": {                                                     (5)
            "current": "OFFLINE",
            "previous": "ONLINE"
        }
    },
    "timestamp": "2019-08-29T14:11:58.101Z"
}

Description:

1 event message type
2 message type format version
3 device identifier
4 interface information
5 the status transition

14.4.4. Catch the failure commands and publish the events in realtime

Suppose that you have a device fleet and you need, for each device who receive command, catch all registred commands which has been expired then sent all the failure events notifications to an HTTP site as notification target.

To register your action policy:

Endpoint:

POST /api/v1/event2action/actionPolicies
Example of a policy to be created in Live Objects
{
    "name": "Command status event to push HTTP",
    "enabled": true,
    "triggers": {
      "commandStatus": {
        "version": 1,
        "filter": {
          "status": [
            "EXPIRED",  <--- filtered status
            "ERROR"
          ]
        }
      }
    },
    "actions": {
      "emails": [],
      "sms": [],
      "httpPush": [
        {
          "webhookUrl": "https://webhook.site/ad4ae2f9-179c-4d8a-ba2f-2b9064a8508c", <-- wehbhookUrl where you push your notification messages
          "headers": {},
          "retryOnFailure": true
        }
      ]
    }
}

When Live Objects command mechanism control detects a final event after processing the command ended with value = EXPIRED or ERROR, the trigger sends the following message to the url above:

Event:

{
  "type": "commandStatus",
  "version": 1,
  "id": "5dd4fa1cff8b5acbd100998b",
  "targetDeviceId": "urn:lo:nsid:bike:vin123",
  "status": "EXPIRED",
  "request": {
    "connector": "mqtt",
    "value": {
      "req": "test",
      "arg": {
        "cmd": "reset"
      }
    }
  }
}

14.4.5. Retrieve the LoRa® network events (specific if you have a LoRa® fleet)

Suppose that you wish to retrieve, in a FIFO queue, the raw data emitted by LoRa® devices in confirmed mode or in unconfirmed mode. You also want the join accept events.

To register your action policy:

Endpoint:

POST /api/v1/event2action/actionPolicies
Example of a policy for loraNetwork events
{
    "name": "my new policy to route lora network events",
    "enabled": true,
    "triggers": {
        "loraNetwork": {
            "version": 1,
            "filter": {
                "messageTypes": [
                    "UNCONFIRMED_DATA_UP",
                    "CONFIRMED_DATA_UP",
                    "JOIN_ACCEPT"
                ]
            }
        }
    },
    "actions": {
        "fifoPublish": [
            {
                "fifoName": "myFIFO1234"
            }
        ]
    }
}

15. Messages data model

15.1. Summary

Live Objects platform relies on message processing to provide services such as storing data, detecting events, managing devices. These messages can be injected and listened using several ways: Web portal, https APIs, MQTT(S), Webhook. This is why it is important to understand Live Objects messaging model in order to build business use cases on top of it.

Inside Live Objects platform, Data message carries datas sent by devices through network interfaces (https, MQTT, LoRa®, SMS, …​). These messages will be stored and processed by other services.

Data message format has a key role inside Live Objects as a common input/output format for storing, searching, processing, and routing features.

Note that even if devices can publish their custom data to Live Objects with a specific format depending on the network interface used, Data message will be used as a common format inside the platform.

This chapter provides a global overview of supported output data model, event message model and network event model, please refer to specific section for detailed data model.

By default and without message routing, the messages are stored in standard format. When you need to route them to a business application or when you want to be notified, you should route them by using message routing service. In this case, the format of the datamessages is extended and takes into account the routing information and the rules that routed the datamessages.

15.2. Stored data message

15.2.1. Summary

When the devices publish the messages, they are processed by the data transformation and then the data analysis services, they will be stored according to output formats depending on the connectivity and the applied process. Consumers can access them through API requests.

Depending on your connectivity interface, the data message model stored in Live Objects may have a dedicated sections to describe the parameters of your datas'.

Data journey of unrouted data message

Interactive

Stored data message object model overview

Interactive

The Data message is a JSON object. Please find below a description of its fields.

Field Description

type

dataMessage. This field is set by Live Objects in the routed Data message. In the store/search section, this field is not set.

version

Version number. See the existing versions in the summary. In the store/search section, this field is not set.

streamId

String identifying a timeseries /stream. Enriched by default if not set. Should not contain following characters: ' " \ ; { } ( ) and ' ' (space).

timestamp

Timestamp associated with the collected information. Generally set by the device, enriched by default if not set. Should follow ISO-8601 date time format.

created

Timestamp reflecting the date on which the data was collected by Live Objects.

location

Geo location (lat, lon, alt, accuracy, provider) associated with the declared and/or collected location infos.

model

String used to indicate which schema is used for the value part of the message, more about model field. Can be empty, but can not contains ' ' (space) or '.' (dot) character.

value

Structured representation (JSON object) of the transported info. This field is usually filled with the useful payload (device measurements). Be a JSON object (not a primitive like number or string). Do not contains field name with '.' (dot) character. Size in bytes can not exceed 1 MiB (1024*1024 bytes).

tags

List of strings associated with the message. Used for extra-information.

extra

Enriched by Live Objects and can contains device inventory information like device’s properties.

metadata

Section enriched by Live Objects.

* source: unique identifier of the device, usually the URN (urn:lo:nsid:<namespace>:<id>) * group: group to which the device belongs, defined by its id and its path * connector: lora, mqtt, …​ * network: information from the network, depends on the connector

When the LoRa® device send message to Live Objects, the network set timestamp value and when the message is processed by Live Objects, it set the created field value by his own timer. Live Objects does not process messages according to the chronological order of transmission (timestamp value set by the network provider timestamp) but according to the order of processing (created value set by Live objects).

15.2.2. LoRa® output

Data Message example : Original message sent by device through LoRa® interface

payload sent by device :

e17aae4133333942bc8b0100

stored data after decoding :

{
  "metadata": {
    "source": "urn:lo:nsid:lora:4883C7DF3001114B",
    "encoding": "siconia_temperature_humidity_pressure",
    "group": {
        "path": "/",
        "id": "root"
    },
    "device": {
      "location": {
        "provider": "static",
        "lon": 2.545599,
        "lat": 48.82198
      }
    },
    "network": {
      "lora": {
        "rssi": -110,
        "esp": -111.76,
        "ack": false,
        "fcnt": 27517,
        "devEUI": "20635F0108000C8D",
        "frequency": 868.5,
        "signalLevel": 5,
        "gatewayCnt": 5,
        "sf": 10,
        "messageType": "UNCONFIRMED_DATA_UP",
        "port": 10,
        "snr": 3,
        "location": {
          "provider": "lora",
          "alt": 0,
          "accuracy": 10000,
          "lon": 2.526197,
          "lat": 48.83361
        },
        "roaming" : {
            "operatorNetId": "600031",
            "operatorName": "Stratis IoT"
        },
        "missingFcnt": 0
      }
    }
  },
  "streamId": "urn:lora:20635F0108000C8D!uplink",
  "created": "2021-05-30T19:02:46.789Z",
  "extra": {
    "_outdoor_source_alt_lat_lon",
  },
  "location": {
    "provider": "static",
    "alt": null,
    "accuracy": null,
    "lon": 2.545599,
    "lat": 48.82198
  },
  "model": "lora_v0",
  "id": "60b3e15603b409370d2d2b10",
  "value": {
    "payload": "e17aae4133333942bc8b0100",
    "temperature": 21.81,
    "humidity": 46.3,
    "pressure": 1013.08
  },
  "timestamp": "2021-05-30T19:02:46.161Z",
  "tags": []
}
15.2.2.1. LoRa® network signal infos

The LoRa® decoded message contains the additional fields added by Live Objects enrichment logic. The network section in the LoRa® decoded message (metadata.network) will be enriched by adding the parameter values collected by network. Here is the description of specific fields (network infos) of LoRa® decoded message :

Parameter (field) Description Notes

SNR

The "Signal Noise Ratio" provides an indication on the level of perturbations compare to the signal itself received by the field gateway.

A bad value of SNR may indicates that the device is in a perturbed environment (for example industrial machines that produce high level of electromagnetic radiations), or that the power of the signal is simply too weak to overcome the ambiant noise. A bad SNR is very likely to cause frame loss.

We consider these typical values for SNR:

  1. bad < -13

  2. average [-13 ; -9]

  3. good > -9

RSSI

The "Received Signal Strength Indication" indicates the strength of the "raw signal" that is to say the signal who contains the util information plus the background noise and the interferences due to the transmission.

It is used to estimate if a device is close or not to a gateway and to automatically adapt the data rate for a best compromise between signal quality and battery consumption. So that a strong RSSI is not necessarily better. It has to be considered globally.

We consider these typical values for RSSI:

  1. weak< -115

  2. average [-115 ; -95]

  3. strong > -95

ESP

The "Estimated Signal Power" represents the strength of the useful signal. Basically it can be considered as a measurement of how well a receiver can “hear” a signal from a sender.

It is computed based on the RSS and the SNR with the formula:

ESP=RSSI-10×log(1+10(--SNR10))

We consider these typical values for RSSI:

  1. weak< -110

  2. average [-110 ; -100]

  3. strong > -100

It’s not necessary to have a strong ESP if the level of SNR is low. The signal will be well received but could be more sensible on the environment changes.

SF

The "Spreading Factor" represents the "effort" that a device do to send a message.

If it is useful for a device to use the highest SF (12) when JOINing to maximize the chance to be heared by a gateway, it is better further to use the lowest SF as possible to save the battery . The network server tells automatically to the device to set the appropriate SF depending on the power of the received signal (RSSI).

Minimum SF is 7, maximum is 12.

gatewayCnt

It is the number of LoRa gateway who "heard" the message sent by the device. It is an indicator of network coverage.

It’s better for reliability to have a space redundancy :

> 1 and even

> 3 for a more precise geolocation

signalLevel

This value is a "Signal level" computed from last uplink.

It’s an Orange computation based on previous indicators to estimate the overall quality of the signal on a scale from 1 (very poor) to 5 (very good).

roaming

Field provided if the message is transmitted by a foreign operator network

operatorNetId : Unique identifier of the operator

operatorName : Optional Name of the operator

In practice:

In most cases the network will pilot the device to automatically adapt the strength of the transmission depending on the radio conditions to keep the best compromise between quality and battery saving. This mechanism is called the Adaptative Data Rate (ADR).

Actions who can improve bad communications would be:

  1. Improve Network coverage by adding local gateways

  2. Improve environment or isolate the device from noise if possible

  3. Improve the device: The quality of the antenna is crucial !

15.2.2.2. LoRa® device battery infos

In some cases, LoRa® devices may publish their battery level if the device supports it, 2 ways are then possible :

  • Using the standard Lorawan mechanism: The device publishes the batterie level in a devStatusAns frame. This frame is published in response to a devStatusAns issued by the network. The lora core network on which Live Objects relies sends a devStatusAns only every week, and the battery level is added into the Live Objects data message (metadata.network.lora.batteryLevel) only if the next payload sent by the device is not empty. Otherwise the battery information is not retrieved by Live Objects.

Datamessage sample:
{
  "metadata": {
    "source": "urn:lo:nsid:lora:4883C7DF3001114B",
    "encoding": "siconia_temperature_humidity_pressure",
    "group": {
        "path": "/",
        "id": "root"
    },
    "device": {
      "location": {
        "provider": "static",
        "lon": 2.545599,
        "lat": 48.82198
      }
    },
    "network": {
      "lora": {
        "rssi": -110,
        "esp": -111.76,
        "ack": false,
        "fcnt": 27517,
        "devEUI": "20635F0108000C8D",
        "frequency": 868.5,
        "signalLevel": 5,
        "gatewayCnt": 5,
        "sf": 10,
        "messageType": "UNCONFIRMED_DATA_UP",
        "port": 10,
        "snr": 3,
        "batteryLevel": 53, --> The value is collected by network and enriched in the datamessage
        "location": {
          "provider": "lora",
          "alt": 0,
          "accuracy": 10000,
          "lon": 2.526197,
          "lat": 48.83361
        },
        "missingFcnt": 0
      }
    }
  },
  "streamId": "urn:lora:20635F0108000C8D!uplink",
  "created": "2021-05-30T19:02:46.789Z",
  "extra": {
    "_outdoor_source_alt_lat_lon",
  },
  "location": {
    "provider": "static",
    "alt": null,
    "accuracy": null,
    "lon": 2.545599,
    "lat": 48.82198
  },
  "model": "lora_v0",
  "id": "60b3e15603b409370d2d2b10",
  "value": {
    "payload": "e17aae4133333942bc8b0100",
    "temperature": 21.81,
    "humidity": 46.3,
    "pressure": 1013.08
  },
  "timestamp": "2021-05-30T19:02:46.161Z",
  "tags": []
}
  • Passing the information into the payload itself (field value.payload of the Live Objects datamessage). In this case a decoder is necessary to extract the information from the hexadecimal sequence

Datamessage sample:
{
  "metadata": {
    "source": "urn:lo:nsid:lora:4883C7DF3001114B",
    "encoding": "siconia_temperature_humidity_pressure",
    "group": {
        "path": "/",
        "id": "root"
    },
    "device": {
      "location": {
        "provider": "static",
        "lon": 2.545599,
        "lat": 48.82198
      }
    },
    "network": {
      "lora": {
        "rssi": -110,
        "esp": -111.76,
        "ack": false,
        "fcnt": 27517,
        "devEUI": "20635F0108000C8D",
        "frequency": 868.5,
        "signalLevel": 5,
        "gatewayCnt": 5,
        "sf": 10,
        "messageType": "UNCONFIRMED_DATA_UP",
        "port": 10,
        "snr": 3,
        "location": {
          "provider": "lora",
          "alt": 0,
          "accuracy": 10000,
          "lon": 2.526197,
          "lat": 48.83361
        },
        "missingFcnt": 0
      }
    }
  },
  "streamId": "urn:lora:20635F0108000C8D!uplink",
  "created": "2021-05-30T19:02:46.789Z",
  "extra": {
    "_outdoor_source_alt_lat_lon",
  },
  "location": {
    "provider": "static",
    "alt": null,
    "accuracy": null,
    "lon": 2.545599,
    "lat": 48.82198
  },
  "model": "lora_v0",
  "id": "60b3e15603b409370d2d2b10",
  "value": {
    "payload": "e17aae4133333942bc8b0100",
    "temperature": 21.81,
    "humidity": 46.3,
    "pressure": 1013.08
    "CustomBatteryLevel": 52, --> The value is published by device in the payload and readable only after decoding
  },
  "timestamp": "2021-05-30T19:02:46.161Z",
  "tags": []
}

15.2.3. MQTT output

Data Message example : Original message sent by device or published by business application through MQTT interface

payload sent by device :

{
   "value" : {
      "revmin":9992,
      "CO2":683,
      "doorOpen":false,
      "hygrometry":45,
      "temperature":139,
      "pressure":1367
  },
   "location":{
      "provider":"GPS",
      "lon":2.30886,
      "lat":48.81839
   }
}

stored data :

{
  "metadata": {
    "connector": "mqtt",
    "source":"urn:lo:nsid:mqtt:12345",
    "transformation": {
      "published": {
        "location": {
          "provider": "GPS",
          "lon": 2.30886,
          "lat": 48.81839
        }
      }
    },
    "group": {
      "path": "/",
      "id": "root"
    },
    "network": {
      "mqtt": {
        "clientId":"<my_mqtt_client_id>"
      }
    }
  },
  "streamId":"urn:lo:nsid:mqtt:12345",
  "created": "2021-06-17T09:21:54.377Z",
  "extra": {
    "propertyDevice1":"12:1b:2e"
  },
  "location": {
    "provider": "GPS",
    "lon": 2.30886,
    "lat": 48.81839
  },
  "id": "60cb14322b9f5a61388d3b3b",
  "value": {
    "revmin": 9992,
    "CO2": 683,
    "doorOpen": false,
    "hygrometry": 45,
    "temperature": 139,
    "pressure": 1367
  },
  "timestamp": "2021-06-17T09:21:54.372Z",
  "tags": []
}

binary payload sent by device :

2101120000011006

stored data after decoding :

{
   "metadata": {
      "connector": "mqtt",
      "source": "urn:lo:nsid:mySensor:11",
      "encoding": "decoder_microtracker_v1.0",
      "device": {
        "location": {
            "provider": "static",
            "alt": 12,
            "lon": 164.7337728,
            "lat": 80.8596736
        }
      },
      "group": {
         "path": "/Binary devices",
         "id": "41Uo8K"
      },
      "network": {
         "mqtt": {
            "clientId": "urn:lo:nsid:mySensor:11"
         }
      }
   },
   "streamId": "urn:lo:nsid:mySensor:11",
   "created": "2020-09-11T12:33:17.465Z",
   "extra": {
      "GPS : DOWN": "GEO_CELLULAR : DOWN"
   },
   "location": {
        "provider": "static",
        "alt": 12,
        "accuracy": null,
        "lon": 164.7337728,
        "lat": 80.8596736
   },
   "model": "my_microtracker_v1",
   "id": "5f5b6e8db112b210b85e4012",
   "value": {
      "messageType": "TRACKER_HEARTBEAT",
      "payload": "32313031313230303030303131303036",
      "battery": {
         "energyLevel": 49,
         "charging": false,
         "unmeasurable": false
      },
      "trackerMode": "CLASSIC"
   },
   "timestamp": "2020-09-11T12:33:17.450Z",
   "tags": []
}
The binary payload sent by device will be generated as hexBinary type, see MQTT binary data push.

15.2.4. SMS ouput

Data Message example : Original message sent by device through SMS interface

payload sent by device :

{<<my payload>>}

stored data :

{
   "metadata": {
      "connector": "sms",
      "source": "urn:lo:nsid:sms:331010101",
      "group": {
         "path": "/",
         "id": "root"
      },
      "network": {
         "mobile": {
            "serverPhoneNumber": "20406",
            "msisdn": "331010101",
            "contentType": "TEXT"
         }
      }
   },
   "streamId": "urn:lo:nsid:sms:331010101",
   "created": "2019-08-27T12:29:27.655Z",
   "extra": {},
   "location": null,
   "model": "sms_v0",
   "id": "5d652227a1a7e80da8b4635e",
   "value": {
      "payload": "{<<my payload>>}"
   },
   "timestamp": "2019-08-27T12:29:22Z",
   "tags": []
}

binary payload sent by device :

056096850001010500020700

stored data after decoding :

{
   "metadata": {
      "connector": "sms",
      "source": "urn:lo:nsid:sms:mySensor",
      "encoding": "my_decoder_tracker_v1.3",
      "group": {
         "path": "/binary_devices",
         "id": "An4NOl"
      },
      "network": {
         "mobile": {
            "serverPhoneNumber": "20259",
            "msisdn": "337000003040131",
            "contentType": "BINARY"
         }
      }
   },
   "streamId": "urn:lo:nsid:sms:mySensorData",
   "created": "2020-09-09T10:00:25.696Z",
   "extra": {},
   "location": null,
   "model": "mySensor_v5",
   "id": "5f58a7b9b112b277cb82d34d",
   "value": {
      "adt": "UNUSED",
      "bleFirmwareVersion": "2.7.0",
      "messageType": "HEARTBEAT",
      "payload": "303536303936383530303031303130353030303230373030",
      "temperature": {
         "unit": "°C",
         "value": 23.28
      },
      "ack": 0,
      "deviceModel": "mySensor_v5",
      "resetCause": "POWER-ON-RESET",
      "battery": {
         "unit": "V",
         "valueFirmwarePrev15": 3.39,
         "value": 3.62,
         "inCharge": false
      },
      "firmwareVersion": "1.5.0",
      "status": {
         "onDemand": false,
         "appState": "idle",
         "userAlert": false,
         "periodic": false,
         "moving": false,
         "appMode": "motionStartEndTrack"
      }
   },
   "timestamp": "2020-09-09T10:00:21Z",
   "tags": []
}

15.2.5. Bulk injection output

Data Message example : Original message published through HTTP interface

data push payload :

   {
      "revmin":9992,
      "CO2":683,
      "doorOpen":false,
      "hygrometry":45,
      "temperature":139,
      "pressure":1367
   }

stored data :

{
   "metadata": {
      "connector": "http"
   },
   "streamId": "urn:lo:nsid:sensor:2327398!measures",
   "created": "2020-06-09T15:18:58.050Z",
   "extra": null,
   "location": null,
   "model": "data_model_v1",
   "id": "5edfa862682ee74e3e297595",
   "value": {
      "revmin": 9992,
      "CO2": 683,
      "doorOpen": false,
      "hygrometry": 45,
      "temperature": 139,
      "pressure": 1367
   },
   "timestamp": "2020-06-09T15:18:58.033Z",
   "tags": []
}

15.2.6. Alarm output

Depending on the type of alarm activated, Live Objects store a second output message which is an additional message that describes the rules that triggered the alarm.

For more information about the alarming service, read.

15.2.6.1. Matching rule output
Fired Event data representation

To learn more about Simple event alarm see.

{
  "tenantId": "String",
  "timestamp": "String",
  "firingRule": {
    // The originating firing rule
  },
  "matchingContext": {
    "tenantId": "(String) the id of the tenant",
    "timestamp": "(String) iso-8601 timestamp of the originating matching event",
    "matchingRule": {
      // the originating matching rule
    },
    "data": {
      // the data message that triggered the matching rule and the firing rule
    }
  }
}
Output Fired Event data model.

Interactive

Fired event object model description:

tenantId

String the tenant that issued the fired event,

timestamp

iso-8601 formatted timestamp, representing the date of emission of the fired event,

firingRule

The firing rule that triggered the event,

matchingContext.tenantId

String the tenant that issued the upstream matching event,

matchingContext.timestamp

ISO-8601 timestamp of the upstream matching event,

matchingContext.matchingRule

The rule that triggered the upstream matching event,

matchingContext.data

The Data Message that triggered the event chain,

15.2.6.2. State rule output

To learn more about State event alarm see.

State Changed Event data structure
{
  "stateKey": "String",
  "previousState": "String",
  "newState":  "String",
  "timestamp": "ISO-8601 Date Strin"g,
  "stateProcessingRuleId": "String",
  "data": "<<DATANEWMODEL, Data Message>>"
}
Output State Event data model

Interactive

State event object model description:

stateKey

The state key value,

previousState

Name of the previous state of the stateKey,

newState

Name the new state of the stateKey,

timestamp

ISO-8601 timestamp of the state change event,

stateProcessingRuleId

id of the rule that generated this state change event,

data

the Data Message that triggered the state change,

15.2.6.3. Activity rule output

To learn more about Activity event alarm see.

Activity Event data structure
{
  "deviceId": "String",
  "deviceAdditionalInfo": {
      "deviceName": "String",
      "groupPath": "String"
  },
  "activityRule": "ActivityRule",
  "state":  "String 'SILENT' or 'ACTIVE'",
  "numberOfAlarmReminders": "Integer",
  "timestamp": "ISO-8601 Date String"
}
Output State Event data model

Interactive

Activity event object model description:

deviceId

Id of the device triggering this activity event

deviceAdditionalInfo

Additional information on the device. Consists of the name of the device and the path of the group it belongs to.

activityRule

ActivityRule triggering this activity event

state

Current state of device, either 'SILENT' or 'ACTIVE'

numberOfAlarmReminders

The number of times a reminder has been sent for the current state.

timestamp

ISO-8601 timestamp of the state change event

15.3. Location infos

Device location data in Live Objects is based on the information reported by the published messages, by the data communicated by the network, by Live Objects data processing steps (Decoders, Custom Pipelines), but it can also be declared as a static location when provisioning each device.

The location field in each dataMessage (IOT data) is optional, but when ordered according the timestamp of the dataMessage, it is possible to track the successive locations of the device in time.

15.3.1. Location infos format

When the location data is present in the message, it is structured in a location section according to the following format:

   "location": {
      "provider": "lora",
      "alt": 0,
      "accuracy": 10000,
      "lon": 2.314306,
      "lat": 48.853233
   },
Field Description

provider

optional. This field indicates the origin of the provided location data. Can be set by device, by network (enrichment process), by decoder, or by custom pipeline (External Enricher).

alt

optional. Altitude measurement value.

accuracy

optional. Accuracy is the tendency of the measurements to agree with the true value.

lon

mandatory. Longitude measurement value.

lat

mandatory. Latitude measurement value.

The structured data of the location in the location fields makes it possible to standardize the processing of this information:

  • By using the geolocation aggregation to build various aggregates of the devices.

  • To display the last known position of the device in a map (Live Objects portal), by taking the last message sent by the device.

  • To display tracking information, by using location data associated with the message timestamps.

15.3.2. Static location

The static location can be added in the device representation. Cf. device representation with the staticLocation section.

This section can be added or updated on an existing device by using:
PATCH /api/v1/deviceMgt/devices/<myDeviceId>
 {
    "id": "<myDeviceId>",
    "description": "Device 123",
    "name": "My Device",
    "staticLocation": {
        "lat": <<Latitude value>>,
        "lon": <<Longitude value>>,
        "alt": <<Altitude value>>
    }
}

Once defined, the static location will also be collected in the stored datamessage after enrichment.

Also, it can be "chosen" as the last kwnown location of a device. In this case, it will be set in the "location" field of a data message. (Cf. Chapter "Assigned location values").

The static location is used to locate the LoRa® gateways in order to optimize the installation and the activation of devices.

Input datamessage
{
    "value": {
        "temperature" : 14.6,
        "battery" : 53,
        "messageAlert":"low battery"
    },

    "location": {
        "lat": 48.86667,
        "lon": 2.33333,
        "alt": 35.2,
        "accuracy": 12.3,
        "provider": "My_embedded_GPS"
    },
    "tags": [ "production", "Orange Live Objects" ]
}
Output datamessage
{
  "metadata": {
    "connector": "mqtt",
    "source": "urn:lo:nsid:my_device",
    "transformation": {
      "published": {
        "location": {
          "provider": "My_embedded_GPS",
          "alt": 35.2,
          "accuracy": 12.3,
          "lon": 2.33333,
          "lat": 48.86667
        }
      }
    },
    "device": {
      "location": {
        "provider": "static",
        "alt": 12,
        "lon": 164.7337728,
        "lat": 80.8596736
      }
    },
    "group": {
      "path": "/",
      "id": "root"
    },
    "network": {
      "mqtt": {
        "clientId": "urn:lo:nsid:my_device"
      }
    }
  },
  "streamId": "urn:lo:nsid:my_stream",
  "created": "2021-06-01T08:02:56.240Z",
  "extra": {
    "_outdoor_source_alt_lat_lon": "appAndroid;48.8737361;2.3610431;83.42344672858451",
    "_indoor_source_building_floor_room": "how to save"
  },
  "location": {
    "provider": "static",
    "alt": 12,
    "accuracy": null,
    "lon": 164.7337728,
    "lat": 80.8596736
  },
  "model": null,
  "id": "60b5e9b08f85ad1604f37662",
  "value": {
    "temperature": 14.6,
    "messageAlert": "low battery",
    "battery": 53
  },
  "timestamp": "2021-06-01T08:02:56.234Z",
  "tags": [
    "production",
    "Orange Live Objects"
  ]
}
Disable enriched staticLocation values in your device datamessages

When you need to use realtime tracking without staticLocation values as last known location, you must delete staticLocation section from your device representation:

PATCH /api/v1/deviceMgt/devices/<myDeviceId>
 {
    "id": "<myDeviceId>",
    "description": "Device 123",
    "name": "My Device",
    "staticLocation": {
    }
}
The staticLocation section must be null and removed from the device representation to disable the consideration of the staticLocation section during processing.

15.3.3. Location provided by the device

Those location data is directly provided by the device, and published into the device payload, two message formats are available:

  • unencoded datamessage contains a location section

  • encoded datamessage contains a location section but readable only after decoding.

15.3.3.1. Unencoded datamessage
Example of published payload
{
    "streamId": "urn:lo:nsid:test:my_device",
    "value": {
        "temperature" : 14.6,
        "battery" : 53,
        "messageAlert":"low battery"
    },
    "location": {           <-- Location data provided by device
        "lat": 48.86667,
        "lon": 2.33333,
        "alt": 35.2,
        "accuracy": 12.3,
        "provider": "My_embedded_GPS"
    },
    "tags": [ "production", "Orange Live Objects" ]
}
Stored datamessage after transformation
{
  "metadata": {
    "connector": "mqtt",
    "source": "urn:lo:nsid:my_device:test",
    "transformation": {
      "published": {
        "location": {
          "provider": "My_embedded_GPS",
          "alt": 35.2,
          "accuracy": 12.3,
          "lon": 2.33333,
          "lat": 48.86667
        }
      }
    },
    "group": {
      "path": "/",
      "id": "root"
    },
    "network": {
      "mqtt": {
        "clientId": "urn:lo:nsid:my_device:test"
      }
    }
  },
  "streamId": "urn:lo:nsid:test:my_device",
  "created": "2021-05-27T13:28:10.376Z",
  "extra": {},
  "location": {                                 <-- Assigned location data
    "provider": "My_embedded_GPS",
    "alt": 35.2,
    "accuracy": 12.3,
    "lon": 2.33333,
    "lat": 48.86667
  },
  "model": null,
  "id": "60af9e6a03b409370dbb1a24",
  "value": {
    "temperature": 14.6,
    "messageAlert": "low battery",
    "battery": 53
  },
  "timestamp": "2021-05-27T13:28:10.371Z",
  "tags": [
    "production",
    "Orange Live Objects"
  ]
}
15.3.3.2. Encoded datamessage
decoded datamessage
{
  "messageType": "TRACKER_POSITION",
  "triggerEvent": "TRACKER_MODE",
  "location": {                  <-- Location data provided by device after payload decoding
    "accuracy": 57,
    "lon": 164.7337728,
    "lat": 80.8596736
  },
  "battery": {
    "energyLevel": 51,
    "charging": false,
    "unmeasurable": false
  },
  "trackerMode": "CLASSIC",
  "status": {
    "wifiFailure": true,
    "bleFailure": true,
    "gpsFailure": false
  }
}
Output datamessage
{
  "metadata": {
    "connector": "mqtt",
    "source": "urn:lo:nsid:bike:test9",
    "encoding": "abeeway_microtracker_v1.0",
    "transformation": {
      "decoder": {
        "location": {
          "provider": "device",
          "accuracy": 57,
          "lon": 164.7337728,
          "lat": 80.8596736
        }
      }
    },
    "group": {
      "path": "/",
      "id": "root"
    },
    "network": {
      "mqtt": {
        "clientId": "urn:lo:nsid:bike:test9"
      }
    }
  },
  "streamId": "urn:lo:nsid:bike:test9",
  "created": "2021-05-29T15:12:49.577Z",
  "extra": {},
  "location": {                                 <-- Assigned location data
    "provider": "device",
    "alt": null,
    "accuracy": 57,
    "lon": 164.7337728,
    "lat": 80.8596736
  },
  "model": "model_abeeway_microtracker_v1",
  "id": "60b259f103b409370d05a98d",
  "value": {
    "messageType": "TRACKER_POSITION",
    "payload": "3333666530343065363937303962633561656361313435396330323836326530623063633139613831633437373061633638613337383730323562306163",
    "triggerEvent": "TRACKER_MODE",
    "location": {
      "accuracy": 57,
      "lon": 164.7337728,
      "lat": 80.8596736
    },
    "battery": {
      "energyLevel": 51,
      "charging": false,
      "unmeasurable": false
    },
    "trackerMode": "CLASSIC",
    "status": {
      "wifiFailure": true,
      "bleFailure": true,
      "gpsFailure": false
    }
  },
  "timestamp": "2021-05-29T15:12:49.543Z",
  "tags": []
}

15.3.4. Location provided by the network

Based on the location technology called Time Difference of Arrival (TDOA) that locates devices using triangulation, in this case LoRa® gateways (min 3 gateways included in the data location collect). Because the gateways are able to collect and transmit timing information, the devices can be located by comparing the times the signals arrive at multiple gateways. TDOA location is advantageous over GPS location in terms of cost and battery drain, but is less accurate. However, TDOA is more accurate than other Cellular based methods.

For LoRa® devices and after enrichment process, the output data message has a network section which contains :

{
  "metadata": {
    "connector": "lora",
    "source": "myStream",
    "encoding": "myDecoder",
    "group": {
      "path": "/my_Sub_Group",
      "id": "O1WpwY"
    },
    "network": {
      "lora": {
        "rssi": -32,
        "esp": -32.54,
        "ack": false,
        "fcnt": 27657,
        "bestGatewayId": "FF020693",
        "devEUI": "70B03000B03GT5",
        "frequency": 867.9,
        "signalLevel": 5,
        "gatewayCnt": 5,
        "sf": 12,
        "messageType": "UNCONFIRMED_DATA_UP",
        "port": 3,
        "snr": 8.75,
        "location": {                 -->(Location data provided by network)
          "provider": "lora",
          "alt": 0,
          "accuracy": 10000,
          "lon": 2.295066,
          "lat": 48.798023
        },
        "missingFcnt": 0
      }
    }
  },
  "streamId": "myStream",
  "created": "2021-04-24T21:49:09.056Z",
  "extra": {},
  "location": {                       -->(Location data assigned after enrichment process)
    "provider": "lora",
    "alt": 0,
    "accuracy": 10000,
    "lon": 2.295066,
    "lat": 48.798023
  },
  "model": "myDecoder",
  "id": "608492558ea8f0470434318f",
  "value": {
    "payload": "039b86028e0801671a",
    "temperature": {
      "unit": "°C",
      "currentTemperatures": [
        {
          "value": 22.4375,
          "timestamp": "2021-04-24T21:36:18.758Z"
        }
      ]
    },
    "humidity": {
      "unit": "%",
      "currentHumidity": [
        {
          "value": 26,
          "timestamp": "2021-04-24T21:36:18.758Z"
        }
      ]
    },
    "battery": {
      "level": {
        "unit": "%",
        "value": 61
      }
    }
  },
  "timestamp": "2021-04-24T21:49:08.758Z",
  "tags": [
    "hygrometry",
    "temperature",
    "indoor"
  ]
}
Here is the datamessage value when the staticLocation is set in the device representation
{
  "metadata": {
    "connector": "lora",
    "source": "myStream",
    "encoding": "myDecoder",
    "device": {
      "location": {                 -->(Location data configured on device)
        "provider": "static",
        "lon": 3.545599,
        "lat": 48.82198
      }
    },
    "group": {
      "path": "/my_Sub_Group",
      "id": "O1WpwY"
    },
    "network": {
      "lora": {
        "rssi": -109,
        "esp": -110.19,
        "ack": false,
        "fcnt": 26316,
        "bestGatewayId": "FF020693",
        "devEUI": "70B03000B03GT5",
        "frequency": 867.9,
        "signalLevel": 5,
        "gatewayCnt": 3,
        "sf": 7,
        "messageType": "UNCONFIRMED_DATA_UP",
        "port": 10,
        "snr": 5,
        "location": {
          "provider": "lora",
          "alt": 0,
          "accuracy": 5000,
          "lon": 2.529708,
          "lat": 48.831375
        },
        "missingFcnt": 0
      }
    }
  },
  "streamId": "myStream",
  "created": "2021-04-24T21:49:09.056Z",
  "extra": {},
  "location": {
    "provider": "static",
    "alt": null,
    "accuracy": null,
    "lon": 3.545599,
    "lat": 48.82198
  },
  "model": "lora_v0",
  "id": "608492558ea8f0470434318f",
  "value": {
    "payload": "32a8"
  },
  "timestamp": "2021-05-26T13:13:53.760Z",
  "tags": []
}

15.3.5. Location provided by an external transformation

Custom pipeline can by used to perform an enrichment on location data. The behavior of this custom pipeline can perform a replacing location data by the location value contained in the response according the defined pipeline override rules.

Two type of steps are available can be used to resolve location coordinates from the input data published by the device or provided by other sources.

15.3.5.1. "Externaltransformation" step

Applied on location field, this external transformation, can be used to override the root location.

Depending on your location value override rule, this resolved value can override the last main location of a DataMessage assigned by previous processing. Also, It can be used to enrich the datamessage without override the main location previously assigned.

15.3.6. Priority location

15.3.6.1. Assigned location values

The assigned location of a DataMessage represents the location selected by Live Objects after the DataMessage has been processed by the data enrichment process, decoding, and custom pipelines. Then it will be assigned to the root of a DataMessage in the end.

As seen above, several sources can collect location values (staticLocation, device or network). Therefore, it becomes necessary to set the root "location" of a DataMessage according to a priority rule.

In output datamessage, the location infos are assigned in the location attribute, in the case of a lot of location providers, only one value is assigned in the location under the following priority rules :

  1. Custom infos manually set by an External Enricher

  2. staticLocation values (if present)

  3. location section values extracted after a message decoding (if the decoding service successfully decode message and the message contains a valid location section)

  4. Published location in the message by the device

  5. location section provided by the network

To retrieve the provided location values, here is the metadata section :

Field Description

location

The assigned location. This field (root location) indicates the location infos assigned by Live Objects.

metadata.device.location

optional. This field indicates the location provided by the device (the static location).

metadata.transformation.published.location

optional. This field, if present, contains the location infos published by the device.

metadata.transformation.decoder.location

optional. This field, if present, contains the infos published by the device after payload decoding.

metadata.network.lora.location

optional. This field, if present, contains the location infos provided by the network.

In the case where the datamessage contains a multiple location values, then the user can choose the "best" for its use case.
15.3.6.2. Location values processing

The datamessage journey includes the processing of location values step by step and involves several components. For each component, the location value is processed and then enriched in the datamessage:

Interactive
Assigned location by priority (viewing the position of the device on the map).

At the end and before the datamessage storage, the root location is assigned according to the rule specified and described above.

15.3.7. Location providers

15.3.7.1. Reserved providers

This providers are set in the output datamessage depending on the source: device or by the network.

Possible values : static, device, lora
15.3.7.2. Custom providers

When the device or an external transformation gives the location value, the provider becomes free: the device (or a customer) can set this value in the datamessage as need.

15.3.8. Location data retention

In the case of a multiple location data sources all the values are kept in the output datamessage, depending on the enrichment and transformation process rules, the root location is assigned by the prioriy location rule, the other values are retained in the datamessage and stored as metadata.

Input message published by the device
{
  "temperature": 14.6,
  "messageAlert": "low battery",
  "battery": 53,
  "location": {
          "provider": "My_embedded_GPS",
          "alt": 35.2,
          "accuracy": 12.3,
          "lon": 2.33333,
          "lat": 48.86667
        }
}
Stored datamessage
{
  "metadata": {
    "connector": "mqtt",
    "source": "urn:lo:nsid:my_stream",
    "transformation": {
      "pipeline": {
        "success": true,
        "id": "60af8cd2fb240421ed158b34"
      },
      "external": {
        "location": {
          "provider": "custom",
          "alt": null,
          "accuracy": 412,
          "lon": 2.2938888888888886,
          "lat": 48.80138888888889
        }
      },
      "published": {
        "location": {
          "provider": "My_embedded_GPS",
          "alt": 35.2,
          "accuracy": 12.3,
          "lon": 2.33333,
          "lat": 48.86667
        }
      },
    },
    "device": {
      "location": {
        "provider": "static",
        "alt": 12,
        "lon": 164.7337728,
        "lat": 80.8596736
      }
    },
    "group": {
      "path": "/",
      "id": "root"
    },
    "network": {
      "mqtt": {
        "clientId": "urn:lo:nsid:my_device"
      }
    }
  },
  "streamId": "urn:lo:nsid:my_stream",
  "created": "2021-05-31T14:09:18.750Z",
  "extra": {
    "_outdoor_source_alt_lat_lon": "appAndroid;48.8737361;2.3610431;83.42344672858451",
    "_indoor_source_building_floor_room": "how to save"
  },
  "location": {
    "provider": "custom",
    "alt": null,
    "accuracy": 412,
    "lon": 2.2938888888888886,
    "lat": 48.80138888888889
  },
  "model": null,
  "id": "60b4ee0e8f85ad1604e5c9d5",
  "value": {
    "temperature": 14.6,
    "messageAlert": "low battery",
    "battery": 53
  },
  "timestamp": "2021-05-31T14:09:17.911Z",
  "tags": [
    "production",
    "Orange Live Objects",
    "Location with external enricher"
  ]
}
field Content

location

To retrieve assigned data location (provider= custom according the priority rule)

metadata.device.location

To retrieve static location (provider=static).

metadata.transformation.device.location

To retrieve published location (provider=device).

metadata.transformation.external.location

To retrieve resolved location (provider=custom).

15.3.9. Location infos usage

15.3.9.1. Last known location

You can retrieve the last known location from the stored datamessages by using the inventory explorer, here is the example uses the RSQL notation :

.Query
POST /api/v1/data/search/hits
{
        "from":0,                               <-- defines the offset from the first result
        "size":1,                               <-- maximum amount of hits to be returned : last hit (only 1 hit is returned)
        "sort":[
        {
                "timestamp":"desc"                  <-- ordered from the last hit date to the first hit date
        }
        ],
        "query":{
                "bool":{
                        "must":[
                        {
                                "range":{
                                        "timestamp":
                                                {
                                                        "lt":"now"    <-- time now (local time using the UTC timestamp)
                                                }
                                        }
                                },
                                {
                                "exists":{
                                         "field": "location"    <-- the datamessage must contain a location infos
                                        }
                }
                        ],
            "filter": [
                {
                    "term": {
                        "metadata.source": "urn:lo:nsid:mqtt:myTest"  <-- the datamessages are filtred by the deviceId
                    }
                }
            ],
                        "must_not":[                          <-- you must exclude the device activity event from your aggregation
                        {
                                "term":{
                                "model":"event:DeviceActivity"
                                }
                        }
                        ]
                }
        }
}
.Query response
[
    {
        "id": "60d2f5bb0dfe5f1e032db7ed",
        "streamId": "urn:lo:nsid:mqtt:myTest",
        "timestamp": "2021-06-23T08:50:03.562Z",  <--  the last datamessage which contains a location infos
        "location": {                             <-- the value of location
            "lat": 48.86667,
            "lon": 2.33333,
            "alt": 35.2,
            "accuracy": 12.3,
            "provider": "My_embedded_GPS"
        },
        "value": {
            "temperature": 14.6,
            "messageAlert": "low battery",
            "battery": 53
        },
        "tags": [],
        "extra": {},
        "metadata": {
            "connector": "mqtt",
            "source": "urn:lo:nsid:mqtt:myTest",
            "transformation": {
                "published": {
                    "location": {
                        "provider": "My_embedded_GPS",
                        "alt": 35.2,
                        "accuracy": 12.3,
                        "lon": 2.33333,
                        "lat": 48.86667
                    }
                }
            },
            "group": {
                "path": "/Devices MQTT test",
                "id": "G07y4D"
            },
            "network": {
                "mqtt": {
                    "clientId": "urn:lo:nsid:mqtt:myTest"
                }
            }
        },
        "created": "2021-06-23T08:50:03.576Z"
    }
]
15.3.9.2. Static sensor

Useful for devices without motion and without tracking use, use the static location during the device provisioning to save its location and retrieve it in your business application if needed.

Business use cases
- Possible measures and the trigger alarms: temperature, humdity (cold chain), fire detection (CO2/temperature), motion detection, pression,etc.
- Operations : monitoring, location of the intervention site, etc.
Advanced use case : industrial zone pollution monitoring
  • based on the example described in this use case, our use case uses the same devices spread over the area to be monitored, each device monitors an area and triggers an alert when something goes wrong.

  • devices are installed in different places located in the map with a static location.

  • alerts received in real time when the threshold pollution is reached.

  • the affected devices location is available on the map (site location).

  • you can inform the specialised early intervention teams to move to the affected site.

15.3.9.3. Geolocation and fleet management

Uses Live Objects inventory explorer API, useful to manage your fleet under location criteria (and the combination with others criterias).

  • You can supervise your device events by location criteria.

  • You can have a view of last activity of your fleet by location criteria.

  • You can have a coordinates of a problematic devices.

  • Then sent a maintenance team for operation.

15.3.9.3.1. Geolocation by boundary delimitation

Boundary delimitation is the drawing of boundaries on a map, in the context of fleet management, it can be used to monitor the devices operation, to collect their status and the network status in a target area by using a maps. Using inventory explorer API, you can also locate your devices on the map and manage easily your own fleet.

  • You can use the geobound filters

  • You can use the filters to refine your selection or your search by using a combinations of filters

  • You can plan the operations of the maintenance team on your devices fleet and optimize its progress over time and on the intervention pathways using the location map.

15.3.9.3.2. Geolocation aggregations

A bucket aggregation that works on geobound designation. The user can define a point of origin and a set of mean distance range of all its device fleet (or a sub set). The aggregation evaluate the distance of each device location from the centroid and determines the bucket it belongs to based on the ranges (a device belongs to a bucket if the distance between the device and the origin falls within the distance range of the bucket). Then depending on the needs, some operations can be applied on this set of the devices. To learn more, see.

15.3.9.4. Tracking

Based on the collection of location data, ordered over timestamp of each published datamessage, the user can use the geofencing approach :

  • The user can determine the moves of the device in time by collecting the successive positions ordered over a time. Here is the device tracking example using geofencing approach. Then you can receive alert when your device enter or leave a monitored zone.

  • In the other hand, the last collected datamessage which contains a last location data, can gives the last known position of the device.

Business use cases
- Location Data collect: tracking, last known position, alerts etc.
- Dynamic position provided by device, network or cellular infos (useful for devices without GPS).

15.4. Routed messages

15.4.1. Summary

When devices publish messages that require routing to business applications. These messages can be device events, data detection or network events, message routing is applied. Messages can be listened by subscribing to the listen channel (HTTP REST, MQTT api, Webhook). To help their dispatching and use, the messages are labeled (by type) and versioned.

This section provides a global overview of supported routed event types, please refer to specific section for detailed output data model.

Description Public type Available version number Available filters in triggers & actions feature

Data message

dataMessage

1

connectors, groupPaths, deviceIds, tags

Matching fired event

matchingFired

1

ruleIds

State change event

stateChange

1

ruleIds

Device activity event

deviceActivity

1

ruleIds, deviceIds

Device created event

deviceCreated

1

connectors, groupPaths, tags

Device deleted event

deviceDeleted

1

connectors, groupPaths, tags

Device status event

deviceStatus

1

connectors, groupPaths

Command status event

commandStatus

1

status

LoRa® network event

loraNetwork

1

messageTypes

LoRa® gateway status event

loraGatewayStatus

1

 — 

At the moment, only version 1 is available. If new versions are added to the versioning space, the support team will notify you of the change.

15.4.2. Routed data messages

Data event detection is useful for monitoring business data collected by Live Objects to trigger alerts when needed.

Message journey of routed data message

Interactive

The routed datamessage is a JSON object. Please find below a description of its fields.

Field Description

type

dataMessage. This field is set by Live Objects in the routed Data message. In the store/search section, this field is not set.

version

Version number. See the existing versions in the summary. In the store/search section, this field is not set.

streamId

String identifying a timeseries /stream. Enriched by default if not set. Should not contain following characters: ' " \ ; { } ( ) and ' ' (space).

timestamp

Timestamp associated with the collected information. Generally set by the device, enriched by default if not set. Should follow ISO-8601 date time format.

created

Timestamp reflecting the date on which the data was collected by Live Objects.

location

Geo location (lat, lon, alt, accuracy, provider) associated with the collected info.

model

String used to indicate which schema is used for the value part of the message, more about model field. Can be empty, but can not contains ' ' (space) or '.' (dot) character.

value

Structured representation (JSON object) of the transported info. This field is usually filled with the useful payload (device measurements). Be a JSON object (not a primitive like number or string). Do not contains field name with '.' (dot) character. Size in bytes can not exceed 1 MiB (1024*1024 bytes).

tags

List of strings associated with the message. Used for extra-information.

extra

Enriched by Live Objects and can contains device inventory information like device’s properties.

metadata

Section enriched by Live Objects.

* source: unique identifier of the device, usually the URN (urn:lo:nsid:<namespace>:<id>) * group: group to which the device belongs, defined by its id and its path * connector: lora, mqtt, …​ * network: information from the network, depends on the connector

15.4.2.1. MQTT Routed data message
Data Message example : Original message sent by device or published by business application through MQTT interface

payload sent by device :

{
      "revmin":9992,
      "CO2":683,
      "doorOpen":false,
      "hygrometry":45,
      "temperature":139,
      "pressure":1367
}

stored data :

{
   "type":"dataMessage", <=== Message type
   "version":1,          <=== Message version
   "metadata":{
      "connector":"mqtt",
      "source":"urn:lo:nsid:mqtt:12345",
      "transformation": {
        "published": {
            "location": {
            "provider": "GPS",
            "lon": 2.30886,
            "lat": 48.81839
            }
        }
      },
      "group":{
         "path":"/",
         "id":"root"
      },
      "network":{
         "mqtt":{
            "clientId":"<my_mqtt_client_id>"
         }
      }
   },
   "streamId":"urn:lo:nsid:mqtt:12345",
   "created":"2019-09-26T08:03:09.394Z",
   "extra":{
      "propertyDevice1":"12:1b:2e"
   },
   "location":{
      "provider":"GPS",
      "alt":null,
      "accuracy":null,
      "lon":2.30886,
      "lat":48.81839
   },
   "model":"demoDevGuide",
   "id":"5d382598a1a7e8315ce82499",
   "value":{
      "revmin":9992,
      "CO2":683,
      "doorOpen":false,
      "hygrometry":45,
      "temperature":139,
      "pressure":1367
   },
   "timestamp":"2019-09-26T08:03:09.390Z",
   "tags":[
      "tag1",
      "tag2"
   ]
}
15.4.2.2. MatchingFired event

The Data Message flow goes through the Simple Event Processing service. This service can apply custom binary logics (written in jsonLogic syntax) on each message to detect specific events. Theses events will be sent as Live Objects MatchingFired event according to firing policies.

  • type field: matchingFired

  • version field: see summary for the available versions

  • This event can be consumed by a business application using Triggers and Actions feature. In this case, the event contains a type and a version. See first example below

  • Also, this event is stored in Live Objects database (if your commercial offer allows storage). In this case, the event is encapsulated in a Data message format. See second example below

  • More details about the feature, see Simple Event Processing section

MatchingFired event example - case: event retrieved by a business application (FIFO, httpPush)
{
   "type":"matchingFired",
   "version":1,
   "tenantId":"12345",
   "timestamp":"2019-09-05T08:51:06.691Z",
   "firingRule":{
      "id":"18d55812-22ae-4ff7-a632-6c4451069c26",
      "name":"firingTestDevGuide"
   },
   "matchingContext":{
      "tenantId":"12345",
      "timestamp":"2019-09-05T08:51:06.624Z",
      "matchingRule":{
         "id":"298502e0-4dc3-489b-ac21-08c98ad066d3",
         "name":"testEventProcessingDevGuide"
      },
      "data":{
         "type":"dataMessage",
         "version":1,
         "streamId":"urn:lo:nsid:mqtt:1234",
         "timestamp":"2019-09-05T08:51:06.583Z",
         "value":{
            "temp":100,
            "pressure":36575
         },
         "tags":[
         ],
         "extra":{
         },
         "metadata":{
            "source":"urn:lo:nsid:mqtt:1234",
            "group":{
               "id":"CdoJOs",
               "path":"/europe"
            },
            "connector":"mqtt",
            "network":{
               "mqtt":{
                  "clientId":"1234"
               }
            }
         }
      }
   }
}
MatchingFired event example - case: event encapsulated in a data message format and store in Live Objects
{
   "metadata": null,
   "streamId": "event:urn:lo:nsid:mqtt:1234",
   "created": "2019-09-05T08:51:06.703Z",
   "extra": null,
   "location": null,
   "model": "event",
   "id": "5d70cc7aa1a7e85c6b9b587d",
   "value": {
      "matchingContext": {
         "matchingRule": {
            "dataPredicate": "{\">\":[{\"var\":\"value.temp\"},99]}",
            "name": "testEventProcessingDevGuide",
            "id": "298502e0-4dc3-489b-ac21-08c98ad066d3",
            "enabled": true
         },
         "data": {
            "metadata": {
               "connector": "mqtt",
               "source": "urn:lo:nsid:mqtt:1234",
               "group": {
                  "path": "/europe",
                  "id": "CdoJOs"
               },
               "network": {
                  "mqtt": {
                     "clientId": "1234"
                  }
               }
            },
            "streamId": "urn:lo:nsid:mqtt:1234",
            "extra": {},
            "value": {
               "temp": 100,
               "pressure": 36575
            },
            "timestamp": "2019-09-05T08:51:06.583Z",
            "tags": []
         },
         "tenantId": "12345",
         "timestamp": "2019-09-05T08:51:06.624Z"
      },
      "tenantId": "12345",
      "timestamp": "2019-09-05T08:51:06.691Z",
      "firingRule": {
         "name": "firingTestDevGuide",
         "matchingRuleIds": [
            "298502e0-4dc3-489b-ac21-08c98ad066d3"
         ],
         "id": "18d55812-22ae-4ff7-a632-6c4451069c26",
         "aggregationKeys": [
            "streamId"
         ],
         "firingType": "ALWAYS",
         "enabled": true
      }
   },
   "timestamp": "2019-09-05T08:51:06.691Z",
   "tags": [
      "event"
   ]
}
15.4.2.3. StateChange Event

The Data message flow goes through the StateChange Processing service. This service can detect changes in devices' states, for example geozone location changes. These events will be sent as Live Objects State Change event.

  • type field: stateChange

  • version field: see summary for the available versions

  • This event can be consumed by a business application using Triggers and Actions feature. In this case, the event contains a type and a version. See first example below

  • Also, this event is stored in Live Objects database (if your commercial offer allows storage). In this case, the event is encapsulated in a Data message format. See second example below

  • More details about the feature, see State Processing section

StateChange event example - case: event retrieved by a business application (FIFO, httpPush)
{
   "type":"stateChange",
   "version":1,
   "tenantId":"12345",
   "stateKey":"urn:lo:nsid:mqtt:1234",
   "previousState":"normal",
   "newState":"hot",
   "timestamp":"2019-09-05T08:51:06.616Z",
   "stateProcessingRuleId":"fa1ff947-7855-4249-a5fe-f5bafe53efe2",
   "stateProcessingRule":{
      "id":"fa1ff947-7855-4249-a5fe-f5bafe53efe2",
      "name":"temperature state rule"
   },
   "data":{
      "type":"dataMessage",
      "version":1,
      "streamId":"urn:lo:nsid:mqtt:1234",
      "timestamp":"2019-09-05T08:51:06.583Z",
      "value":{
         "temp":100,
         "pressure":36575
      },
      "tags":[

      ],
      "extra":{

      },
      "metadata":{
         "source":"urn:lo:nsid:mqtt:1234",
         "group":{
            "id":"CdoJOs",
            "path":"/europe"
         },
         "connector":"mqtt",
         "network":{
            "mqtt":{
               "clientId":"1234"
            }
         }
      }
   }
}
StateChange event example - case: event encapsulated in a data message format and store in Live Objects
{
   "metadata": null,
   "streamId": "event:urn:lo:nsid:mqtt:1234",
   "created": "2019-09-05T08:51:06.621Z",
   "extra": null,
   "location": null,
   "model": "event",
   "id": "5d70cc7a5705d87bd1b66a8a",
   "value": {
      "stateProcessingRuleId": "fa1ff947-7855-4249-a5fe-f5bafe53efe2",
      "data": {
         "metadata": {
            "connector": "mqtt",
            "source": "urn:lo:nsid:mqtt:1234",
            "group": {
               "path": "/europe",
               "id": "CdoJOs"
            },
            "network": {
               "mqtt": {
                  "clientId": "1234"
               }
            }
         },
         "streamId": "urn:lo:nsid:mqtt:1234",
         "extra": {},
         "value": {
            "temp": 100,
            "pressure": 36575
         },
         "timestamp": "2019-09-05T08:51:06.583Z",
         "tags": []
      },
      "tenantId": "12345",
      "newState": "hot",
      "stateKey": "urn:lo:nsid:mqtt:1234",
      "previousState": "normal",
      "timestamp": "2019-09-05T08:51:06.616Z",
      "stateProcessingRule": {
         "stateKeyPath": "streamId",
         "name": "temperature state rule",
         "stateFunction": "{\"if\":[{\"<\":[{\"var\":\"value.temp\"},0]},\"cold\",{\"<\":[{\"var\":\"value.temp\"},100]},\"normal\",\"hot\"]}",
         "id": "fa1ff947-7855-4249-a5fe-f5bafe53efe2",
         "enabled": true,
         "filterPredicate": "null"
      }
   },
   "timestamp": "2019-09-05T08:51:06.616Z",
   "tags": [
      "event"
   ]
}
15.4.2.4. DeviceActivity event

The Activity processing feature aims to monitor device inactivity. When a device is "SILENT" or goes "ACTIVE" again, an event is generated. These events can be listened with a business application using FIFO or httpPush. In the web portal, these events are displayed as "notifications".

  • type field: deviceActivity

  • version field: see summary for the available versions

  • This event can be consumed by a business application using Triggers and Actions feature. In this case, the event contains a type and a version. See first example below

  • Also, this event is stored in Live Objects database (if your commercial offer allows storage). In this case, the event is encapsulated in a Data message format. See second example below

  • More details about the feature, see Activity Processing section

DeviceActivity event example - case: event retrieved by a business application (FIFO, httpPush)
{
        "type": "deviceActivity",
        "version": 1,
        "deviceId": "urn:lo:nsid:mqtt:1234",
        "deviceAdditionalInfo": {
                "deviceName": "sensor #12",
                "groupPath": "/europe"
        },
        "activityRule": {
                "id": "683bb813-495f-423a-87f6-d87656c8b02c",
                "name": "test 10 min"
        },
        "state": "SILENT",
        "previousState": "UNKNOWN",
        "timestamp": "2020-06-09T07:47:00.004Z",
        "numberOfAlarmReminders": 0
}
DeviceActivity event example - case: event encapsulated in a data message format and store in Live Objects
{
   "metadata":null,
   "streamId":"event:urn:lo:nsid:mqtt:1234",
   "created":"2019-09-05T09:35:00.019Z",
   "extra":null,
   "location":null,
   "model":"event:DeviceActivity",
   "id":"5d70d6c4a1a7e85c6b9b58ab",
   "value":{
      "deviceAdditionalInfo":{
         "deviceName":"Auto-created device (mqtt / 1234)",
         "groupPath":"/europe"
      },
      "numberOfAlarmReminders":0,
      "state":"SILENT",
      "deviceId":"urn:lo:nsid:mqtt:1234",
      "activityRule":{
         "name":"test 10 min",
         "id":"683bb813-495f-423a-87f6-d87656c8b02c",
         "silentPolicy":{
            "duration":"PT10M",
            "repeatInterval":"PT10M"
         },
         "targets":{
            "deviceIds":[
               "urn:lo:nsid:mqtt:1234"
            ],
            "groupPaths":[
            ]
         },
         "enabled":true
      },
      "timestamp":"2020-06-09T07:47:00.004Z"
   },
   "timestamp":"2020-06-09T07:47:00.004Z",
   "tags":[
      "event"
   ]
}

15.4.3. Device events

Device events are reported when an event occurs on the device. The device manager reports this event as a message that will be collected by the routing service, which forwards it to the consumer. Business applications can use the listening channels (HTTP REST, MQTT client and Webhook) in order to have them.

Message journey of routed event message

Interactive
15.4.3.1. Device created event

The deviceCreated events are generated by the Live Objects device manager when a device is provisioned.

These events are notifications and are not aimed at giving full provisioning details about the device. To retrieve the details about the device, you should use the Device Management Inventory REST API.

The deviceCreated notification is useful, for example, when devices are auto-provisioned in Live Objects (see MQTT devices and external connector mode).

The consumption of this event used with the Device Management REST API allow you to update your own business application database for example.

If you are not familiar with the device representation and device management in Live Objects, see Device inventory section.

The event is a JSON object. Please find below a description of its fields.

Field Description

type

deviceCreated. This field is set by Live Objects in the routed event.

version

Version number. See the existing versions in the summary.

deviceId

Device identifier.

timestamp

Timestamp for the routing event.

DeviceCreated event example
{
   "type":"deviceCreated",
   "version":1,
   "deviceId":"urn:lo:nsid:mqtt:1234",
   "timestamp":"2019-09-05T09:50:00.394Z"
}
15.4.3.2. Device deleted event

The deviceDeleted events are generated by the Live Objects device manager when a device is deleted.

These events are notifications and are not aimed at giving full provisioning details about the device. To retrieve the details about the device, you should use the Device Management Inventory REST API.

The consumption of this event used with the Device Management REST API allow you to update your own business application database for example.

If you are not familiar with the device representation and device management in Live Objects, see Device inventory section.

The event is a JSON object. Please find below a description of its fields.

Field Description

type

deviceDeleted. This field is set by Live Objects in the routed event.

version

Version number. See the existing versions in the summary.

deviceId

Device identifier.

timestamp

Timestamp for the routing event.

DeviceDeleted event example.
{
   "type":"deviceDeleted",
   "version":1,
   "deviceId":"urn:lo:nsid:mqtt:1234",
   "timestamp":"2019-09-05T09:55:00.004Z"
}
15.4.3.3. DeviceStatus event

This event is generated by Live Objects when a device interface’s status is changing. Examples :

  • When a LwM2M device recently created connects to Live Objects for the first time, a device status event is generated with the previous status : REGISTERED and the current status : ONLINE

  • When a MQTT device is disconnected, a device status event is generated with the previous status : ONLINE and the current status : OFFLINE

  • When the first JOIN REQUEST is received from a recently created LoRa device, a device status event is generated with the previous status : REGISTERED and the current status : INITIALIZING

This event is internally used by the device manager to update its connectors database. Also, it’s possible to route this event using Triggers and Actions feature. By doing this, a business application can listen and process this event.

Please refer to the Connectivity section for the description of device status state machines on each connectivity (LwM2M, MQTT, LoRa, …). And to the interface status section for a summary of the supported device status.

The device status event is a JSON object. Please find below a description of its fields.

Field Description

type

deviceStatus. This field is set by Live Objects in the routed event.

version

Version number. See the existing versions in the summary.

deviceId

Device identifier.

updatedInterface

Infomation about the interface. In status sub-section, information about the status of the interface with the previous and current state.

timestamp

Timestamp for the routing event.

DeviceStatus event example - case: event retrieved by a business application (FIFO, httpPush).
{
   "type":"deviceStatus",
   "version":1,
   "deviceId":"urn:lo:nsid:mqtt:1234",
   "updatedInterface":{
      "connector":"mqtt",
      "nodeId":"1234",
      "enabled":true,
      "status":{
         "current":"ONLINE",
         "previous":"OFFLINE"
      }
   },
   "timestamp":"2019-09-05T09:50:00.394Z"
}
Please refer to a global overview of supported event occurred on the interfaces of each connector, see Interface section.
15.4.3.4. CommandStatus events

This event is generated by Live Objects plaform when a device command status change occurs. For example, when a command is acknowledged by a MQTT device, a command status event is sent by the platform with the status PROCESSED.

The command status events are triggers than can be mapped to supported actions (HTTP push, fifo…​)

The command status event is a JSON object. Please find below a description of its fields.

Field Description

type

commandStatus. The type is set by Live Objects platform.

version

Version number. See the existing versions in the summary.

id

The id of the command.

targetDeviceId

The deviceId related to the command event.

status

The command status. Refers to command status chapter.

deliveryStatus

The delivery command status. Refers to command status chapter.

errorCode

The error code. Refers to command object model chapter.

request

The request associated to the command

request.connector

The connector used for the command (mqtt, lora…​)

request.value

The request JSON object

response

The device response associated to the command (depends on command status and ackMode used).

response.value

The response JSON object

created

Creation date of the command - string ISO 8601 format in UTC.

updated

Update date of the command (status change) - string ISO 8601 format in UTC.

Please refer to a global overview of supported command statuses of each connector, see Command status section.
CommandStatus event example:
{
  "type" : "commandStatus",
  "version" : 1,
  "id" : "5d9ef867be84e3147f9db0a3",
  "targetDeviceId" : "urn:lo:nsid:mysensor:16503",
  "status" : "PROCESSED",
  "deliveryStatus" : "REPLIED",
  "request" : {
    "connector" : "mqtt",
    "value" : {
      "req" : "reboot",
      "arg" : {
        "delay" : 30000,
        "bootMode" : "safe"
      }
    }
  },
  "response" : {
    "value" : {
      "done" : true
    }
  },
  "created" : "2019-10-10T09:22:47.765Z",
  "updated" : "2019-10-10T09:23:53.318Z"
}

15.4.4. Network event

15.4.4.1. LoRa® network event

This event is generated by Live Objects plaform when a LoRa® device or network perform an action. It is a specific event for LoRa® connectivity. If you don’t use this connectivity, you are not concern with this event.

For example, when a device sends a data without confirmation, a LoRa® network event is sent by the platform with the message type UNCONFIRMED_DATA_UP.

The LoRa® network event is a trigger type in Triggers and Actions feature. These events can be mapped to a supported actions (HTTP push, fifo…​).

The LoRa® network event is a JSON object. Please find below a description of its fields.

Field Description

type

loraNetwork. The type is set by Live Objects platform.

version

Version number. See the existing versions in the summary.

timestamp

The time stamp when the event is emitted.

devEUI

The global end-device ID (for more information, see the chapter 6.2.1 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

appEUI

The global application ID (for more information, see the chapter 6.1.2 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

devNonce

Counter incremented to each emitted Join-request (for more information, see the chapter 6.2.4 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

messageType

Message type of message emitted by the LoRa® device (for more information, see the chapter 4.2.1 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf). List of message types: "UNCONFIRMED_DATA_UP", "CONFIRMED_DATA_UP", "UNCONFIRMED_DATA_DOWN", "CONFIRMED_DATA_DOWN", "JOIN_REQUEST", "JOIN_ACCEPT"

payload

Payload sent by the device

port

The value of FPort field (for more information, see the chapter 4.3.2 of lora-alliance.org/wp-content/uploads/2020/11/lorawan1.0.3.pdf).

signal

The description signal of the best Long Range Router (LRR). Ten field are defined in the standard:

  • rssi: its Received Signal Strength Indicator

  • snr: its Signal Noise Ratio

  • esp: its Estimated Signal Power

  • sf: its Spreading Factor

  • frequency: its frequency

  • signalLevel: signal quality indicator from 1 to 5. It is assessed from the spreading factor and from the signal noise ratio provided by the frame.

  • gatewayCnt: number of macro gateways that have received the message

  • bestGatewayId: ID of the best LoRa® gateway (optional)

  • gateways: list of gateway seen by the LoRa® device (optional)

  • id: id of the gateway

  • rssi: the Received Signal Strength Indicator of the described gateway

  • snr: the Signal Noise Ratio of the described gateway

  • esp: the Estimated Signal Power of the described gateway

result

Only available for JOIN_ACCEPT messages. Values : "success"

rawJoinAccept

Encoded message. This field is used only when the message type is "JOIN_ACCEPT"

frameHeader

The headers' description of the received frame

macCommands

The list of MAC commands emitted by the LoRa® device. Each MAC command is described in according to two fields:

This is an example:

LoRa® network example:
{
   "type":"loraNetwork",
   "version":1,
   "timestamp":"2018-10-13T03:08:19.965Z",
   "devEUI":"0123456789ABCDEF",
   "messageType":"UNCONFIRMED_DATA_UP",
   "payload":"00000100000000000000000100000002000000030000000400000005000000060000000",
   "port":1,
   "signal": {
      "rssi":-114.0,
      "snr":-9.0,
      "esp":-123.51,
      "sf":12,
      "signalLevel":3,
      "gatewayCnt":3
    },
    "frameHeader":{
      "fcnt":13890,
      "adr":true,
      "ack":false,
      "adrAckRequest":false,
      "devAddr":"1000025A",
      "framePending" : true/false  <=== (1)
    },
    "macCommands":[
       {
         "type":"LinkADRAns",
         "rawValue":"0307"
       }
    ]
}
1 For downlinks only
15.4.4.2. LoRa® gateway status event

This event is generated by Live Objects when a LoRa® gateway status is changing.

The LoRa® gateway status event is a JSON object. Please find below a description of its fields.

Field Description

type

loraGatewayStatus. This field is set by Live Objects in the routed event.

version

Version number. See the existing versions in the summary.

gatewayId

Gateway identifier.

status.current

Current status of the gateway. Either "ONLINE", "OFFLINE" or "UNKNOWN".

status.previous

Previous status of the gateway. Either "ONLINE", "OFFLINE" or "UNKNOWN".

timestamp

Timestamp for the routing event.

LoraGatewayStatus event example
{
   "type":"loraGatewayStatus",
   "version":1,
   "gatewayId":"ABCD1234",
   "status": {
      "current":"ONLINE",
      "previous":"OFFLINE"
   },
   "timestamp":"2020-09-11T09:50:00.394Z"
}

16. API’s for business applications

When your device publish data to Live Objects, you have two ways to retrieve them :

  • mode RESTful API: dedicated only to application that will retrieve Data and Events using HTTPS protocol and Restful API architecture design.

  • mode "Application": dedicated only to application that will retrieve Data and Events from FIFO queues (pushed by Notifications rules)

The restriction about the first "mode" is that it’s stateless. In the second one MQTT clients can create a stateful session with the queues and without loss data (persistent sessions).

16.1. REST API

16.1.1. Endpoints

https://liveobjects.orange-business.com/api/

Currently, two version coexist "v0" and "v1". As a consequence all methods described in this document are available on URLs starting by:

https://liveobjects.orange-business.com/api/v0/

or

https://liveobjects.orange-business.com/api/v1/

Some v0 methods have been deprecated and replaced by v1 methods.

16.1.2. Principles

All the functionalities of Live Objects are available on the REST APIs. It is the same API that is used by the Live Objects web portal.

16.1.3. Content

By default all methods that consume or return content only accept one format: JSON (cf. http://json.org ).

As a consequence, for those methods the use of HTTP headers Content-Type or Accept with value application/json is optional.

16.1.4. API-key authentication

Clients of the Live Objects Rest API are authenticated, based on an API key that must be provided with any request made to the API.

This API key must be added has a HTTP header named X-API-Key to the request.

Example (HTTP request to the API):

GET /api/v1/deviceMgt/devices HTTP/1.1
Host: <base URL>
X-API-Key: <API key>

If you don’t provide such an API key, or if you use an invalid API key, Live Objects responds with the standard HTTP Status code 403 Forbidden.

16.1.5. Paging

Some methods that return a list of entities allow paging: the method doesn’t return the full list of entities, but only a subset of the complete list matching your request.

Two standard query parameters are used in the list method (i.e. that must be added at the end of the URL, after a ?, separated by a &, and defined like this: <param>=<value>). These parameters depend on API version.

16.1.5.1. API v0
  • size: maximum number of items to return (i.e. number of items per page),

  • page: number of the page to display (starts at 0).

Those parameters are not mandatory: by default page will be set to 0 and size to 20.

Example:

  • If size=10 and page=0 then item number 0 to 9 (at most) will be returned.

  • If size=20 and page=1, then items number 20 to 39 (at most) will be returned.

Example (HTTP request to the API):

GET /api/v0/topics/fifo?page=100&size=20 HTTP/1.1
Host: <base URL>
X-API-Key: <API key>

The responses of such methods are a “page” of items - a JSON object with the following attributes:

  • totalCount: total number of entities matching request in service (only part of them are returned),

  • size: the value for “size” taken into account (can be different of the one in request if the value was invalid),

  • page: the value for “page” taken into account (can be different of the one in request if the value was invalid),

  • data: list of returned entities.

16.1.5.2. API v1
  • limit: maximum number of items to return (i.e. number of items per page),

  • offset: number of items to skip (starts at 0).

Those parameters are not mandatory: by default offset will be set to 0 and limit to 20.

Example:

  • If limit=10 and offset=0 then item number 0 to 9 (at most) will be returned.

  • If limit=20 and offset=1, then items number 1 to 20 (at most) will be returned.

Example (HTTP request to the API):

GET /api/v1/deviceMgt/devices?limit=100&offset=20 HTTP/1.1
Host: <base URL>
X-API-Key: <API key>
X-Total-Count: <boolean>

The responses of such methods are a list of items. If request header X-Total-Count is true, the total count of items will be present in the HTTP response header.

Response HTTP headers:

  • X-Result-Count: number of items return in the response

  • X-Result-Limit: the value for “limit” taken into account

  • X-Total-Count: Optional. total number of entities matching request in service

16.1.6. HTTPS REST API documentation

All HTTPS REST methods (device management, data management and bus management, etc.) are described in the HTTPS REST API documentation available here : https://liveobjects.orange-business.com/swagger-ui/index.html.

16.2. MQTT API

16.2.1. Using FIFO

16.2.1.1. Principles

Live Objects "message bus" is the central layer between the Connectivity layer and Service layer.

This message bus offers the FIFO’s access mode: * FIFO : the solution to set up a point to point messaging and guarantee that the messages are delivered to the consumer. Messages are stored in a queue on disk until consumed and acknowledged. Each message is delivered to only one consumer, when multiple consumers are subscribed to the same queue concurrently, messages are load-balanced between available consumers. More info: FIFO mode,

Communications in FIFO mode is based on the usage of topics.

16.2.1.2. Messages publish/subscribe

Messages published on a FIFO topic are persisted until a subscriber is available and acknowledges the handling of the message. If multiple subscribers consume from the same FIFO topic, messages are load balanced between them. Publication to and consumption from a FIFO topic use acknowledgement, ensuring no message loss.

For example, on the Live Objects MQTT interface, a publication to MQTT topic "fifo/<your fifo name>" is translated into a message publication on the Live Objects message bus on "fifo/<your fifo name>" topic.

The message exchanged on those topics must respect a standard format.

Tenants are free to use Fifo topics to achieve the communication patterns they need between their devices and applications.

16.2.1.3. FIFO Provisioning

Before being used, a FIFO topic must be created from the Live Objects web portal or by using REST API endpoint.

Example: FIFO provisioning

POST   https://liveobjects.orange-business.com/api/v0/topics/fifo
X-API-Key: <your API key>
Accept: application/json
{
  "maxLengthBytes": 524288,
  "messageTtl": 604800,
  "name": "MyFIFOName"
}
16.2.1.4. FIFO mode / queues
FIFO mode

Interactive

  • On the left, a client publishes in FIFO topic/queue "fifo01" while no consumer is subscribed. The message is stored into the queue, on disk. When later a consumers subscribes to the FIFO topic/queue, the message will be delivered. The message will only disappear from disk once a subscriber acknowledges the reception of the message.

  • On the right, a client publishes on FIFO topic/queue "fifo02" while a consumer is subscribed: the message is stored on disk and immediately delivered to the consumer. The message will only disappear from disk once a subscriber acknowledges the reception of the message. When a consumer that received the message but didn’t acknowledge the message unsubscribes from the topic/queue, the message is put back into the "fifo02" queue and will be delivered to the next available consumer.

16.2.1.5. FIFO size

FIFO are size-limited. The maximum size is given in bytes. Messages will be dropped from the front of the queue to make room for new messages once the limit is reached meaning that the older messages will be dropped first.

The total number of FIFO and the sum of the size of the FIFO is limited depending on your offer.

For more info about limition, see "Limitations" chapter.

16.2.1.6. Usage summary
Usage Description

"Device" mode

The devices use topics to publish data, retrieve commands,configurations and resources update requests.

"External connector" mode

The devices behind this connector use topics to publish data, retrieve commands request.

"Application" mode

The business application use topics to retrieve data and events.

FIFO publish action

Live objects use these topics to publish specific data when triggers are enabled.

16.2.2. "Application" mode

The "application" mode purpose is to retrieve messages available in your FIFOs.

Typically, use this mode when you want to consume flows of data collected by Live Objects.

The FIFO you connect to, must be declared using the FIFO APIs. To push data toward these FIFOs, you must use the Fifo publish action rules.

Application mode can also be used to publish a DataMessage in the specific case that it is not linked to any device.

16.2.2.1. Summary

In "application" mode, you can use this authorized topics:

Direction Topic Description

Subscribe

fifo/{fifoName}

Consume the messages of a fifo

Publish

application/v1/data

Store a DataMessage (specific use case where data is not linked to a device)

16.2.2.2. Connection

When initiating the MQTT connection, to select the "application" mode you must use the following credentials:

  • clientId : any string between 1 and 128 characters long, containing no spaces or special characters except :, - or _ . The MQTT protocol indicates it must be unique per connection, but Live Objects does not enforce it.

  • username : application (case sensitive)

  • password : a valid API Key with BUS_R role to subscribe to FIFO and/or DATA_W to publish DataMessage

To find more information regarding Live Objects MQTT endpoints, please refer to: MQTT endpoints

You must use a secured connection (MQTTS port 8883). The MQTT non-secured connection is not supported for "application" mode.
16.2.2.3. FIFO subscription

To subscribe to a FIFO queue, a MQTT client connected in "application" mode must subscribe to the following MQTT topic:

fifo/{fifoName}

where fifoName is the identifier of the targeted FIFO queue.

This works only if the used API key has no restriction or if the FIFO queue is specified in the API key’s restriction list.

If the subscription succeeds, Live Objects only returns a MQTT SUBACK packet once the subscription is active.

If the subscription fails (for ex. because the FIFO does not exist), a MQTT SUBACK packet is returned based on the MQTT protocol version used. In MQTT 3.1.1, the Failure return code 0x80 will be used. In MQTT 3.1, 0x01 will be returned.

You can refer to your Audit Logs where additional information regarding errors during MQTT connection will be displayed.

16.2.2.4. Data publication

The nominal way to publish DataMessage is to use MQTT External connector mode and publish a Data as a device.

In some specific use cases you may want to publish data without any device enrichment process, similar to the HTTP data store API.

To publish such DataMessage, a MQTT client connected in "application" mode must publish to the following MQTT topic:

application/v1/data

The payload of this publication should follow:

DataMessage publication
{
   "streamId":"urn:lo:nsid:detector_A8:12435355",
   "timestamp":"2019-05-20T16:01:47Z",
   "model":"data_v0",
   "value":{
      "temperature":14.6,
      "battery":53,
      "messageAlert":"low battery"
   },
   "location":{
      "lat":48.86667,
      "lon":2.33333,
      "alt":35.2,
      "accuracy":12.3,
      "provider":"GPS"
   },
   "tags":[
      "production",
      "london"
   ],
   "metadata":{
      "encoding":"base64",
      "source":"urn:lo:nsid:detector_A8:12435355"
   }
}
Field Description

streamId

(Mandatory). The streamId where the data will be stored in; and retrieved using the HTTP store API.

timestamp

(Optional). Should follow ISO-8601 format. If not set, current timestamp will be used.

model

(Optional). Can not contains ' ' (space) or '.' (dot) character. Model is needed to be able to use the search APIs on fields inside the value object.

value

(Optional). JSON compliant object. No inner field name should contains '.' (dot) character.

location

(Optional). If set, geo-query will be available through search APIs.

tags

(Optional) List of additional information used to tag the DataMessage

metadata.encoding

(Optional) In order for the data to be enriched by decoders and pipelines functionalities, 'metadata.encoding' field must be set.

metadata.source

(Optional) source of the data.

If the publication succeeds, Live Objects will acknowledge the message according to the QoS level.

If the publication fails (for ex. because the JSON is badly formatted), Live Objects will nevertheless acknowledge the message according to the QoS level, and an AuditLog message will be sent with anomaly details.

17. Alarming

17.1. Concepts

17.1.1. Alarms rules concepts

3 independent features are available for event processing :

  • Simple Event Processing (SEP) : a stateless service aimed at detecting notable single event from the flow of data messages. Example: raise an event when the device temperature is above 25°C.

  • State processing (SP) : a service aimed at detecting changes in "device state" computed from data messages. Example: raise an event when the device temperature status changes from "cold" to "hot". A state is computed by applying a state function to a data Message. A notification is sent by Live Objects each time a state value change.

  • Activity processing (AP) : detect 'silent devices', i.e. the lack of activity of a device. Example: raise an event when the device is not connected or did not send data message since 1 day.

Event processing and State processing services share common concepts :

  • apply rules when receiving a message : matching rules for SEP and state processing rules for SP. The rules are defined using the JsonLogic format.

  • have a common Context repository where you can store useful information for rule definition If your system is observable and periodically send measurement data, you can observe the state changes and notify them by using context repository (ex your device send periodically ambient temperature measurement : "cold" threshold is when data is below 20°C).

  • have a common Geozone repository where you can store the geographical references (polygons) you may use in your rules.

  • generate output events that your business application can consume to initiate downstream action(s) like alarming, execute a business process, etc.

  • limit the number of created rules (matching, firing and state processing) - order of idea is a thousand - in order to ensure high performances. The idea is to create generic rules and if needed, apply device-specific threshold using the Context repository.

Differences between Simple Event processing and State processing :

  • Simple Event Processing provides a stateless detection function (matching rule) while State Processing provides a stateful (the current state of the device is known by the system) detection function which is useful for use cases more complex than normal/alert status. State processing can be seen as a basic state machine where transitions between states are managed by the state function result and events are transition notifications.

  • Simple Event Processing has a frequency function (firing rule) which defines when "fired events" must be generated : ONCE, ALWAYS, SLEEP.

Alarming E2E overview

Interactive

17.1.2. Notifications concepts

The triggers and actions service purpose is to execute an action on a given trigger. This enables to create notifications easily on an event detection or to enable new external downstream action on new data.

Upon trigger activation, the following actions can be taken :
Email

An email can be sent to one or multiple recipient. The email content and subject can be specified and templated using the event or message as template data context.

SMS

An SMS can be sent to one or multiple recipient. The SMS content can be specified and templated using the event or message as template data context.

Http Push

An http push can be triggered to a particular web hook identified by its url. The data can be forwarded as-is or templated to match a particular format. A retry policy can be enabled if needed.

Publish in a FIFO queue

The alarm events are available in a FIFO queue and can be retrieved with a MQTT client.

Publish in Azure Event Hubs

The message can be sent in your Azure Event Hubs service. The data can be forwarded as-is or templated to match a particular format. A retry policy can be enabled if needed.

17.1.3. Rationale

The role of this service is to provide ability to trigger an action upon a Live Objects message. See message data model Event to Action can enable interesting use cases for the user such as tighter integration of Live Objects to existing communication tools (such as but not limited to Slack, mattermost, HipChat, IFTTT etc.), enable downstream actions on its toolchains (trigger builds or various tasks on jenkins etc.) or enable more complex backend/cloud connectivity.

17.2. Alarm configuration

To configure your event rules and process data message of your streams, you must configure :

17.2.1. Context repository

17.2.1.1. Definition

The context repository is a database that allows storing user data that could be useful in the event rules definition and not present in the data messages. The context may include, for instance, thresholds definition, geographical zones, a list of device identifiers, a user preference, a group of contexts. The context has a key-value format. The key is a string and the value can be a primitive (string, numeric…​), a JSON object or an array. Optional tags are available to ease the search among the tenant contexts.

for geographical zones, a dedicated geozone database is provided. Once the user has provisioned his geozones, they are automatically available in the user context.
17.2.1.2. Context provisioning

The Live Objects API to manage context provisioning are described in the swagger documentation (Event processing - Context section) : https://liveobjects.orange-business.com/swagger-ui/index.html.

17.2.1.3. Context groups

A context value may reference other context keys. Instead of referencing each context individually, the rule can then reference the context group.

Example: See a context groups example.

extract context key

A context key is not necessarily hard coded in your rule. For instance, it can be extracted from your data message (using tags or device identifier).

Here, the context key is generated with the concatenation of the value.streamId field and a string.
 {"ctx" : {"cat":[{"var" : "value.streamId"},"alertingzone"]}}
Here, the context key is extracted from the value.tags field.
"ctx": { "get": [{"filter": [{"var": "value.tags"},"zone"]},0]}

17.2.2. Geozone repository

17.2.2.1. Definition

The Geozone repository is a database that allows the user to save his geographical sites/zones of interest. The geozones are stored as polygons (array of geopoints coordinates in decimal degrees). Meta information like a description and tags can be stored with the geozone.

Format:
  • coordinate order for polygon definition : use longitude as the first coordinate and latitude as the second coordinate.

  • the polygons are closed linestrings. Closed LineStrings have at least four coordinate pairs and specify the same position as the first and last coordinates.

Example of polygon :

[[[1.780892, 48.091452], [2.301382, 48.000565], [2.281961, 47.509630], [1.252634, 47.729556], [1.780892, 48.091452]]]
17.2.2.2. Provisioning

The Live Objects API to manage geozone provisioning are described in the swagger documentation (Event processing - Geozone section) : https://liveobjects.orange-business.com/swagger-ui/index.html.

Example:

PUT liveobjects.orange-business.com/api/v0/eventprocessing/geozones/grand-orleans
{
  "description": "my geozone grand Orleans",
  "geometry": {
    "coordinates": [[
        [1.780892, 48.091452],
        [2.301382, 48.000565],
        [2.281961, 47.509630],
        [1.252634, 47.729556],
        [1.780892, 48.091452]
        ]],
    "type": "Polygon"
  },
  "tags": ["zone-nord"]
}
  • Once a geozone is provisioned, it is available in the user context. Hence, it can be referenced in event processing rules or in groups of context.

  • When a geozone is updated, the modifications are immediately taken into account by the contexts or rules referencing the geozone.

17.2.3. Rules and JsonLogic syntax

A rule is a function applied on a data message in order to detect any significant change in the data (exceeding threshold, state modification, change of location). The rules in Simple Event Processsing and State Processing are defined within Live Objects plateform with the JsonLogic syntax.

the JsonLogic log operator has been deactivated.

17.2.4. Additional operators

In addition to the existing JsonLogic operators (logic and boolean operators, numeric operators, string operators, array operators), Live Objects provides geographic operators (distance, inside, insideindex, closeto, closetoindex), context operator (ctx) and miscellaneous operators (get, currentstate).

Table 13. distance
Name

distance

Description

Geographical operator. Returns the distance in meters between two points, given their latitude and longitude in decimal degrees.

Parameters

lon1, lat1, lon2, lat2 in decimal degrees

Logic

{
  ">" :
    {
      "distance" : [
        { "var" : "location.lon"},
        {"var" : "location.lat"},
        2.296565,
        48.800206
      ]
    },
    6000
  ]
}

Data

Eiffel Tower

{
  "location":{
     "lon" : 2.2945,
     "lat" : 48.8584
  }
}

inside

Result

true

Table 14. ctx
Name

ctx

Description

Retrieve, from the context repository, one or several values using a key or an array of keys. Several ctx operators can be nested (group of contexts).

Parameters

key or array of keys

Context

In the following example, "freezingThreshold" and "liquidThreshold" must have been provisioned in the tenant context before being used.

PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/freezingThreshold
{
  "contextData": 0
}

PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/liquidThreshold
{
  "contextData": 100
}

Logic

{
  "if": [
    {"<": [
      {"var":"value.temp"},
      {"ctx": "freezingThreshold"}
    ]},
    "ice",
    {"<": [
      {"ctx": "freezingThreshold"},
      {"var":"value.temp"},
      {"ctx": "liquidThreshold"}
    ]},
    "liquid",
    "gas"
  ]
}

Pre-requisite

Data

{
  "value":{"temp":55}
}

Result

"liquid"

Table 15. currentstate
Name

currentstate

Description

Retrieve the current state of a device when applying a stateProcessing function. For state processing rules only. In the following example, current state can be "cold", "normal" or "hot".

The example following logic function is an hysteresis :

if current state is not hot, transition to hot if value.temp > 100

if current state is hot, transition to normal if value.temp < 80

if value.temp < 0 transition to cold

Logic

{"if" : [
  {"and": [
    { "!==": [
      { "currentstate": [] },
      "hot"
    ]},
    {"<": [
      80,
      {"var": "value.temp"},100
    ]}
  ]},
  "normal",
  {"<": [
    {"var":"value.temp"},
    0
  ]},
  "cold",
  {"<": [
    {"var":"value.temp"},
    80
  ]},
  "normal",
  "hot"
]}

Data

{
  "value":{"temp":20.0}
}

Result

"normal"

Table 16. get
Name

get

Description

Returns the element at the specified position in an array.

Parameters

array, index in the array

Context

In the following example, an array containing latitude and longitude values must have been provisioned in the tenant context :

PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/2geopoints
{
  "contextData": [48.800206, 2.296565, 48.800474, 2.295562]
}

Logic

{
  "distance": [
    {
      "get": [
        {"ctx": "2geopoints"}, <- lat1 in contextData value index 0
        0
      ]
    },
    {
      "get": [
        {"ctx": "2geopoints"}, <- lon1 in contextData value index 1
        1
      ]
    },
    {
      "get": [
        {"ctx": "2geopoints"}, <- lat2 in contextData value index 2
        2
      ]
    },
    {
      "get": [
        {"ctx": "2geopoints"}, <- lon2 in contextData value index 3
        3
      ]
    }
  ]
}

Data

 {}

Result

79 (distance between coordinates lat1,lon1 and lat2,lon2)

Table 17. inside
Name

inside

Description

Checks if a point defined by its latitude and longitude is inside a polygon (or at least one polygon if an array of polygons is provided as input parameter).

Parameters

longitude, latitude in decimal degrees for the point to be tested, polygon(s) defined by the coordinates of their vertices (lon, lat in decimal degrees).

Logic

{
  "inside": [
    {"var": "location.lon"},
    {"var": "location.lat"},
    [[
      [2.381121,48.627973],
      [2.129376,48.629499],
      [2.099351,48.768217],
      [2.116302,48.955198],
      [2.317994,48.927845],
      [2.455176,48.913357],
      [2.489472,48.841933],
      [2.392301,48.762871],
      [2.381121,48.627973]
    ]]
  ]
}

Data

{
  "location":{
    "lon":2.350350,
    "lat":48.854064
  }
}

inside

Result

true

Table 18. insideindex
Name

insideindex

Description

Checks if a point is inside an array of polygons. Returns the index of the first matching polygon. Returns -1 if no matching was found. This operator is usually in conjunction with the "get" operator which will return the matching polygon.

Parameters

longitude, latitude in decimal degrees for the point to be tested, array of polygons defined by the coordinates of their vertices (lon, lat in decimal degrees).

Context

In the example, an array containing latitude and longitude values must have been provisioned in the tenant context :

PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/zone-nord
{
  "contextData": ["zone-grandparis", "zone-grandorleans"]
}

PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/zone-grandparis
{
  "contextData": [[
    [2.381121, 48.627973],
    [2.129376, 48.629499],
    [2.099351, 48.768217],
    [2.116302, 48.955198],
    [2.317994, 48.927845],
    [2.455176, 48.913357],
    [2.489472, 48.841933],
    [2.392301, 48.762871],
    [2.381121, 48.627973]
  ]]
}

PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/zone-grandorleans
{
  "contextData": [[
    [1.780892, 48.091452],
    [2.301382, 48.000565],
    [2.281961, 47.509630],
    [1.252634, 47.729556],
    [1.780892, 48.091452]
  ]]
}

Logic

{
  "get": [
    {
      "ctx": {
        "get": [
          {
            "filter": [
              {"var": "tags"},
              "zone"
            ]
          },
          0
        ]
      }
    },
    {
      "insideindex": [
        {"var": "location.lon"},
        {"var": "location.lat"},
        {
          "ctx": {
            "ctx": {
              "get": [
                {
                  "filter": [
                    {"var": "tags"},
                    "zone"
                  ]
                },
                0
              ]
            }
          }
        }
      ]
    }
  ]
}

}

Data

{
  "location":{
    "lat" : 48.854064,
    "lon" : 2.350350
  },
  "tags" : [
    "otherTag2",
    "zone-nord",
    "otherTag1"
  ]
}

Result

"zone-grandparis"

Table 19. closeto
Name

closeto

Description

Checks if a circle is close to a polygon or at least one of the polygons (polygon array).

Parameters

longitude, latitude (in decimal degrees for the circle center), circle radius, polygon or array of polygons

Logic

{
  "closeto": [
    { "var": "location.lon" },
    { "var": "location.lat" },
    { "var": "location.accuracy" },
    [
      [[
        [1.780892,48.091452],
        [2.301382,48.000565],
        [2.281961,47.509630],
        [1.252634,47.729556],
        [1.780892,48.091452]
      ]],
      [[
        [2.281961,47.509630],
        [1.252634,47.729556]
      ]],
      [[
        [2.22412,48.85863],
        [2.25219,48.88143],
        [2.28404,48.8785],
        [2.26816,48.86721],
        [2.2588,48.84913],
        [2.22859,48.85004],
        [2.22412,48.85863]
      ]]
    ]
  ]
}

Data1 : circle center outside polygons, the circle does not intersect any polygon.

{
  "location":{
    "lon": 2.263849,
    "lat": 48.855983,
    "accuracy" : 100
  }
}

closeTo1

Result1

false

Data2 : circle center outside polygons, the circle intersects one polygon.

{
  "lon" : 2.263849,
  "lat" : 48.855983,
  "accuracy" : 200
}

closeTo2

Result2

true

Data3 : a point inside one of the polygons.

{
  "lon" : 2.260265350341797,
  "lat" : 48.85693640789798,
  "accuracy" : 0
}

closeTo3

Result3

true

Table 20. closetoindex
Name

closetoindex

Description

Checks if a circle is close to an array of polygons. Returns the index of the first matching polygon (first index in the array is 0). Returns -1 if no matching was found.

Parameters

longitude, latitude (in decimal degrees for the circle center), circle radius, array of polygons

Logic

{ "
  closetoindex" : [
    { "var" : "location.lon"},
    { "var" : "location.lat"},
    { "var" : "location.accuracy"} ,
    [
      [[
        [1.780892, 48.091452],
        [2.301382, 48.000565],
        [2.281961, 47.509630],
        [1.252634, 47.729556],
        [1.780892, 48.091452]
      ]],
      [[
        [2.224120, 48.858630],
        [2.252190, 48.881430],
        [2.284040, 48.878500],
        [2.268160, 48.867210],
        [2.258800, 48.849130],
        [2.228590, 48.850040],
        [2.224120, 48.858630]
      ]]
    ]
  ]
}

N.B.: first polygon in the array is the Orleans area; 2nd polygon is the Paris area.

Data

{
  "location":{
    "lon" : 2.263849,
    "lat" : 48.855983,
    "accuracy" : 500
  }
}

closeToIndex1

Result

1

Table 21. now_utc
Name

now_utc

Description

Returns the processing time as ISO 8601 string.

Similar to javaScript new Date().toISOString()

Parameters

none

Logic

{
   "<=":[
      0,
      {
         "get_utc_hours":[
            {
               "now_utc":[

               ]
            }
         ]
      },
      12
   ]
}

Data

 {}

Result

true if processing hour is between 0 and 12

Table 22. get_utc_hours
Name

get_utc_hours

Description

Returns the hour of the ISO 8601 provided parameter .

Similar to javaScript new Date(param).getUTCHours()

Parameters

ISO 8601 String

Logic

{\"get_utc_hours\" : [\"2018-02-15T13:01:37.290Z\"]}

Data

 {}

Result

13

Table 23. • get_utc_minutes
Name
  • get_utc_minutes

Description

Returns the minutes of the ISO 8601 provided parameter .

Similar to javaScript new Date(param).getUTCMinutes()

Parameters

ISO 8601 String

Logic

{\"get_utc_minutes\" : [\"2018-02-15T13:01:37.290Z\"]}

Data

 {}

Result

1

Table 24. • get_utc_day
Name
  • get_utc_day

Description

Returns the day of the week of the ISO 8601 provided parameter .

Similar to javaScript new Date(param).getUTCDay()

Parameters

ISO 8601 String

Logic

{\"get_utc_day\" : [\"2018-02-15T13:01:37.290Z\"]}

Data

 {}

Result

4

Table 25. • get_utc_date
Name
  • get_utc_date

Description

Returns the day of the month of the ISO 8601 provided parameter .

Similar to javaScript new Date(a).getUTCDate()

Parameters

ISO 8601 String

Logic

{\"get_utc_day\" : [\"2018-02-15T13:01:37.290Z\"]}

Data

 {}

Result

15

Table 26. • get_time
Name
  • get_time

Description

Returns epoch (milliseconds) of the ISO 8601 provided parameter .

Similar to javaScript new Date(a).getTime()

Parameters

ISO 8601 String

Logic

{\"get_time\" : [\"2018-01-15T13:00:37.290Z\"]}

Data

 {}

Result

1516021237290.0

17.2.5. Simple Event Processing

17.2.5.1. Concepts

Simple event processing (SEP) service is aimed at detecting notable single event from the flow of data messages.

Simple event processing combines a stateless boolean detection function (matching rule) with a frequency function (firing rule).

It generates fired events as output that your business application can consume to initiate downstream action(s) like alarming, execute a business process, etc.

Simple Event Processing service E2E overview

Interactive

17.2.5.2. Processing rules

You can set up Matching rules and Firing rules to define how data messages are processed by the SEP service and how fired events are triggered:

17.2.5.3. Matching rule

A matching rule is a simple or compound rule that will be applied on each data message to evaluate if a « match » occurs. A matching rule is evaluated as a boolean result. Matching rule supports numeric, string, logic and distance operators and is based on JsonLogic.

Matching context (containing data message and matching rule id, etc.) are processed by the firing rules associated to these matching rules.

17.2.5.4. Firing rule

A firing rule applies to the matches triggered by one or many matching rules and defines when fired events must be generated.

A firing rule specifies:

  • the list of matching rules associated to this firing rule – when these matching rules match, the firing rule is applied,

  • the frequency of firing: once, sleep and always,

  • optionally, a list of aggregation keys identifying fields to extract from the matching context to identify the firing context.  

The firing rule is applied as follow on each matching context:

  • the firing rule generates the firing context from the matching context, by extracting one or multiple fields defined with the aggregation keys,

  • the firing rule then applies the frequency parameter to optionally throttle the triggering of fired events belonging to the same firing context.  

If the frequency of the firing rule is defined as ONCE or SLEEP then firing guards are created in the system to prevent new generation of fired events for a given firing context. You can manage the firing guards, and for example, remove a firing guard to re-activate a firing rule for a specific firing context.

As an example, by setting the metadata.source field as aggregation key, if a fired event is generated for a device “A”, a firing guard will prevent new fired event for this device “A” and this firing rule. By the way, fired events could occur for devices “B”, “C”, etc…​ for this rule.

With SLEEP mode, a duration specifies the minimum time between two fired events. When the duration is elapsed, the firing guards is removed and new fired events could occur. This duration is computed for each element of the tuple composed of firing rule id + aggregation keys + value (firingRuleID:metadata.source:deviceId1 , firingRuleID:metadata.source:deviceId2, …)

Interactive

The sleepDuration is expressed in a iso8601-duration format.

17.2.5.5. Fired events consumption

Fired events are accessible with the MQTT API. Your business application must connect using MQTT application mode and subscribe to a FIFO. This FIFO should previously be filled with matchingFired events.

Example of a fired event data representation

This example shows a fired event object triggered by one matching rule and filtered by a firing rule (that will block any other event from occuring unless the guard is lifted). The matching rule check on all published messages if the device location have more than 6 m from the the coordinates (48.800206,2.296565) and the temperature published is more than 99°. The firing rule then trigger the event and filter all messages selected by the source field "metadata.source".

{
  "matchingContext": {
    "matchingRule": {
      "dataPredicate": "{\"and\":[{\">\":[{\"distance\":[{\"var\":\"location.lat\"},{\"var\":\"location.lon\"},48.800206,2.296565]},6]},{\">\":[{\"var\":\"value.temp\"},99]}]}",
      "name": "compound rule with numeric and distance operators Rule",
      "id": "d5f75f5a-4c43-4b12-81e0-0ddff0083c52",
      "enabled": true
    },
    "data": {
      "metadata": {
        "connector": "mqtt",
        "source": "urn:lo:nsid:mqtt:myTest",
        "transformation": {
          "published": {
            "location": {
              "lon": -122.431297,
              "lat": 37.773972
            }
          }
        },
        "group": {
          "path": "/",
          "id": "root"
        },
        "network": {
          "mqtt": {
            "clientId": "urn:lo:nsid:mqtt:myTest"
          }
        }
      },
      "streamId": "urn:lo:nsid:dongle:00-14-22-01-23-45!temperature",
      "extra": {},
      "location": {
        "lon": -122.431297,
        "lat": 37.773972
      },
      "model": "temperatureDevice_v0",
      "value": {
        "temp": 105
      },
      "timestamp": "2021-06-17T13:15:04.165Z",
      "tags": []
    },
    "tenantId": "5c0a6fb49a927971342aea06",
    "timestamp": "2021-06-17T13:15:04.185Z"
  },
  "tenantId": "5c0a6fb49a927971342aea06",
  "timestamp": "2021-06-17T13:15:04.276Z",
  "firingRule": {
    "name": "firing rule test",
    "matchingRuleIds": [
      "d5f75f5a-4c43-4b12-81e0-0ddff0083c52"
    ],
    "id": "04e30d59-82eb-4fb5-9243-6111d188b131",
    "aggregationKeys": [
      "metadata.source"
    ],
    "firingType": "ONCE",
    "enabled": true
  }
}
17.2.5.6. Examples

Here are some examples of usage of the simple event processing service.

Data message sent by a device with temperature set to 105 and location set at San Francisco (37.773972,-122.431297)

{
  "streamId":"urn:lo:nsid:dongle:00-14-22-01-23-45!temperature",
  "location":{
    "lat":37.773972,
    "lon":-122.431297
  },
  "model":"temperatureDevice_v0",
  "value":{
    "temp":105
  }
}

Matching rule: numeric (temperature higher than 99) and distance operator (distance between data message and Paris (48.800206, 2.296565) must be higher than 6km)

{
  "id": "d5f75f5a-4c43-4b12-81e0-0ddff0083c52",
  "name": "compound rule with numeric and distance operators Rule",
  "enabled": true,
  "dataPredicate": {
    "and": [
        {
            ">": [
            {
                "distance": [
                {
                "var": "location.lat"
                },
                {
                "var": "location.lon"
                },
                48.800206,
                2.296565
                ]
            },
            6000
            ]
        },
        {
        ">": [
           {
             "var": "value.temp"
           },
          99
        ]
      }
    ]
  }
}

Firing rule with frequency ONCE and aggregationKeys based on the source field :

{
    "name": "firing rule test",
    "enabled": true,
    "matchingRuleIds": ["d5f75f5a-4c43-4b12-81e0-0ddff0083c52 --> {matchingRuleId}"],
    "aggregationKeys":["metadata.source"],
    "firingType":"ONCE"
}

Fired event will be generated once for each source sending data with temperature higher than 99 and not located within a radius of 6km of Paris.

Example with other operators ">", "if", "in", "cat" :

{
  ">":[
    {
      "var":{
        "cat":[
          "value.", {
            "if" : [
              {"in": [{"var":"model"}, "v0"]},
              "temp",
              {"in": [{"var":"model"}, "v1"]},
              "temperature",
              "t"
            ]
          }
        ]
      }
    },
    100
  ]
}

This rule allows to specify the field to be compared to the value "100” based on the model of the data message.

If the model value is:

  • "v0", the comparison will be made with the field "value.temp”,

  • "v1", the comparison will be made with the field "value.temperature”,

  • else it will be made with the field "value.t”.

17.2.6. State Processing

17.2.6.1. Concepts

State processing (SP) service aims at detecting changes in "device state" computed from data messages.

A state can represent any result computed from Live Objects data messages : geo-zone ("paris-area", "london-area", ..), temperature status ("hot", "cold", ..), availability status ("ok" , "ko"). Each state is identified by a key retrieved from the user-defined json-path in the data message.

stateKeyPath examples : "streamId", "metadata.source"

A state is computed by applying a state function to a data Message. A notification is sent by Live Objects each time a state value change. State processing differs from event processing as it provides stateful rules which is useful for use cases more complex than normal/alert status. State processing can be seen as a basic state machine where transitions between states are managed by the state function result and events are transition notifications.

17.2.6.2. State Processing rules

You can set up StateProcessing rules to define how data messages are processed by the SP service.

A StateProcessing rule applies to all new data messages.

Table 27. StateProcessing rule
field name required ? description

enabled

required

Defines if the rule should be enabled and applied to new data message.

filterPredicate

optional

Filters data on which the state processing logic should be applied. This boolean function is described in JsonLogic syntax.
If no filter predicate is specified, state function is applied to every data message.

stateKeyPath

required

A json-path that will be used to retrieve the state key form the triggering data message.
Example: In order to associate a state with a device status and depending on your needs, you can use streamId or metadata.source as stateKey path.

stateFunction

required

This is the core of the state processing logic. This function takes as input a data message and computes a state associated whith the state key.
The State function is written in JsonLogic syntax and can return any primitive value : String, Number, Boolean.

17.2.6.3. State change events

State change events are accessible with the MQTT API. Your business application must connect using MQTT application mode and subscribe to a FIFO. This FIFO should previously be filled with stateChange events.

17.2.6.4. State processing initialization

When a state is computed for the first time, it generates a state change event with previous state equals null.

17.2.6.5. Examples

Here are some examples of usage of the state processing.

Temperature monitoring of a device sensor, with 3 temperature ranges.

Temperature State processing logic:

  • if temperature is below 0 degree Celsius, sensor state is cold.

  • if temperature is between 0 and 100 degrees Celsius sensor state is normal.

  • if temperature is higher than 100 degrees Celsius sensor state is hot.

The sensor is identified by the streamId field within the data message.

{
  "name": "temperature state rule",
  "enabled": true,
  "stateKeyPath": "streamId",
  "stateFunction": {
    "if": [
      {"<": [
        {"var": "value.temp"},
        0
      ]},
      "cold",
      {"<=": [
        {"var": "value.temp"},
        100
      ]},
      "normal",
      "hot"
    ]
  }
}

We assume that the current state of the sensor is "normal".

The following data message will generate a state change event from "normal" to "hot" for state key : "urn:lo:nsid:mqtt:myTest".

{
  "streamId":"urn:lo:nsid:dongle:00-14-22-01-23-45!temperature",
  "location":{
    "lat":37.773972,
    "lon":-122.431297
  },
  "model":"temperatureDevice_v0",
  "value":{
    "temp":200
  }
}

State change event :

{
  "stateProcessingRuleId": "75c47213-b7fb-4fd9-8c4a-9d2209236a60",
  "data": {
    "metadata": {
      "connector": "mqtt",
      "source": "urn:lo:nsid:mqtt:myTest",
      "transformation": {
        "published": {
          "location": {
            "lon": -122.431297,
            "lat": 37.773972
          }
        }
      },
      "group": {
        "path": "/",
        "id": "root"
      },
      "network": {
        "mqtt": {
          "clientId": "urn:lo:nsid:mqtt:myTest"
        }
      }
    },
    "streamId": "urn:lo:nsid:dongle:00-14-22-01-23-45!temperature",
    "extra": {},
    "location": {
      "lon": -122.431297,
      "lat": 37.773972
    },
    "model": "temperatureDevice_v0",
    "value": {
      "temp": 200
    },
    "timestamp": "2021-06-17T12:30:16.659Z",
    "tags": []
  },
  "tenantId": "5c0a6fb49a927971342aea06",
  "newState": "hot",
  "previousState": "normal",
  "timestamp": "2021-06-17T12:30:16.708Z",
  "stateProcessingRule": {
    "stateKeyPath": "urn:lo:nsid:dongle:00-14-22-01-23-45!temperature",
    "name": "temperature state rule",
    "stateFunction": "{\"if\":[{\"<\":[{\"var\":\"value.temp\"},0]},\"cold\",{\"<\":[{\"var\":\"value.temp\"},100]},\"normal\",\"hot\"]}",
    "id": "75c47213-b7fb-4fd9-8c4a-9d2209236a60",
    "enabled": true,
    "filterPredicate": "null"
  }
}

17.2.7. Activity Processing

17.2.7.1. Concepts

Activity processing (AP) service aims at detecting devices that have no activity.

All of the following 'activities' are monitored :

  • 'connected' event sent by the device

  • new data sent with the deviceId as 'metadata.source'

  • command response from this device

  • setParam response from this device

17.2.7.2. Activity rules

You can set up Activity rules to define how devices activity should be monitored.

You can target a list of deviceIds or a list of groups. All devices of these groups will be targeted. You can target a group with its path, including or not the subPath.

If a device is targeted by several rules, then several activity events can be thrown for this device.

Table 28. Activity rule
field name required ? description

enabled

required

Defines if the rule should be activated or not.

name

required

Name of the rule that can be used to ease rule management, must be unique and not empty.

silentPolicy

required

Define the duration of device inactivity before throwing an event. This duration will be reused when the device will be active once again.
You can also define a repeat interval (optional) : the 'silent' event will be re-thrown at this interval as long as the device remains silent.
All the duration are defined using ISO 8601, e.g. 'P1D' for 1 day, 'PT12H' for 12 hours, 'P2DT3H30M' for 2 days 3 hours 30 minutes. Please note that any duration below 10 minutes will be handled by the platform as a 10 minutes delay (this goes for both inactivity delay and repeat interval)

targets

required

List of deviceIds and/or devices groups that targeted by the rule. At least 1 deviceId or 1 group must be set.
Groups are targeted by their path (e.g. '/europe/france'), and an additional marker to specify if all subpath groups must be targeted.
If a new device is added to or removed from a targeted group, it will be taken into account.

tags

optional

A list of tags can be set : they will be recorded in all events triggered by this rule. This can ease event search and management.

When an activityRule is updated, all activity states linked to this rule are reset to a specific 'UNKNOWN' state.

17.2.7.3. Activity States

An activity state is unique for a couple 'activity rule id + device id', it holds :

  • the state 'ACTIVE', 'SILENT' or 'UNKNOWN' of the device for this rule. As a device can be targeted by several rules with different silent duration, at a specific moment, 1 device can have several activity states, with different states. 'UNKNOWN' is specific to the initial state after activity rule creation or update.

  • the last activity timestamp of the device.

  • the timestamp of the next alarm that will be sent if there is no device activity until then. It can be triggered by the silent duration or repeatInterval duration depending on the current state (respectively ACTIVE or SILENT).

  • the number of times a reminder has been sent for the current state.

17.2.7.4. Activity Events

Activity events are accessible with the MQTT API. Your business application must connect using MQTT application mode and subscribe to a FIFO. This FIFO should previously be filled with deviceActivity events.

17.2.7.5. Example

Here is one example of usage of the activity processing.

ActivityRule targeting the group path '/france/lyon' an all its sub path. The silent trigger is 1 day and the repeat alarm interval is 12 hours.

{
  "name": "devices in Lyon",
  "enabled": true,
  "silentPolicy": {
    "duration" : "P1D",
    "repeatInterval" : "PT12H"
  },
  "targets": {
    "groupPaths" : [
      {
        "path" : "/france/lyon",
        "includeSubPath" : true
      }
    ]
  }
}

If the device does not connect nor send any data for 1 day, then the following event will be sent:

{
  "deviceId": "urn:lo:nsid:dongle:00-14-22-01-23-45",
  "deviceAdditionalInfo": {
    "deviceName": "myDongle001",
    "groupPath": "/france/lyon"
  },
  "state":"SILENT",
  "numberOfAlarmReminders": 0,
  "timestamp": "2018-04-24T08:29:49.029Z",
  "activityRule": {
    "id": "d16b4319-a486-4cb8-a10e-b4a452cda4be",
    "name": "devices in Lyon",
    "enabled": true,
    "silentPolicy": {
      "duration" : "P1D",
      "repeatInterval" : "PT12H"
    },
    "targets": {
      "groupPaths" : [
        {
          "path" : "/france/lyon",
          "includeSubPath" : true
        }
      ]
    }
  }
}

12 hours later, if the device is still silent, the event will be sent again with 'numberOfAlarmReminders' incremented by 1:

{
  "deviceId": "urn:lo:nsid:dongle:00-14-22-01-23-45",
  "deviceAdditionalInfo": {
    "deviceName": "myDongle001",
    "groupPath": "/france/lyon"
  },
  "state":"SILENT",
  "numberOfAlarmReminders": 1,
  "timestamp": "2018-04-24T20:29:49.029Z",
  "activityRule": {
    "id": "d16b4319-a486-4cb8-a10e-b4a452cda4be",
    "name": "devices in Lyon",
    "enabled": true,
    "silentPolicy": {
      "duration" : "P1D",
      "repeatInterval" : "PT12H"
    },
    "targets": {
      "groupPaths" : [
        {
          "path" : "/france/lyon",
          "includeSubPath" : true
        }
      ]
    }
  }
}

17.3. Notifications

When an alarm is raised, a notification can be sent to one or several recipients, using email or sms. An action policy has to be provisioned to define :

  • triggers: i.e. which alarms to route. One trigger must be defined in the action policy.

  • actions : i.e. which channel (Ex : email, sms) will be used to route the messages and which recipients for the alarms.

17.3.1. Action policy

Events related to the alarming on device activity/state change/event processing can be notified by email or sms. The notification triggering and actions are defined in an action policy, provisioned in Live Objects.

17.3.1.1. Provisioning

To create a new action policy linked with an event rule :

Endpoint:

POST /api/v1/event2action/actionPolicies
An action policy has the following top level data representation (in this example, an event linked to state change event) :
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e"
    "name": "name-aea80c1d-5777-4e20-822c-5e6871f428e5",
    "enabled": true,
    "triggers": {
        "stateChange": {
            "version": 1,
            "filter": {
                "ruleIds": ["state-change-event-3422c5ac-de95-4727-855a-39d43902b7b3"]
            }
       }
    },
    "actions:" {
        "emails": [{
           "to": ["notification@orange.com"],
           "cc": ["cc@orange.com"],
           "cci": ["cci@orange.com"],
           "subjectTemplate": "State change for {{stateKey}}",
           "contentTemplate": "{{stateKey}} change from state {{previousState}} to state {{newState}} at {{timestamp}}"
        }],
        "sms": [{
            "destinationPhoneNumbers": ["+33601234567"],
            "contentTemplate": "{{stateKey}} new state {{newState}} at {{timestamp}}"
        }],
        "httpPush": [{
            "webhookUrl": "https://hooks.myservice.com/services/SOMEWEBHOOKREFERENCE",
            "headers": {"authorization": ["Bearer 00000000-0000-0000-0000-000000000000"]},
            "retryOnFailure": true,
            "content": "{\"text\": \"Devices {{deviceIds}} activity change triggered by activity rule: {{ruleIds}} : at {{timestamp}}\"}"
        }],
        "fifoPublish": [{
            "fifoName": "myFifo"
        }],
        "azureEventHubs":[{
            "eventHubsNamespace": "myEventHubsNamespace",
            "eventHubName":"myEventHubName",
            "sharedAccessKeyName":"mySharedAccessKeyName",
            "sharedAccessKey":"mySharedAccessKey",
            "content":"{\"text\": \"Devices {{deviceIds}} activity change triggered by activity rule: {{ruleIds}} : at {{timestamp}}\"}",
            "retryOnFailure":false
        }]
      }
    }
}

The field id is auto generated by Live Objects and added in the POST response object.

field name is required description

name

optional

Defines a user friendly name for the action policy

enable

required

Enables or disables the action policy

triggers

required

Defines the type of trigger that will start an action. It can be one of the following :

  • deviceActivity

  • matchingFired

  • stateChange

Note: triggers object should have exactly one trigger defined.

actions

required

Object that defines the action that will be started upon a trigger activation
Note: actions object should not be empty. At least one action should be defined.

actions.emails

optional

A collection of Email actions (see Email notification section)

actions.sms

optional

A collection of SMS actions (see SMS notification section)

actions.httpPush

optional

A collection of HTTP push actions (see HTTP Push notification section)

actions.fifoPublish

optional

A collection of FIFO publish actions (see FIFO notification section)

actions.azureEventHubs

optional

A collection of Azure Event Hubs actions (see Azure Event Hubs notification section)

To retrieve your action policy:

Endpoint:

GET /api/v1/event2action/actionPolicies/{policyId}

17.3.2. Triggers

There are three kinds of rule event based triggers. You can either trigger an action on a fired event, a state changed event or a device activity event. This allows you to write complex matching, filtering, state or activity processing rules on your data and route chosen data to the desired actions.

An event trigger is represented by the id of the rule that will emit the corresponding event. You can specify multiple rule identifiers as trigger for one action policy.

17.3.2.1. Format
Table 29. Triggers
Type Triggered Filtering criteria

deviceActivity

on device activity event (example : activity state transition from "SILENT" to "ACTIVE")

"deviceIds": a list of device identifiers (as String) to be monitored,
"ruleIds": a list of activity rule identifiers (as String)

matchingFired

on simple event processing firing event

"ruleIds": a list of firing rule identifiers (as String)

stateChange

on state change event

"ruleIds": a list of state processing rule identifiers (as String)

When several criterias are present in a filter, they are combined with a AND boolean logic. OR operator is applied between each elements inside filter’s list.
17.3.2.2. Examples

Activity change

Example of action policy with a trigger on device activity change
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e",
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
        "deviceActivity": {
            "version": 1,
            "filter": {
                "deviceIds" :["device_identifier"],
                "ruleIds": ["activity-change-event-e64528bd-490e-405f-9c7f-0b80eda62ce5"]
            }
        }
    },
    "actions": {
        "emails": [{
            "to": ["to@orange.com"],
            "contentTemplate": "Event for Rule {{activityRule.name}} and device {{deviceAdditionalInfo.deviceName}}"
        }],
        "sms": [],
        "httpPush": [],
        "fifoPublish": []
    }
}
Example of event message sent (by email, http push, fifo, sms) by the action policy when it is triggered
{
    "type": "deviceActivity",
    "version": 1,
    "deviceId": "device_identifier",
    "deviceAdditionalInfo": {
        "deviceName": "deviceName",
        "groupPath": "groupPath"
    },
    "activityRule": {
        "id": "activity-change-event-e64528bd-490e-405f-9c7f-0b80eda62ce5",
        "name": "name"
    },
    "state": "SILENT",
    "timestamp": "2019-08-26T00:00:00.000Z",
    "numberOfAlarmReminders": 0
}

State change

Here is an example of an action policy with a trigger on a state change rule.
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e",
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
        "stateChange": {
          "version": 1,
          "filter": {
            "ruleIds": ["state-change-event-6a9a1b48-72da-4405-a65e-7e482abbe826"]
         }
    },
    "actions": {
        ...
    }
}
Example of event message sent by the action policy when it is triggered
{
    "type": "stateChange",
    "version": 1
    "tenantId": "it-2f2ab8e7-bd58-4423-adc1-efcba36faaa8",
    "stateKey": "stateKey",
    "previousState": "previousState",
    "newState": "newState",
    "timestamp": "2019-09-02T14:08:04.337Z",
    "stateProcessingRuleId": "state-change-event-6a9a1b48-72da-4405-a65e-7e482abbe826",
    "data": {
        "streamId": "streamId",
        "timestamp": "2019-09-02T14:08:04.334Z",
        "value": {
            "string": "input",
            "integer": 0
        },
        "type": "dataMessage",
        "version": 1
    }
}

Fired event (event processing)

Example of action policy
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e",
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
        "matchingFired": {
          "version": 1,
          "filter": {
            "ruleIds": [
              "firing-event-961a4bb5-c244-4df8-88cd-80c4e03c42b9", "10000000-0000-0000-0000-000000000001"
            ]
         }
    },
    "actions": {
        ...
    }
}
Example of event message sent by the action policy when it is triggered
{
    "type": "matchingFired",
    "version": 1,
    "tenantId": "it-cbe67009-7653-4c5e-9762-58b2afe0240d",
    "timestamp": "2019-09-02T13:55:17.433Z",
    "firingRule": {
        "id": "firing-event-961a4bb5-c244-4df8-88cd-80c4e03c42b9"
    },
    "matchingContext": {
        "tenantId": "it-cbe67009-7653-4c5e-9762-58b2afe0240d",
        "timestamp": "2019-09-02T13:55:17.433Z",
        "matchingRule": {
            "id": "cc76a37a-1b18-45f9-8356-7733d9ccbc3b"
        },
        "data": {
            "streamId": "streamId",
            "timestamp": "2019-09-02T13:55:17.426Z",
            "value": {
                "string": "debug",
                "integer": 100
            },
            "type": "dataMessage",
            "version": 1
        }
    }

}

17.3.3. Actions

An action, within an action policy, will define what to do upon trigger activation. An action is always passed the data message or the event that triggered it as datacontext for templating purpose or cherry picking a particular field within that data. Some actions give you the ability to template their output. The templating language used is Mustache. You can use fields of your triggering data (event or message) by leveraging the mustache variable mechanism.

17.3.3.1. Email notification

This action is self explanatory and serve the purpose of sending email to one or multiple recipients when a trigger is activated.

Representation of an email action
{
    "to": [] of String,
    "cc": [] of String,
    "cci": [] of String,
    "subjectTemplate": String,
    "contentTemplate": String
}

to

A List of String each representing a valid email

cc

A List of String each representing a valid email

cci

A List of String each representing a valid email

subjectTemplate

A string representing a Mustache template. This will be use to render the email subject.

contentTemplate

A string representing a Mustache template. This will to render the email content.

Example of an action policy sending an email on a state change event
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e",
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
        "stateChange": {
            "filter": {
                "ruleIds": ["22222222-2222-2222-2222-222222222222"]
            },
            "version": 1
        }
    },
    "actions":
    {
        "emails": [{
            "to": ["notification@orange.com"],
            "cc": ["cc@orange.com"],
            "cci": ["cci@orange.com"],
            "subjectTemplate": "State change for {{stateKey}}",
            "contentTemplate": "{{stateKey}} change from state {{previousState}} to state {{newState}} at {{timestamp}}"
    }
}

In this example, the fields stateKey, previousState, newState, timestamp are referencing the event message which generates the notification. The event message is available in the data context of the notification process.

17.3.3.2. SMS notification

This action is self explanatory and serve the purpose of sending sms to one or multiple recipients (MSISDNs) when a trigger is activated.

Representation of an SMS action
{
    "destinationPhoneNumbers": [] of String,
    "contentTemplate": String
}

destinationPhoneNumbers

a collection of string representing each a recipient msisdn

contentTemplate

A string representing a Mustache template. It will be rendered as the sms content.

Example of an action policy sending an sms on a fired event
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e",
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
        "matchingFired": {
            "filter": {
                "ruleIds": ["22222222-2222-2222-2222-222222222222"]
            },
            "version": 1
        }
    },
    "actions":
    {
        "sms": [{
                "destinationPhoneNumbers": ["+33123456789"],
                "contentTemplate": "Event fired at {{timestamp}} with value : {{value}}"
            }]
    }
}
17.3.3.3. HTTP Push notification

This action is self explanatory and serve the purpose of sending a message to a webhook server when a trigger is activated.

Representation of an HTTP Push action
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e",
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
        "deviceActivity": {
            "filter": {
                "deviceIds": ["urn:lo:nsid:sensor:temp001"],
                "ruleIds": ["22222222-2222-2222-2222-222222222222"]
            },
            "version": 1
        }
    },
    "actions": {
        "httpPush": [{
            "webhookUrl": "https://hooks.myservice.com/services/SOMEWEBHOOKREFERENCE",
            "headers": {"authorization": ["Bearer 00000000-0000-0000-0000-000000000000"]},
            "retryOnFailure": true,
            "content": "{\"text\": \"Devices {{deviceIds}} activity change triggered by activity rule: {{ruleIds}} : at {{timestamp}}\"}"
        }]
    }
}
17.3.3.4. FIFO notification

This action is self explanatory and serve the purpose of sending a message to a FIFO when a trigger is activated.

Representation of sending an event message to a FIFO
{
    "id": "6c95837b-251d-41d8-95f1-42facdf8e71e",
    "name": "some_user_friendly_name",
    "enabled": true,
    "triggers": {
       "deviceStatus": {
          "version": 1,
          "filter": {
             "connectors": ["mqtt"],
             "groupPaths": [{"path": "/lyon", "includeSubPath": true}]
          }
       }
    },
    "actions": {
        "fifoPublish": [{
            "fifoName": "myFifo"
        }]
    }
}
17.3.3.5. Azure Event Hubs notification

This action is self explanatory and serve the purpose of sending a message to an Azure Event Hub instance when a trigger is activated.

Representation of sending an event message to an Azure Event Hub
{
   "name": "some_user_friendly_name",
   "enabled": true,
   "triggers": {
      "dataMessage": {
         "version": 1
      }
   },
   "actions": {
      "azureEventHubs": [
         {
            "eventHubsNamespace": "myEventHubsNamespace",
            "eventHubName": "myEventHubName",
            "sharedAccessKeyName": "mySharedAccessKeyName",
            "sharedAccessKey": "mySharedAccessKey",
            "content": "{\"text\": \"new message sent by device {{metadata.source}} at {{timestamp}}\"}",
            "retryOnFailure": false
         }
      ]
   }
}
17.3.3.6. Datacontexts for templating

Actions template can have 3 kinds of datacontexts :

These are used as the root object of the mustache templating engine.

17.4. Alarms and notifications examples

17.4.1. Use case 1: Motion detection during the night

17.4.1.1. Description

We assume that in a factory, several motion sensors are installed in specific areas where usually, there is no activity during the night.
A new detection can be suspicious and a guard must check the place.
The motion sensor publishes a Data message in Live Objects using MQTT protocol each time there is detection with a minimum of 10 sec interval between two detections.
The night time is from 20h to 06h (24h UTC time).

17.4.1.2. Live Objects features

For this use case, we will use:

  • Alarming: a Simple Event Processing rule associated with a Firing rule

  • Notifications: Triggers & Actions with a SMS notification

Step 1: identifying the Data message format

The Data message sent by the device follows this format:

Data message published by device
{
   "location": {
      "provider": "gps",
      "lon": 2.99616,
      "lat": 50.21142
   },
   "model": "demoDevGuide",
   "value": {
      "motionSensorDetection": 1,
       "type":"alert",
       "typeId":4,
       "version": "1.2.4"
   },
   "timestamp": "2019-09-06T08:58:10.953Z",
   "tags": [
      "last_version","areaSouth"
   ]
}

Details about Data message format: see Data model section

The Data message after internal Live Objects enrichment follows this format:

Data message after enrichment by Live Objects
{
  "metadata": {
    "connector": "mqtt",
    "source": "urn:lo:nsid:mqtt:myTest",
    "transformation": {
      "published": {
        "location": {
          "provider": "gps",
          "lon": 2.99616,
          "lat": 50.21142
        }
      }
    },
    "group": {
      "path": "/",
      "id": "root"
    },
    "network": {
      "mqtt": {
        "clientId": "urn:lo:nsid:mqtt:myTest"
      }
    }
  },
  "streamId": "urn:lo:nsid:mqtt:myTest",
  "created": "2021-06-17T14:21:34.036Z",
  "extra": {},
  "location": {
    "provider": "gps",
    "alt": null,
    "accuracy": null,
    "lon": 2.99616,
    "lat": 50.21142
  },
  "model": "demoDevGuide",
  "id": "60cb5a6e2b9f5a61388d3fb7",
  "value": {
    "motionSensorDetection": 1,
    "typeId": 4,
    "type": "alert",
    "version": "1.2.4"
  },
  "timestamp": "2021-06-17T14:21:34.026Z",
  "tags": [
    "last_version",
    "areaSouth"
  ]
}

Details about Live Objects enricher: see Data enrichment process

Step 2: set the matching rule

The matching rule is using the additional “get_utc_hours” jsonLogic operator to extract the hour value of the timestamp.

Matching rule
{
   "name":"matching rule with time condition",
   "enabled":true,
   "dataPredicate":{
      "and":[
         {
            "==":[
               {
                  "var":"value.motionSensorDetection"
               },
               1
            ]
         },
         {
            "or":[
               {
                  ">=":[
                     {
                        "get_utc_hours":[
                           {
                              "var":"timestamp"
                           }
                        ]
                     },
                     20
                  ]
               },
               {
                  "<":[
                     {
                        "get_utc_hours":[
                           {
                              "var":"timestamp"
                           }
                        ]
                     },
                     6
                  ]
               }
            ]
         }
      ]
   }
}

Details about additional operators: see Additional operators

Step 3: set the firing rule

As the minimum interval is 10 sec between two data messages in case of motion detection, to avoid SMS spam, we define here a firing rule with SLEEP mode in order to repeat the notification with a larger time interval. Here the sleep duration is set to 2 minutes.

Firing rule
{
   "name":"firing rule with sleep mode to avoid flooding",
   "enabled":true,
   "matchingRuleIds":[
      "my_matching_rule_id"
   ],
   "aggregationKeys":["metadata.source"],
   "firingType":"SLEEP",
   "sleepDuration":"PT2M"
}

Step 4: set the notification using triggers and actions policy

Here you can find an action policy with the trigger type "matchingFired" linked with the ruleId = the firingRuleId of the rule created in the previous step.

Action policy
{
   "name":"notification by sms for a motion detection during the night",
   "enabled":true,
   "triggers":{
      "matchingFired":{
         "version":1,
         "filter":{
            "ruleIds":[
               "my_firing_rule_id"
            ]
         }
      }
   },
   "actions":{
      "sms":[
         {
            "destinationPhoneNumbers":[
               "+33612345667"
            ],
            "contentTemplate":"Motion detection! Sensor: {{matchingContext.data.metadata.network.mqtt.clientId}} at {{matchingContext.data.timestamp}}"
         }
      ]
   }
}

Details about Triggers and actions feature: see Notification

Test it! With this data message from the device: detection at 23:58 UTC:

Data message matching the conditions
{
   "location": {
      "provider": "gps",
      "lon": 2.99616,
      "lat": 50.21142
   },
   "model": "demoDevGuide",
   "value": {
      "motionSensorDetection": 1,
       "type":"alert",
       "typeId":4,
       "version": "1.2.4"
   },
   "timestamp": "2019-09-06T23:58:10.953Z",
   "tags": [
      "last_version","areaSouth"
   ]
}

A SMS is sent:

"Motion detection! Sensor: 1234qfre at 2019-09-06T23:58:10.953Z"

17.4.2. Use case 2: geozone supervision of a tracker

Pre-requisites:

  • the event processing feature is enabled for the tenant.

  • the tenant has a valid Live Objects API key.

17.4.2.1. Use case description: tracking of package between the shipment zone, transportation zone and delivery zone.

The REST requests for this example are available here and can be run in Postman.

A truck leaves San Francisco with its shipment. A tracker is embedded in the shipment. The truck may take Highway 101 or Route 5 to Los Angeles. A state change event will be sent when the tracker changes of zone.

  • Shipment zone (red) = San Francisco GPS polygon (lat, lon): (38.358596, -123.019952) (38.306889, -120.954523) (37.124990, -121.789484)

  • Delivery zone (green) = LA GPS polygon: (34.238622, -118.909873) (34.346562, -117.747086) (33.620728, -117.551111) (33.533648, -118.269687)

  • Transportation zone 1 (yellow) = 101 Highway: (37.561997, -122.05261237) (34.059617, -118.154639) (34.102708, -119.203276) (37.440666, -122.641996)

  • Transportation zone 2 (blue) = Route 5: (37.8705177, -121.3220217) (34.309766, -118.027739) (33.679366, -118.377685) (37.714244, -121.662597)

17.4.2.2. Geographical zones

lom_ep_stateprocessing1

17.4.2.3. Steps

Interactive

Step1: Geozone provisioning

First you need to create the 4 geozones you would like to monitor.

  • Make sure that you enter the coordinates with the longitude first (lon, lat).

  • The polygon must be closed (last point=first point).

PUT liveobjects.orange-business.com/api/v0/eventprocessing/geozones/san-francisco

In the request body:

{
  "description": "San Francisco zone",
  "geometry": {
    "coordinates": [[
        [-123.019952, 38.358596],[-120.954523, 38.306889],
        [-121.789484, 37.124990],[-123.019952, 38.358596]
    ]],
    "type": "Polygon"
  },
  "tags": [
    "SF-area", "shipment"
  ]
}
PUT liveobjects.orange-business.com/api/v0/eventprocessing/geozones/los-angeles
{
  "description": "Los Angeles zone",
  "geometry": {
    "coordinates": [[
      [-118.909873, 34.238622],[-117.747086, 34.346562],
      [-117.551111, 33.620728],[-118.269687, 33.533648],[-118.909873, 34.238622]
    ]],
    "type": "Polygon"
  },
  "tags": [
    "LA-area", "delivery"
  ]
}
PUT liveobjects.orange-business.com/api/v0/eventprocessing/geozones/transportation1
{
  "description": "Transportation zone Highway 101",
  "geometry": {
    "coordinates": [[
      [-122.05261237, 37.561997],[-118.154639, 34.059617],
      [-119.203276, 34.102708],[-122.641996, 37.440666],[-122.05261237, 37.561997]
    ]],
    "type": "Polygon"
  },
  "tags": [
    "transportation"
  ]
}
PUT liveobjects.orange-business.com/api/v0/eventprocessing/geozones/transportation2
{
  "description": "Transportation zone Route 5",
  "geometry": {
    "coordinates": [[
      [-121.3220217, 37.8705177],[-118.027739, 34.309766],
      [-118.377685, 33.679366],[-121.662597, 37.714244],[-121.3220217, 37.8705177]
    ]],
    "type": "Polygon"
  },
  "tags": [
    "transportation"
  ]
}

Once the geozones are provisioned, they are available in your user context and can be referenced in your rules.

Step2: Context provisioning
  • There are 2 transportation zones. You can group them into a single transportation context which will be used in your rule.

  • If you want to apply the rule only to a specific tracking device (the one present in the truck), you can create a device-group context containing the device identifier.

  • You can use the geozones san-francisco and los-angeles in your rule definition. But you probably do not want to reference directly the city names in the rule in order to be able to change the shipment and delivery zones without modifying the rule. Hence, you create an indirection in the context (san-francisco→shipment; los-angeles→delivery).

    PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/transportation
    {
      "contextData": ["transportation1","transportation2"],
      "tags": [
        "transportation","zone","california"
      ]
    }
    PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/device-group
    {
      "contextData": ["urn:lo:nsid:lora:0020B20000000101"],
      "tags": [
        "device","truck"
      ]
    }
    PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/shipment
    {
      "contextData": "san-francisco",
      "tags": [
        "geozone"
      ]
    }
    PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/delivery
    {
      "contextData": "los-angeles",
      "tags": [
        "geozone"
      ]
    }
Step3: State processing rule provisioning
  • This example is aimed at detecting a change in the device state, so you have to create a state processing rule which will be applied only to the monitored device (in the truck).

  • An event will be raised when the truck moves from one zone to the next one (shipment→transportation or transportation→delivery).

Before provisioning the state processing rule, it is useful to run the state processing function on a test data message.

POST liveobjects.orange-business.com/api/v0/eventprocessing/stateprocessing-rule/test
{
  "currentState": {},
  "data": {
    "metadata": {
      "connector": "http",
      "source": "urn:lo:nsid:lora:0020B20000000101"
   },
   "streamId": "urn:lo:nsid:lora:0020B20000000101",
    "location": {
      "provider": "lora",
      "accuracy": 10,
      "lon": -122.169846,
      "lat": 37.602902
   },
   "model": "lora_v0",
   "value": {
      "payload": "ae2109000cf3"
   }
  },
  "stateProcessingFunction": {
    "if": [
      {
        "inside": [
          {
            "var": "location.lon"
          },
          {
            "var": "location.lat"
          },
          {
            "ctx": {"ctx":"shipment"}
          }
        ]
      },
      "shipment_zone",
      {
        "inside": [
          {
            "var": "location.lon"
          },
          {
            "var": "location.lat"
          },
          {
            "ctx": {"ctx":["transportation"]}
          }
        ]
      },
      "transportation_zone",
      {
        "inside": [
          {
            "var": "location.lon"
          },
          {
            "var": "location.lat"
          },
          {
            "ctx": {"ctx":"delivery"}
          }
        ]
      },
      "delivery_zone",
      "unknown_zone"
    ]
  }
}

Response:

{
    "stateFunctionValid": true,
    "dataValid": true,
    "stateFunctionResult": "shipment_zone"
}

Now that the state function is tested, you can provision the state processing rule.

Geo tracking state processing rule:

POST liveobjects.orange-business.com/api/v0/eventprocessing/stateprocessing-rule
{
  "name": "geo tracking", (1)
  "enabled": true,
  "stateFunction": { (2)
    "if": [
      {
        "inside": [
          {"var": "location.lon"},
          {"var": "location.lat"},
          {"ctx": {"ctx":"shipment"}}
        ]
      },
      "shipment_zone",
      {
        "inside": [
          {"var": "location.lon"},
          {"var": "location.lat"},
          {"ctx": {"ctx":["transportation"]}}
        ]
      },
      "transportation_zone",
      {
        "inside": [
          {"var": "location.lon"},
          {"var": "location.lat"},
          {"ctx": {"ctx":"delivery"}}
        ]
      },
      "delivery_zone",
      "unknown_zone"
    ]
  },
  "filterPredicate": {
    "in": [ (3)
      {"var": "metadata.source"},
      {"ctx": "device-group"}
    ]
  },
  "stateKeyPath": "metadata.source" (4)
}
1 state rule name
2 state processing function in Jsonlogic format
3 the rule will be used only on the devices defined in the device-group
4 the current state will be stored using the "metadata.source" field.
Step4: Data messages

You can simulate, with the Live Objects REST API, the data messages sent by the tracker.

Data Message 1:
POST liveobjects.orange-business.com/api/v0/data/streams/urn:lo:nsid:lora:0020B20000000101
{
  "metadata": {
    "connector": "http",
    "source": "urn:lo:nsid:lora:0020B20000000101"
  },
  "location": {
    "provider": "lora",
    "accuracy": 10,
    "lon": -122.169846,
    "lat": 37.602902
  },
  "model": "lora_v0",
  "value": {
    "payload": "ae2109000cf3"
  },
  "timestamp": "2017-07-26T08:32:44.034Z",
  "tags": [
    "San Francisco", "Tracker"
  ]
}

The first data message in the SF area will generate an event with no previous state.

{
  "stateProcessingRuleId": "78063026-51e2-4c3e-aaf5-99efc4ee0255",
  "data": {
    "metadata": {
      "connector": "http",
      "source": "urn:lo:nsid:lora:0020B20000000101"
    },
    "streamId": "urn:lo:nsid:lora:0020B20000000101",
    "location": {
      "provider": "lora",
      "accuracy": 10,
      "lon": -121.562765,
      "lat": 36.969311
    },
    "model": "lora_v0",
    "value": {
      "payload": "ae2109000cf3"
    },
    "timestamp": "2017-07-26T08:32:44.034Z",
    "tags": [
      "Highway 101",
      "Tracker"
    ]
  },
  "tenantId": "5c0a6fb49a927971342aea06",
  "newState": "transportation_zone",
  "stateKey": "urn:lo:nsid:lora:0020B20000000101",
  "previousState": "null",
  "timestamp": "2021-06-17T13:57:36.637Z",
  "stateProcessingRule": {
    "stateKeyPath": "metadata.source",
    "name": "geo tracking",
    "stateFunction": "{\"if\":[{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":\"shipment\"}}]},\"shipment_zone\",{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":[\"transportation\"]}}]},\"transportation_zone\",{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":\"delivery\"}}]},\"delivery_zone\",\"unknown_zone\"]}",
    "id": "78063026-51e2-4c3e-aaf5-99efc4ee0255",
    "enabled": true,
    "filterPredicate": "{\"in\":[{\"var\":\"metadata.source\"},{\"ctx\":\"device-group\"}]}"
  }
}

Any other message in SF area will not generate event, because the state would remain unchanged.

Data Message 2:

Now, you can send a second data message, located this time on Highway 101.

POST liveobjects.orange-business.com/api/v0/data/streams/urn:lo:nsid:lora:0020B20000000101
{
  "metadata": {
    "connector": "http",
    "source": "urn:lo:nsid:lora:0020B20000000101"
  },
  "location": {
    "provider": "lora",
    "accuracy": 10,
    "lon": -121.562765,
    "lat": 36.969311},
  "model": "lora_v0",
  "value": {
    "payload": "ae2109000cf3"
  },
  "timestamp": "2017-07-26T08:32:44.034Z",
  "tags": [
    "Highway 101", "Tracker"
  ]
}

The message in Highway 101 area will generate the following event. Any other message in Highway 101 area would not generate event because state would be unchanged.

{
  "stateProcessingRuleId": "78063026-51e2-4c3e-aaf5-99efc4ee0255",
  "data": {
    "metadata": {
      "connector": "http",
      "source": "urn:lo:nsid:lora:0020B20000000101"
    },
    "streamId": "urn:lo:nsid:lora:0020B20000000101",
    "location": {
      "provider": "lora",
      "accuracy": 10,
      "lon": -121.562765,
      "lat": 36.969311
    },
    "model": "lora_v0",
    "value": {
      "payload": "ae2109000cf3"
    },
    "timestamp": "2017-07-26T08:32:44.034Z",
    "tags": [
      "Highway 101",
      "Tracker"
    ]
  },
  "tenantId": "5c0a6fb49a927971342aea06",
  "newState": "transportation_zone",
  "stateKey": "urn:lo:nsid:lora:0020B20000000101",
  "previousState": "null",
  "timestamp": "2021-06-17T13:57:36.637Z",
  "stateProcessingRule": {
    "stateKeyPath": "metadata.source",
    "name": "geo tracking",
    "stateFunction": "{\"if\":[{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":\"shipment\"}}]},\"shipment_zone\",{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":[\"transportation\"]}}]},\"transportation_zone\",{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":\"delivery\"}}]},\"delivery_zone\",\"unknown_zone\"]}",
    "id": "78063026-51e2-4c3e-aaf5-99efc4ee0255",
    "enabled": true,
    "filterPredicate": "{\"in\":[{\"var\":\"metadata.source\"},{\"ctx\":\"device-group\"}]}"
  }
}
Data Message 3:
POST liveobjects.orange-business.com/api/v0/data/streams/urn:lo:nsid:lora:0020B20000000101
{
  "metadata": {
    "connector": "http",
    "source": "urn:lo:nsid:lora:0020B20000000101"
  },
  "location": {
    "provider": "lora",
    "accuracy": 10,
    "lon": -118.154555,
    "lat": 33.881571},
  "model": "lora_v0",
  "value": {
    "payload": "ae2109000cf3"
  },
  "timestamp": "2017-07-26T08:32:44.034Z",
  "tags": ["Los Angeles", "Tracker"]
}

The third message in LA area will generate the following event. Any other message in LA area would not generate event because state would remain unchanged.

{
  "stateProcessingRuleId": "78063026-51e2-4c3e-aaf5-99efc4ee0255",
  "data": {
    "metadata": {
      "connector": "http",
      "source": "urn:lo:nsid:lora:0020B20000000101"
    },
    "streamId": "urn:lo:nsid:lora:0020B20000000101",
    "location": {
      "provider": "lora",
      "accuracy": 10,
      "lon": -118.154555,
      "lat": 33.881571
    },
    "model": "lora_v0",
    "value": {
      "payload": "ae2109000cf3"
    },
    "timestamp": "2017-07-26T08:32:44.034Z",
    "tags": [
      "Los Angeles",
      "Tracker"
    ]
  },
  "tenantId": "5c0a6fb49a927971342aea06",
  "newState": "delivery_zone",
  "stateKey": "urn:lo:nsid:lora:0020B20000000101",
  "previousState": "transportation_zone",
  "timestamp": "2021-06-17T14:01:48.004Z",
  "stateProcessingRule": {
    "stateKeyPath": "metadata.source",
    "name": "geo tracking",
    "stateFunction": "{\"if\":[{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":\"shipment\"}}]},\"shipment_zone\",{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":[\"transportation\"]}}]},\"transportation_zone\",{\"inside\":[{\"var\":\"location.lon\"},{\"var\":\"location.lat\"},{\"ctx\":{\"ctx\":\"delivery\"}}]},\"delivery_zone\",\"unknown_zone\"]}",
    "id": "78063026-51e2-4c3e-aaf5-99efc4ee0255",
    "enabled": true,
    "filterPredicate": "{\"in\":[{\"var\":\"metadata.source\"},{\"ctx\":\"device-group\"}]}"
  }
}

17.4.3. Use case 3: air quality monitoring

Pre-requisites:

  • the event processing feature is enabled for the tenant.

  • the tenant has a valid Live Objects API key.

17.4.3.1. Use case description :
  • Monitor 2 pollutants (NO2 and PM10)

  • Trigger INFO or ALERT events when thresholds are reached.

  • Trigger daily pollution level state change events for each pollutant.

This example includes SIMPLE EVENT PROCESSING rules and STATE PROCESSING rules.

The REST queries for this example are available here and can be run in Postman.

Air quality information is available for every monitoring station in a city. 3 different types of message are available:

  • hourly pollution level for each pollutant (data message sent every hour).

  • pollution level for the last 3 hours for each pollutant (data message sent every hour).

  • daily average level for each pollutant (data message once a day at 0 a.m.).

Information/Alert thresholds are defined for each pollutant type:

Interactive

Daily pollution level:

Interactive

For NO2, the threshold to trigger the ALERT is lower if the daily state for the previous day is MEDIUM or HIGH. The daily calculated state for NO2 must be stored by your application in the tenant context. Example:

PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/no2-previous-day-medium-level-reached
{
  "contextData": true,
  "tags": [
    "previous day"
  ]
}

Event triggering on air quality:

  • 6-hour INFO: when the information level is reached in a monitoring station for NO2 or PM10. Then, wait for 6 hours before getting any new "information level reached" event.

  • real-time ALERT

    • when the alert level is reached in a monitoring station for NO2 or PM10.

    • when the information level is reached in a monitoring station for NO2 and the daily pollution level for previous day was MEDIUM or HIGH

  • daily pollution level:when the daily pollution level changes, like for example: LOW→MEDIUM or MEDIUM→HIGH

Interactive

17.4.3.2. Streams of messages

A stream of data messages is attached to a monitoring station. The messages from the "paris-centre" monitoring station will be sent in a distinct stream from the "place de l’Opéra" monitoring station.

Data messages
  • hourly pollution level (sent every hour)

{
   "streamId": "paris-centre-hourly",
    "location": {
        "lon":2.2945, "lat": 48.8584
   },
   "model": "model_hourly",
   "value": {
      "type":"hourly",
      "NO2":450,
      "PM10":17,
      "monitoring-station":"paris-centre"
   },
   "timestamp": "2017-07-27T13:00:00Z"
}
  • hourly pollution level for the last 3 hours (sent every hour)

{
   "streamId":  "paris-centre-last-3-hours",
    "location": {
        "lon":2.2945, "lat": 48.8584
   },
   "model": "model_last_three_hours",
   "value": {
      "type":"last_three_hours",
      "data1": {"value":{"NO2":420,"PM10":16},"timestamp":"2017-07-27T11:00:00Z"},
      "data2": {"value": {"NO2":401,"PM10":14},"timestamp":"2017-07-27T12:00:00Z"},
      "data3": {"value": {"NO2":450,"PM10":17},"timestamp":"2017-07-27T13:00:00Z"},
      "monitoring-station":"paris-centre"
   },
   "timestamp":"2017-07-27T13:00:00Z"
}
  • daily average (sent once a day)

{
   "streamId": "paris-centre-daily",
    "location": {
        "lon":2.2945, "lat": 48.8584
   },
   "model": "model_daily",
   "value": {
      "type":"daily",
      "avg-NO2":250,
      "avg-PM10":53,
      "monitoring-station":"paris-centre"
   },
   "timestamp":"2017-07-28T00:00:00Z"
}
17.4.3.2.1. Test steps
Step1: Context provisioning
  • Create the information/alert levels for each pollutant.

    PUT liveobjects.orange-business.com/api/v0/eventprocessing/context/no2-alert-threshold-1
    {
      "contextData": 400,
      "tags": [
        "threshold","alert","no2"
      ]
    }

For the provisioning of the other thresholds, please check the postman requests.

Step2: State processing rule provisioning

Once the threshold levels are provisioned in the context, the rules need to be provisioned:

  • For events on exceeding thresholds, use Simple Event Processing (matching rules to check if an event should be triggered + firing rule for the frequency of triggering).

  • For events on daily pollution state change, use State Processing.

Interactive

Before provisioning the state processing rule, it is useful to run the state processing function on a test data message.

POST liveobjects.orange-business.com/api/v0/eventprocessing/stateprocessing-rule/test
{
  "currentState": {},
  "data": {
    "metadata": {
      "connector": "http"
      },
    "streamId": "paris-centre-daily",
    "location": {
        "lon":2.2945, "lat": 48.8584
    },
    "model": "model_daily",
    "value": {
      "type":"daily",
      "avg-NO2":9,
      "avg-PM10":9,
      "monitoring-station":"paris-centre"
    },
    "timestamp":"2017-07-27T00:00:00Z"
  },
  "stateProcessingFunction": {
    "if": [
      {
        "and":
          [
            { "<": [
              { "var": "value.avg-NO2"},
              {"ctx": "no2-alert-threshold-2"}
            ]},
            {"==": [{ "var": "value.type"}, "daily"]}
          ]
      },
      "LOW",
      {
        "and":
          [
            { "<": [
              {"ctx": "no2-alert-threshold-2"},
              { "var": "value.avg-NO2"},
              {"ctx": "no2-alert-threshold-1"}
            ]},
            {"==": [{ "var": "value.type"}, "daily"]}
          ]
        },
      "MEDIUM",
      {
        "and":
          [
            { ">": [
              { "var": "value.avg-NO2"},
              {"ctx": "no2-alert-threshold-1"}
            ]},
            {"==": [{ "var": "value.type"}, "daily"]}
          ]
      },
      "HIGH"
    ]
  }
}

Response:

{
    "stateFunctionValid": true,
    "dataValid": true,
    "stateFunctionResult": "LOW"
}

The test endpoint expects, as input, the current state, a data message and the state function. The response returns the function status (valid or not), the data status (valid or not) and the result of the state function applied to the data.

The threshold values are retrieved from the tenant context (ctx).

Now that the state function is tested, you can provision the state processing rule.

Daily pollution state processing rule:

POST liveobjects.orange-business.com/api/v0/eventprocessing/stateprocessing-rule
{
  "name": "NO2 daily pollution level",
  "enabled": true,
  "stateFunction": {
    "if": [
      {
        "and":
          [
            { "<": [
              { "var": "value.avg-NO2"},
              {"ctx": "no2-alert-threshold-2"}
            ]},
            {"==": [{ "var": "value.type"}, "daily"]}
          ]
      },
      "LOW",
      {
        "and":
          [
            { "<": [
              {"ctx": "no2-alert-threshold-2"},
              { "var": "value.avg-NO2"},
              {"ctx": "no2-alert-threshold-1"}
            ]},
            {"==": [{ "var": "value.type"}, "daily"]}
          ]
      },
      "MEDIUM",
      {
        "and":
          [
            { ">": [
              { "var": "value.avg-NO2"},
              {"ctx": "no2-alert-threshold-1"}
            ]},
            {"==": [{ "var": "value.type"}, "daily"]}
          ]
      },
      "HIGH"
    ]
  },
  "stateKeyPath": "streamId"
}

For the PM10 pollutant, the process is the same to create the state processing rule.

Step3: matching rule provisioning

Example: for NO2, if the previous day ended with a "MEDIUM" or "HIGH" level, the ALERT threshold level is 200 microgram/m3 instead of 400. When receiving the daily pollution state change event every night, your application must store it in the context (key name in the context: "no2-previous-day-medium-level-reached" and "no2-previous-day-high-level-reached", value: true or false) in order to be used in the real-time alerts.

the previous day state is set in the tenant context every night, by your application, based on the daily state event sent by the state processing rule.

More info on matching rules.

A testing point is available to prepare the matching rule and test it on a data message.

POST liveobjects.orange-business.com/api/v0/eventprocessing/matching-rule/test
{
  "data": {
    "metadata": {
      "connector": "http"
      },
   "streamId": "paris-centre-hourly",
    "location": {
        "lon":2.2945, "lat": 48.8584
   },
   "model": "model_hourly",
   "value": {
      "type":"hourly",
      "NO2":201,
      "PM10":15,
      "monitoring-station":"paris-centre"
   },
   "timestamp":"2017-07-27T02:00:00Z"
  },
  "dataPredicate": {
    "and": [
      {
        ">": [{"var": "value.NO2"}, {"ctx": "no2-alert-threshold-2" }]
      },
      {
        "or": [
          {"==": [{"ctx": "no2-previous-day-medium-level-reached"},true]},
          {"==": [{"ctx": "no2-previous-day-high-level-reached"},true]}
        ]
      },
      {
        "==": [{"var": "value.type"},"hourly"]
      }
    ]
  }
}

Response:

{
    "dataPredicateValid": true,
    "dataValid": true,
    "dataPredicateResult": true
}

Now, provision the matching-rule:

POST liveobjects.orange-business.com/api/v0/eventprocessing/matching-rule
{
  "name": "no2-alert-level-reached-threshold2",
  "dataPredicate": {
    "and": [
      {
        ">": [{"var": "value.NO2"}, {"ctx": "no2-alert-threshold-2" }]
      },
      {
        "or": [
          {"==": [{"ctx": "no2-previous-day-medium-level-reached"},true]},
          {"==": [{"ctx": "no2-previous-day-high-level-reached"},true]}
        ]
      },
      {
        "==": [{"var": "value.type"},"hourly"]
      }
    ]
  },
  "enabled": true
}

Response:

{
  "id": "0476993c-b7cc-49a7-9a86-87431ead76e7",
  "name": "no2-alert-level-reached-threshold2",
  "enabled": true,
  "dataPredicate": {
    "and": [
      {
        ">": [{"var": "value.NO2"}, {"ctx": "no2-alert-threshold-2"}]
      },
      {
        "or": [
          {"==": [{"ctx": "no2-previous-day-medium-level-reached"}, true]},
          {"==": [{"ctx": "no2-previous-day-high-level-reached"}, true]}
        ]
      },
      {
        "==": [{"var": "value.type"}, "hourly"]
      }
    ]
  }
}
Step4: firing rule provisioning

When the matching rule is ready, a firing rule must be provisioned in order to set the frequency for event triggering (ONCE, ALWAYS, SLEEP).

For the matching rule described in the previous step, an event is sent everytime the ALERT threshold is reached in a monitoring station.

POST liveobjects.orange-business.com/api/v0/eventprocessing/firing-rule
{
  "aggregationKeys": [
    "streamId"
  ],
  "enabled": true,
  "firingType": "ALWAYS",
  "matchingRuleIds": [
    "0476993c-b7cc-49a7-9a86-87431ead76e7"
  ],
  "name": "firing NO2 alert 200"
}

Another example of firing rule: for the PM10/NO2 INFO event, for a monitoring station, when an event is triggered, we do not want to receive any other INFO event in the next 6 hours. The firingType is set to SLEEP:

POST liveobjects.orange-business.com/api/v0/eventprocessing/firing-rule
{
  "aggregationKeys": [
    "streamId"
  ],
  "enabled": true,
  "firingType": "SLEEP",
  "matchingRuleIds": [
    "4578993c-b7cc-49a7-9a86-87431ead96a9"
  ],
  "name": "firing PM10 INFO",
    "sleepDuration": "PT6H"
}

The sleepDuration is expressed in a iso8601-duration format.

For the provisioning of the other SEP rules, please check the postman requests.

Step5: Send data messages

In this test, the data messages are sent using Live Objects REST http API.

Data message 1: hourly
POST liveobjects.orange-business.com/api/v0/data/streams/paris-centre-hourly
{
   "location": {
        "lon":2.2945, "lat": 48.8584
   },
   "model": "model_hourly",
   "value": {
      "type":"hourly",
      "NO2": 250,
      "PM10":45,
      "monitoring-station":"paris-centre"
   },
   "timestamp": "2017-07-27T14:00:00Z"
}
Data message 2: last 3 hours
POST liveobjects.orange-business.com/api/v0/data/streams/paris-centre-last-3-hours
{
    "location": {
        "lon":2.2945, "lat": 48.8584
   },
   "model": "model_last_three_hours",
   "value": {
      "type":"last_three_hours",
      "data1": {"value":{"NO2":420,"PM10":16},"timestamp":"2017-07-27T11:00:00Z"},
      "data2": {"value": {"NO2":401,"PM10":14},"timestamp":"2017-07-27T12:00:00Z"},
      "data3": {"value": {"NO2":450,"PM10":17},"timestamp":"2017-07-27T13:00:00Z"},
      "monitoring-station":"paris-centre"
   },
   "timestamp":"2017-07-27T13:00:00Z"
}
Data message 3: daily average
POST liveobjects.orange-business.com/api/v0/data/streams/paris-centre-daily
{
    "location": {
        "lon":2.2945, "lat": 48.8584
   },
   "model": "model_daily",
   "value": {
      "type":"daily",
      "avg-NO2":92,
      "avg-PM10":20,
      "monitoring-station":"paris-centre"
   },
   "timestamp":"2017-07-28T00:00:00Z"
}

In this example, the daily average is calculated in another system. Another option would be to calculate it in a recurrent query on the hourly stream, and then create the daily data message.

POST liveobjects.orange-business.com/api/v0/data/search
{ "size":0,
  "query": {
    "filtered": {
      "filter": {
        "bool":{
          "must": [
            {
              "term": {
                "streamId": "paris-centre-hourly"
              }
            },
            {
              "range": {
                "timestamp": {
                  "gte":"2017-07-27",
                  "lt":"2017-07-28"
                }
              }
            }
          ]
        }
      }
    }
  },
  "aggs": {
    "avg-NO2": {
      "avg": { "field": "@model_hourly.value.NO2" }
    },
    "avg-PM10": {
      "avg": { "field": "@model_hourly.value.PM10" }
    }
  }
}

response:

{
    "took": 124,
    "hits": {
        "total": 1
    },
    "aggregations": {
        "avg-PM10": {
            "value": 41
        },
        "avg-NO2": {
            "value": 450
        }
    }
}
Step6: Get events

The tenant can be notified of the triggered events. The events are also stored in a dedicated stream which can be requested using the Datamanagement data search API.

POST liveobjects.orange-business.com/api/v0/data/search
{
  "from": 0,
  "size": 10,
  "query": {
    "filtered": {
      "filter": {
        "bool":{
          "must": [
            {
              "term": {
                "streamId": "event:paris-centre-hourly"
              }
            },
            {
              "range": {
                "timestamp": {
                  "gte":"2017-08-03",
                  "lt":"2017-08-07"
                }
              }
            }
          ]
        }
      }
    }
  }
}

The response contains the list of events on the hourly stream for the "paris-centre" monitoring station.

{
  "took": 22,
  "hits": {
    "total": 2,
    "hits": [
      {
        "_source": {
          "metadata": null,
          "streamId": "event:paris-centre-hourly",
          "created": "2017-08-07T11:16:01.920Z",
          "location": {
            "provider": null,
            "alt": null,
            "accuracy": null,
            "lon": 2.2945,
            "lat": 48.8584
          },
          "model": "event:model_hourly",
          "id": "59884bf1e9cf83391a49ee61",
          "value": {
            "tenantId": "597f812389179c3436edf332",
            "matchingContext": {
              "matchingRule": {
                "dataPredicate": "{
                  \"and\":[
                    {\">\":[
                      {\"var\":\"value.NO2\"},
                      {\"ctx\":\"no2-info-threshold-1\"}
                    ]},
                    {\"==\":[
                      {\"var\":\"value.type\"},
                      \"hourly\"
                    ]}
                  ]
                }",
                "name": "no2-info-level-reached",
                "id": "84b1cbd7-5184-4460-b05e-41236fbfe770",
                "enabled": true
              },
              "data": {
                "metadata": {
                  "connector": "http"
                },
                "streamId": "paris-centre-hourly",
                "location": {
                  "lon": 2.2945,
                  "lat": 48.8584
                },
                "model": "model_hourly",
                "value": {
                  "NO2": 450,
                  "PM10": 41,
                  "type": "hourly",
                  "monitoring-station": "paris-centre"
                },
                "timestamp": "2017-07-27T14:00:00Z"
              },
              "tenantId": "597f812389179c3436edf332",
              "timestamp": "2017-08-07T11:16:04.859Z"
            },
            "timestamp": "2017-08-07T11:16:04.875Z",
            "firingRule": {
              "name": "firing NO2 INFO",
              "matchingRuleIds": [
                "84b1cbd7-5184-4460-b05e-41236fbfe770"
              ],
              "sleepDuration": "PT6H",
              "id": "f1dfc01d-a236-4bf6-b8a7-fdb2aa6a4e10",
              "aggregationKeys": [
                "streamId"
              ],
              "firingType": "SLEEP",
              "enabled": true
            }
          },
          "timestamp": "2017-08-07T11:16:04.875Z",
          "tags": [
            "event"
          ]
        }
      }
...
}

The events can also be retrieved with MQTT on a specific topic.

18. Web portal

The Live Objects web portal is available at https:/liveobjects.orange-business.com.

The User Guide presents Live Objects web portal, to learn more about using it: see here.

19. Audit Log

19.1. Concepts

This service will let you monitor what is happening in the core of the platform. More precisely, you will find an "AuditLog message" when an error occurs in a Live Objects service.

Use Audit log only as debugging tool

  • the format of these logs is subject to change

  • quantity of AuditLogs and retention duration are limited. See the dedicated section

Simple http REST API is available to search and retrieve specific AuditLog messages that will allow you to debug your application.

See the AuditLog swagger documentation for further information regarding this API.

You will also find an Activity log menu in the web portal to display these AuditLog messages.

19.2. List of events

Events detailed information are subject to changes. Here are the kind of events you will be able to get.

Category Sub-category Description Actions generating an AuditLog

connectivity

mqtt

Logs about the MQTT connector (all modes)

ERROR logs activated by default.

INFO logs activated only when debug mode is activated on the API-Key.

Note: MQTT AuditLogs are capped to avoid flooding. An AuditLog is sent to inform a limit is reached.

ERROR

# bad topic subscription or publication
# wrong datamessage format when publish
# connection error
# reached rate limit…​

INFO
# connections and disconnections

connectivity

lora

LoRa® network events. Specific for LoRa® connector. These logs depend of your offer and can be extended with an advance mode. Please contact your customer service.

By default, simple network events are raised as AuditLog messages.
# Join request
# Join accept

connectivity

lwm2m

Logs about the LwM2M connector

ERROR logs activated by default.

INFO logs activated only when the debug mode is activated on the LwM2M interface.

Note: LwM2M AuditLogs are capped to avoid flooding. An AuditLog is sent to inform the limit is reached. The capping limit is higher when the debug mode is activated.

ERROR
# limit reached
# connection refused (wrong security info, service disabled, etc.)
# the request timed out
# invalid request or response
# any other reason preventing a message to be successfully sent or processed by the platform
# DTLS handshake failed

INFO
# LwM2M operations (Register, Read, Send, etc.) requests and responses (including device responses with a code 4xx or 5xx)
# DTLS handshake initiated

notification

http

Logs about the httpPush action used in the Routing service

ERROR trying to send an event using httpPush action.
4xx, 5xx with the response body
Note: the AuditLog message is sent at the end of the retry policy, if activated in the routing policy.

notification

azure

Logs when using the action Azure Event Hubs in the Routing service

ERROR

# trying to send an event to Microsoft Azure Event Hubs using the dedicated action in the Routing service.

data

storage

Logs about the Search service (Elastic Search indexation)

ERROR
# 1000 fields in the model exceeded
# incoherence of the model (for ex. start with an integer and then value change with a boolean)
# several different types in an array ex. [1234, "stringText"] ⇒ impossible to index for Elastic Search

data

pipeline

Logs about the Pipeline service

ERROR
# ExternalTransformation Step : 4xx or 5xx response from server / connection timeout / invalid data format of the response / too many pending data messages for the pipeline

device management

twin

Logs about the Twin service

ERROR
# Max supported objects or instances
# Invalid instance: definition not found, wrong parent/mapType/objectType, or duplicate
# Reported values: distinct path quota reached
# Reported values: size quota reached

INFO
# Operations : delayed operations

20. Glossary

API

Application Programming Interface

FIFO

First In First Out

HTTP

HyperText Transfer Protocol

IoT

Internet of Things

IP

Internet Protocol

LED

Light-Emitting Diode

LPWA

Low-Power, Wide Area radio protocol

LPWAN

Low-Power, Wide Area Network

LOM

Live Objects Manage

M2M

Machine To Machine

MQTT

Message Queue Telemetry Transport

PPA

Personal Package Archives

PubSub

Publish and Subscribe

REST

REpresentational State Transfer

SaaS

Software as a Service

SDK

Software Development Kit

SIM

Subscriber Identity Module

TCP

Transmission Control Protocol

21. Limitations

21.1. Rate limiting

Rate limiting is applied to each API key and control the number of calls or messages per time window (e.g. 1 call per second). Depending on the offer, a rate limiting configuration may be applied to http interface, mqtt interface or both.

Http interface

Each response of the web controller contains 3 headers giving additional information on the status of the current request regarding rate limitation:

X-RateLimit-Limit: 5
X-RateLimit-Remaining: 3
X-RateLimit-Reset: 1479745936295
  • X-Rate-Limit-Limit is the rate limit ceiling per second

  • X-Rate-Limit-Remaining is the number of requests left for this time window

  • X-RateLimit-Reset is the ending date of the current time window (expressed in epoch milliseconds).

When receiving a request that would exceed authorized traffic limit, the web application returns a 429 Too Many Requests error with an empty body.

Note that all X-RateLimit headers are present in the response, as they would in a successful response.

Mqtt limits

Live Objects enforces limits for connections and traffic. Refer to the limit table. When a MQTT client tries to connect to Live Objects, connection limits are enforced according to the connection mode ( Device, Application, Connector ). If a limit is reached, the connection is refused. When a MQTT client sends traffic to Live Objects ( publish, subscribe ), traffic limits are enforced according to the connection mode ( Device, Application, Connector ). Refer to the following section for trafic limit policies.

Mqtt trafic limits with Device Mode

Devices using MQTT are subject to the subscribed offer traffic limits. The limits are at the account level and at the connection level. Refer to the limit table for details.

If a limit is reached for a MQTT/publish then the published message will be dropped and a warning will be available in Audit Log.

If a limit is reached for a MQTT/subscribe then the subscribe message will be rejected and a warning will be available in Audit Log.

Mqtt trafic limits with Application and Connector Mode

If a traffic ( subscribe, publish ) limit is reached, then the MQTT session will be closed. If an API key is used for several MQTT sessions at the same time, the API key quotas are computed with the overall API key traffic.

As MQTT 3.11 protocol does not provide a way to give disconnection reasons; you should use the AuditLog service to retrieve additional information. The client is expected to reconnect with a back off policy and re-send its data, as traffic will be allowed again in the next time window.

21.2. Resources limitation

Resource rate limiting is applied to each API Key and limit the search request.

X-ResourceLimit-Limit : 100
X-ResourceLimit-Remaining : 10
X-ResourceLimit-Reset : 1568707112000
X-ResourceLimit-Resource :SEARCH_DSL_QUERY
  • X-ResourceLimit-Limit is the rate limit ceiling of the authorized traffic limit (number of requests) for this time window

  • X-ResourceLimit-Remaining is the number of requests left for this time window

  • X-ResourceLimit-Reset is the ending date of the current time window (expressed in epoch milliseconds).

  • X-ResourceLimit-Resource is the resource identifier (SEARCH_DSL_QUERY)

When receiving a request that would exceed authorized traffic limit, the web application returns a 429 Too Many Requests error with an empty body.

21.3. Limitation table

Category Limit Limit type Value Default Auditlog notification

Access Management

Max number of API-Key

Absolute

Check your offer

5

NO

Max number of users

Absolute

Check your offer

5

NO

Actions

Max number of action policy

Absolute

Check your offer

50

NO

Max number of each action’s type per action policy

Absolute

Non-adjustable

10

NO

Max number of emitted emails

Rate

Check your offer

1000/day

YES

Max number of emitted SMS

Rate

Check your offer

10/day

NO

(httpPush) Max waiting time for a response from the remote host

Rate

Non-adjustable

5 seconds

YES

(httpPush) Socket timeout: Max time of inactivity between two data packets after connection

Rate

Non-adjustable

5 seconds

YES

(httpPush) Max number of bufferized messages (overflow)

Absolute

Non-adjustable

10.000

YES

Triggers

Max number of connectors filter per filter’s type

Absolute

Non-adjustable

20

NO

Alarming

Max Number of Matching rules

Absolute

Check your offer

50

NO

Max Number of Firing rules

Absolute

Check your offer

50

NO

Max Number of State processing rules

Absolute

Check your offer

50

NO

Max Number of Activity processing rules

Absolute

Check your offer

50

NO

Max number of deviceIds per Activity processing rule

Absolute

Non-adjustable

100

NO

Max number of groupPaths per Activity processing rule

Absolute

Non-adjustable

100

NO

Auditlog

Max number of audit log messages

Absolute

Non-adjustable

10.000.000

NO

Log messages retention delay

Absolute

Non-adjustable

14 days

YES

Business application & REST API

Max number of HTTP requests per API-Key

Rate

Check your dashboard

120/minute

NO

Max number of HTTP requests per account

Rate

Check your dashboard

3600/hour

NO

Max number of emitted bulks (for more information, see the chapter "Add a data message to a stream")

Rate

Check your dashboard

120/minute

NO

Max number of messages per bulk

Absolute

Check your offer

1000

NO

Max number of created FIFO (for more information, see the chapter "Using FIFO")

Absolute

Check your offer

10

NO

Max global FIFO size

Absolute

Check your offer

20 MBytes

NO

MQTT: Application mode

Max number of MQTT concurrent connections using application mode

Absolute

Check your dashboard

100

YES

Max number of MQTT message published per API-Key using: application mode

Rate

Check your dashboard

120/minute

YES

Max number of MQTT message published in total for the account using: application mode

Rate

Check your dashboard

3600/hour

YES

MQTT: Device mode

Max number of MQTT concurrent connections using device mode

Absolute

Check your offer

100

YES

Max connection attempts per device using device mode

Rate

Non-adjustable

1/second

YES

Max connection attempts per account using device mode

Rate

Check your offer

5/second

YES

Max number of MQTT message published per connection using: device mode

Rate

Check your offer

120/minute

YES

Max number of MQTT message published in total for the account using: device mode

Rate

Check your offer

3600/hour

YES

Max number of MQTT subscribe per connection using: device mode

Rate

Non-adjustable

10/minute

YES

MQTT: External connector mode

Max number of MQTT concurrent connections using external connector mode

Absolute

Check your dashboard

100

YES

Max number of MQTT message published per API-Key using: external connector mode

Rate

Check your dashboard

120/minute

YES

Max number of MQTT message published in total for the account using: external connector mode

Rate

Check your dashboard

3600/hour

YES

Data Management

Max number of custom pipelines

Absolute

Check your offer

10

NO

Max number of bufferized messages (overflow) for externalTransformation step

Absolute

Non-adjustable

10.000

NO

http connection timeout for externalTransformation step

Absolute

Non-adjustable

15 seconds

NO

http socket timeout for externalTransformation step

Absolute

Non-adjustable

30 seconds

NO

Max number of data retrieved per request using /streams http API (streamId)

Absolute

Non-adjustable

1.000

NO

Max number of data retrieved using /streams http API (streamId)

Rate

Non-adjustable

25.000/minute

NO

Datamessages retention delay in store service

Absolute

Check your offer

1 year

NO

Data Messages size limits

Max size of useful payload (size of "value" field).

Absolute

Non-adjustable

1 MBytes

NO

Max number of tags in datamessage

Absolute

Non-adjustable

10

YES

Device Management: Inventory

Max number of devices

Absolute

Check your offer

10

NO

Max number of tags

Absolute

Check your offer

10/device

NO

Max number of properties

Absolute

Check your offer

10/device

NO

Max number of interfaces

Absolute

Non-adjustable

5/device

NO

Max number of groups

Absolute

Non-adjustable

1500

NO

Max number of group levels

Absolute

Non-adjustable

7

NO

Device Management: Resources

Max size of a resource file

Absolute

Non-adjustable

10 MBytes

NO

Max number of aliases per resource

Absolute

Non-adjustable

5

NO

Size of device error message can be published: Max number of chars in message

Absolute

Check your offer

256

YES

Max number of resource per device

Absolute

Non-adjustable

50

YES

In-band update max number of retries for READ Firmware state operation

Absolute

Non-adjustable

10

NO

In-band update max number of retries for READ Firmware update result operation

Absolute

Non-adjustable

20

NO

Device Management: Command

Max number of queued commands per device

Absolute

Non-adjustable

10

NO

Device Management: Campaigns

Max number of scheduled campaigns

Absolute

Check your offer

50

NO

Max number of devices target in a campaign

Absolute

Check your offer

200

NO

Max number of operations in a campaign

Absolute

Non-adjustable

5

NO

Twin Management: Model

Max number of custom models

Absolute

Non-adjustable

20

NO

Twin Management: Operations

Max number of actives operations

Absolute

Check your offer

30

NO

Max number of final operations

Absolute

Check your offer

100

NO

Max number of attempts

Absolute

Non-adjustable

5

NO

Max global size of values for a write operation

Absolute

Non-adjustable

1Mo

NO

Twin Management: Reported values

Max distinct path for reported value per device

Absolute

Non-adjustable

500

YES

Max global size of reported values per device

Absolute

Non-adjustable

1Mo

YES

Max data message size of reported values

Absolute

Non-adjustable

1Mo

YES

Twin Management: Observation

Max number of observations per device

Absolute

Non-adjustable

10

NO

LWM2M connector

Size of a resource body that will be accepted as the payload of a CoAP POST/PUT or the response to a GET request

Absolute

Non-adjustable

550 KBytes

NO

Max number of supported and instantiated objects in the Register and Update operations

Absolute

Non-adjustable

200

YES

Max number of uplinks linked to the Registration Interface (Register / Update / De-register) for a given endpoint

Rate

Non-adjustable

10/minute

YES

Max number of uplinks linked to the Information Reporting Interface (Notify / Send) for a given endpoint

Rate

Non-adjustable

60/minute

YES

SMS connector

Max number of SMS interfaces

Absolute

Check your offer

10

NO

Max number of outgoing messages

Rate

Check your offer

100/day

NO

LoRa connector

Max number of LoRa interfaces

Absolute

Check your offer

10

NO

Max number of outgoing messages

Rate

Check your offer

None

NO

Decoding service

Max number of CSV decoders

Absolute

Non-adjustable

100

NO

Max number of binary decoders

Absolute

Non-adjustable

100

NO

Max number of javascript decoders

Absolute

Non-adjustable

100

NO

Max number of javascript-split decoders

Absolute

Non-adjustable

100

NO

Bootstrap LwM2M service

Max duration of the compute time during requests in the http /bootstrap/lwm2m/entries/search and /bootstrap/lwm2m/entries/count API. For each request, the compute time will be taken into account and the sum should not exceed the quota

Rate

Non-adjustable

total of 1 sec of compute / 10 sec

NO

Indexation & Search

Datamessages retention delay in search service

Absolute

Check your offer

1 year

NO

Max number of indexed fields for the account in total

Absolute

Check your offer

1000

YES

Max duration of the compute time during requests in the http search API. For each request, the compute time will be taken into account and the sum should not exceed the max

Rate

Check your offer

total of 10 sec of compute / 10 sec

NO

Security

Max number of CA certificates for SSL2WAYS

Absolute

Check your offer

10

NO

Network metrics

Max retention of network metrics

Absolute

Non-adjustable

31 days

NO