Scenario: Configuring a logical interface for a Thing (Beta)

This scenario builds on the previous Scenario: Configuring a common logical interface.

Important:

In this scenario, temperature and humidity devices publish environmental data that is collected in two meeting rooms - Meeting Room 1 and Meeting Room 2. For each meeting room, the temperature and humidity device data is separately mapped to two device type logical interfaces.

For Meeting Room 1, the temperature device data that is associated with the TSensor device type is mapped to the logical interface Thermometer Interface and the humidity device data that is associated with the device type HumiditySensor is mapped to the logical interface Hygrometer Interface.

For Meeting Room 2, the temperature device data that is associated with the TempSensor device type is mapped to the Thermometer Interface logical interface, and the humidity device data that is associated with the device type HumiditySensor is mapped to the Hygrometer Interface logical interface.

A Thing type called RoomType is then created, along with two room Thing instances: meetingroom1 and meetingroom2.

This scenario sets up a composition that includes the thermometer and hygrometer logical interfaces and then maps the correct environmental device to each of the room instances, for example, tSensor and humiditySensor1 are mapped to meetingroom1.

Prerequisites

Before you continue, make sure that you:

About this task

In Platform Service, a Thing can consist of a number of devices and Things. A Thing type defines how instances of a Thing are composed.

A logical interface is associated with a Thing type. This association defines the structure of the state that is generated for a Thing type instance. Mappings are used to define how properties from the aggregated devices and Things are mapped to properties on a Thing state.

The logical interface is used to remove the requirement for the application to understand how a device or Thing is configured. For example, you might measure the temperature of a room by using a single device, or you might calculate the room temperature by taking the average reading of a number of devices. The application requires information on the state of a room or rooms, one component of which is a temperature property. It does not matter how the temperature value that is received by the application is calculated.

In this scenario, two temperature devices and two humidity devices publish events to Platform Service. One temperature device and one humidity device are in Meeting Room 1 of an office block. The other temperature and humidity devices are in Meeting Room 2. The following diagram illustrates the configuration for Meeting Room 1:

Mapping between temperature and humidity Thing and an application on Platform Service.

A Thing type called RoomType is used to define how instances of rooms are composed. A logical interface is associated with the RoomType and defines that inbound events are mapped to a single reading that shows both temperature and humidity. This single reading is the Thing state. Mappings are used to define how properties from the temperature and humidity devices are mapped to this Thing state. When a new reading is published by these devices, the value of the property that is associated with the Thing state is changed.

The following table shows the four devices that are used in our example, the topic that each device publishes on, and an example payload for each device.

Device/Type Event Event Payload/Property
tSensor/TSensor (meetingroom1) iot-2/evt/tevt/fmt/json { "t" : 34.5 }/ temperature1
tempSensor/TempSensor (meetingroom2) iot-2/evt/tempevt/fmt/json { "temp" : 34.5 }/ temperature2
humiditySensor1/HumiditySensor (meetingroom1) iot-2/evt/humevt/fmt/json { "hum" : 75 }/ humidity1
humiditySensor2/HumiditySensor (meetingroom2) iot-2/evt/humevt/fmt/json { "hum" : 75}/ humidity2

Note: The event identifiers tevt, tempevt, humevt are required when you define mappings to make a property that is associated with an inbound event of that type to a property in the logical interface. In this scenario, two properties are defined in the logical interface - temperature and humidity.

A logical interface is also configured. The logical interface represents the Thing state in the following structure:

{
  "temperature" : <current temperature value in Celsius>
  "humidity" : <current humidity value>
}

Use the following example scenario to set up your own interfaces environment.

Note: A table listing the resource property names, values, and identifiers that are used in this guide is documented in Resource names and identifiers.

Add a device type and a device

In this scenario, three device types and four device instances are used. Device instance tSensor is associated with device type TSensor. Device instance tempSensor is associated with device type TempSensor. Device instances humiditySensor1 and humiditySensor2 are associated with device type HumiditySensor.

You can create device types and devices by using the Platform Service UI, or by using REST APIs.

For more information about using the Platform Service IoT Platform dashboard to add device types and devices, see the Getting started with data management by using the Web interface documentation.

For information about using REST APIs to add device types and devices, see the Platform Service HTTP REST API documentation.

Steps

Step 1: Create a Thing type schema file.

Create a Thing type schema file that references the device logical interface identifiers for the temperature and the humidity device types.

The following example shows how to create a Thing type schema file that is called roomTypeSchema.

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type" : "object",
    "title" : "Room Thing Type Schema",
    "description" : "JSON Schema that defines the structure of the Room Thing Type.",
    "properties" : {
        "thermometer": {
            "type": "object",
            "description": "The thermometer device",
            "$logicalInterfaceRef": "IThermometer"
        },
        "hygrometer": {
            "type": "object",
            "description": "The hygrometer device",
            "$logicalInterfaceRef": "IHygrometer"
        }
    },
    "required" : [
        "temperature",
        "humidity"
    ]
}

Tip: Use the required parameter to mark one or more properties as required. Required properties must be included in a device message for Watson IoT Platform to update the device state with the device data. A message that does not include the required property is not processed.
Note: The schema identifier that is generated when you create a Thing type schema file must be specified when you create your Thing type.

Step 2: Create a Thing schema resource.

Create the schema resouce by uploading the Thing type schema file that was generated in the previous step.
Upload the Thing type schema file by using the following API:

POST /draft/schemas

The schema definition file is passed to the Watson IoT Platform within a multipart POST (multipart/form-data). The body of the POST must contain at least two parts:

For more details, see the Platform Service HTTP REST API documentation.

The following example shows how to use cURL to create the Thing type schema resource:

curl --request POST \
  --url https://yourOrgID.internetofthings.ibmcloud.com/api/v0002/draft/schemas \
  --header 'authorization: Basic MK2fdJpobP6tOWlhgTR2a4Hklss2eXC7AZIxZWxPL9B8XlVwSZL=' \
  --header 'content-type: multipart/form-data' \
  --form name=roomTypeSchema \
  --form 'schemaFile=@"/Users/ANOther/Documents/IoT/DeviceState/thingStateDemo/setup/schemas/roomTypeSchema

The following example shows a response to the POST method:

{
  "name" : "roomTypeSchema",
  "createdBy" : "a-8x7nmj-9iqt56kfil",
  "contentType" : "application/octet-stream",
  "updated" : "2016-12-06T14:38:52Z",
  "schemaFileName" : "roomType.json",
  "version" : "draft",
  "created" : "2016-12-06T14:38:52Z",
  "id" : "5a72ea48d60180002c4f5e58",
  "refs" : {
      "content" : "/api/v0002/draft/schemas/5a72ea48d60180002c4f5e58/content"
  },
  "schemaType" : "json-schema",
  "updatedBy" : "a-8x7nmj-9iqt56kfil"
}

The schema identifier 5a72ea48d60180002c4f5e58 that is returned in response to the POST method is required when you create a Thing type.

Step 3: Create a Thing type

Thing types are used to model Thing instances. A Thing type must be created in an organization before a Thing instance can be created. For this scenario, create one Thing type.
The schema that is associated with a Thing type defines the type of objects that are aggregated together to make an instance of a Thing. The Thing type must reference the Thing type schema resource that you created in the previous step.
Create a Thing type by using the following API:

POST /draft/thing/types

The following parameters are required in the body of the POST method:

Parameter Description
id Provide an identifier for the Thing type that you are creating.
name Provide a name for the Thing type that you are creating.
schemaId The identifier created for the composition schema resource.

For more details, see the Platform Service HTTP REST API documentation.

The following example shows how to use cURL to create a Thing type that is called RoomType.

curl --request POST \
  --url https://yourOrgID.internetofthings.ibmcloud.com/api/v0002/draft/thing/types \
  --header 'authorization: Basic MK2fdJpobP6tOWlhgTR2a4Hklss2eXC7AZIxZWxPL9B8XlVwSZL=' \
  --header 'content-type: application/json' \
  --data '{"id" : "RoomType", "name" : "Room Thing Type", "description" : "Room Thing Type", "schemaId" : "5a72ea48d60180002c4f5e58"}'

Response:

{
 "name": "RoomType",
 "description": "Room Thing Type",
 "id": "RoomType",
 "schemaId": "5a72ea48d60180002c4f5e58",
 "metadata": {},
  "refs": {
    "schema": "/api/v0002/draft/schemas/5a72ea48d60180002c4f5e58",
    "mappings": "/api/v0002/draft/thing/types/RoomType/mappings",
    "logicalInterfaces": "/api/v0002/draft/thing/types/RoomType/logicalinterfaces"
   },
 "version": "draft",
 "created": "2018-02-01T10:22:43Z",
 "createdBy": "ANOther",
 "updated": "2018-02-01T10:22:43Z",
 "updatedBy": "ANOther"
}

Step 4: Create a logical interface schema file

In your logical interface, you can define the structure of the data that is stored as the Thing state. For this scenario, create a logical interface that defines temperature and humidity properties. Associate the logical interface with the Thing type RoomType by referencing the logical interface identifier that is generated when you create the logical interface resource.
The following example shows how to create a logical interface schema file that is called roomSchema.

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type" : "object",
    "title" : "roomSchema",
    "description" : "JSON Schema that defines the canonical room state structure",
    "properties" : {
        "temperature" : {
            "description" : "Temperature in degrees celsius",
            "type" : "number",
            "minimum" : -273.15,
            "default" : 0.0
        },
        "humidity" : {
            "description" : "Percentage humidity",
            "type" : "number",
            "minimum" : 0,
            "maximum" : 100,
            "default" : 0.0
        }
    },
    "required" : [
        "temperature",
        "humidity"
    ]
}

Step 5: Create a logical interface schema resource.

Upload the logical interface schema file that you created in the previous step to create a logical interface schema resource for your Thing type by using the following API:

POST /draft/schemas

For more details, see the Platform Service HTTP REST API documentation.

The following example shows how to use cURL to create the logical interface schema:

curl --request POST \
  --url https://yourOrgID.internetofthings.ibmcloud.com/api/v0002/draft/schemas \
  --header 'authorization: Basic MK2fdJpobP6tOWlhgTR2a4Hklss2eXC7AZIxZWxPL9B8XlVwSZL=' \
  --header 'content-type: multipart/form-data' \
  --form name=roomSchema \
  --form 'schemaFile=@"/Users/ANOther/Documents/IoT/ThingState/thingStateDemo/setup/schemas/room.json"'

The following example shows a response to the POST method:

{
  "created" : "2016-12-06T16:51:14Z",
  "name" : "roomSchema",
  "createdBy" : "a-8x7nmj-9iqt56kfil",
  "updated" : "2016-12-06T16:51:14Z",
  "updatedBy" : "a-8x7nmj-9iqt56kfil",
  "schemaType" : "json-schema",
  "contentType" : "application/octet-stream",
  "schemaFileName" : "room.json",
  "version" : "draft",
  "refs" : {
    "content" : "/api/v0002/draft/schemas/5a4b9847d60180002efce645/content"
  },
  "id" : "5a4b9847d60180002efce645"
}

Use the schema identifier 5a4b9847d60180002efce645 that is returned in the response to the POST method to add the logical interface schema resource to the logical interface for your Thing type.

Step 6: Create a logical interface for the Thing type.

The logical interface must reference the logical interface schema resource that you created in the previous step.
To create a logical interface, use the following API:

POST draft/logicalinterfaces

You can optionally specify a meaningful alias name for your logical interface. The alias can be referenced in the API call or topic string subscription that is used to retrieve the state of a Thing, instead of using the auto-generated logical interface identifier.

Note: The alias name must be 1 - 36 characters long and can include alphanumeric, hypen, period, underscore characters. The alias name cannot be a 24 character hex string.

In this scenario, use the schema identifier 5a4b9847d60180002efce645 that was returned in the previous response to add the logical interface schema to the logical interface.

The following example shows how to use cURL to create a logical interface with the alias IRoom:

curl --request POST \
  --url https://yourOrgID.internetofthings.ibmcloud.com/api/v0002/draft/logicalinterfaces \
  --header 'authorization: Basic MK2fdJpobP6tOWlhgTR2a4Hklss2eXC7AZIxZWxPL9B8XlVwSZL=' \
  --header 'content-type: application/json' \
  --data '{"name" : "IRoom", "alias" : "IRoom", "schemaId" : "5a72ea48d60180002c4f5e58"}'

The following example shows a response to the POST method:

{
  "createdBy" : "a-8x7nmj-9iqt56kfil",
  "refs" : {
      "schema" : "/api/v0002/draft/schemas/5a72ea48d60180002c4f5e58"
  },
  "schemaId" : "5a72ea48d60180002c4f5e58",
  "created" : "2016-12-06T16:53:27Z",
  "updatedBy" : "a-8x7nmj-9iqt56kfil",
  "id" : "5a4b9847d60180002efce645",
  "updated" : "2016-12-06T16:53:27Z",
  "name" : "IRoom",
  "alias" : "IRoom",
  "version" : "draft"
}

In this scenario, use the logical interface identifier 5a4b9847d60180002efce645 that is returned in the response to the POST method to add your logical interface to your device type. You also use this identifier to map an inbound device event to a property that is defined by the logical interface.

For more details, see the Platform Service HTTP REST API documentation.

Step 7: Add the logical interface to the Thing type.

To add a logical interface to a Thing type, use the following API:

POST draft/thing/types/{thingtypeId}/logicalinterfaces

For more details, see the Platform Service HTTP REST API documentation.
In this scenario, the logical interface is associated with Thing type RoomType.

The following example shows how to use cURL to add the Thing logical interface IRoom to the Thing type RoomType:

{   
  "id": "5a4b9847d60180002efce645"
}
curl --request POST \
  --url https://yourOrgID.internetofthings.ibmcloud.com/api/v0002/draft/logicalinterfaces \
  --header 'authorization: Basic MK2fdJpobP6tOWlhgTR2a4Hklss2eXC7AZIxZWxPL9B8XlVwSZL=' \
  --header 'content-type: application/json' \
  --data '{"id": "5a4b9847d60180002efce645"}'

The following example shows a response to the POST method:

{
 "name": "Room Logical Interface",
 "description": "This is a Room logical interface",
 "id": "5a4b9847d60180002efce645",
 "schemaId": "5a4b9817d60180002efce644",
 "refs": {
   "schema": "/api/v0002/draft/schemas/5a4b9817d60180002efce644"
 },
 "version": "draft",
 "created": "2018-01-02T14:33:43Z",
 "createdBy": "ANOther",
 "updated": "2018-01-02T14:33:43Z",
 "updatedBy": "ANOther"
}

Step 8: Define mappings

Define the mappings for the Thing type that describe how to map properties from the state of the aggregated devices or Things to the properties that are defined on the Thing type logical interface.

To map events, use the following API:

POST draft/thing/types/{thingtypeId}/mappings

where thingtypeId is the identifier that is returned in the response to the POST request when the Thing type is created.

The following parameters are required in the body of the POST request:

Parameter Description
propertyMappings A valid JSON structure that maps properties defined for the logical interface with the properties of the device event payload.
logicalInterfaceId The logical interface identifer is required in the body of the payload.

For more details, see the Platform Service HTTP REST API documentation.

The following example shows how to use cURL to add a mapping to Thing type RoomType:

{
  "logicalInterfaceId": "5a4b9847d60180002efce645",
  "notificationStrategy": "on-state-change",
  "propertyMappings": {
       "thermometer": {
         "temperature": "$event.temperature"
       },
       "hygrometer": {
         "humidity": "$event.humidity"
       }
   },
}

The thermometer device is defined in roomTypeSchema. The $event.temperature property is defined in the logical interface schema with the identifier 5846ed076522050001db0e12 and alias IThermometer.
The hygrometer device is defined in the roomTypeSchema. The $event.humidity property is defined in the logical interface schema with the identifier 5846cd7c6522050001db0e24 and alias IHygrometer.

Step 9: Validate and activate the configuration

Validate and activate the configuration that is related to Thing state update for each Thing type. This configuration includes your schemas, logical interfaces and mappings.

To validate and activate your Thing type configuration, use the following API:

PATCH /draft/thing/types/{thingTypeId}

where thingTypeId is the Thing type identifier.

The following example shows how to use cURL to validate and activate the configuration that is associated with the Thing type RoomType:


curl --request PATCH \
  --url https://yourOrgID.internetofthings.ibmcloud.com/api/v0002/draft/device/types/RoomType \
  --header 'authorization: Basic MK2fdJpobP6tOWlhgTR2a4Hklss2eXC7AZIxZWxPL9B8XlVwSZL=' \
  --header 'content-type: application/json' \
  --data '{
            "operation" : "activate-configuration"
          }'

The following example shows a response to the PATCH method:

{
 "message": "CUDIM0300I: State update configuration for Thing Type 'Room Thing Type' has been successfully submitted for  activation.",
 "details": {
   "id": "CUDIM0300I",
   "properties": [
     "Thing Type",
     "Room Thing Type"
   ]
 },
 "failures": []
}

Step 10: Create an instance of a Thing type

A Thing is an instance of a Thing type. A Thing enables you to aggregate one or more instances of a device or Thing together into a single object.

To create a Thing, use the following API:

POST /thing/types/{thingTypeId}/things

where thingtypeId is the identifier that is returned in the response to the POST request when the Thing type is created.

For more details, see the Platform Service HTTP REST API documentation.

In this scenario, we need to create two Thing instances that are of Thing type RoomType. One Thing instance is called meetingroom1 and the other Thing instance is called meetingroom2.

The following example shows how to use cURL to create a Thing instance that is called meetingroom1. The meetingroom1 Thing instance is associated with tSensor and humiditySensor1 device instances.

thingId = "meetingroom1"
 meetingroom1AggregatedObjects = {
   "thermometer": {
     "type": "device",
     "typeId": "TSensor",
     "id": "tSensor"
   },
   "hygrometer": {
     "type": "device",
     "typeId": "HumiditySensor",
     "id": "humiditySensor1"
   }
 }

The Thing identifier that is created is used in the URL of the POST method that is called to add a temperature event to the Thing logical interface.

The following example shows how to use cURL to create a Thing instance that is called meetingroom2. meetingroom2 is associated with the tempSensor and humiditySensor2 device instances.

thingId = "meetingroom2"
   meetingroom2AggregatedObjects = {
    "thermometer": {
      "type": "device",
      "typeId": "TempSensor",
      "id": "tempSensor"
    },
    "hygrometer": {
      "type": "device",
      "typeId": "HumiditySensor",
      "id": "humiditySensor2"
    }
  }

Step 11: Verify that mapped device events are published to the logical interface

Publish the following events for devices that are aggregated into the Thing meetingroom1:

Publish the following events for devices that are aggregated into the Thing meetingroom2:

For information about publishing an inbound event from a device, see MQTT connectivity for applications.

Step 12: Check that the state of the Thing is changed.

You can retrieve the state of the Thing either by using HTTP REST APIs, or by subscribing to a topic.

If you have an MQTT client application, you can subscribe to the following topic string:

iot-2/type/${thingTypeId}/id/$thingId/intf/${logicalInterfaceId}/evt/state

Alternatively, you can retrieve the latest Thing state by using the following HTTP REST API:

GET iot-2/thing/type/${ThingTypeId}/id/${ThingId}/intf/${LogicalInterfaceId}/evt/state

The following parameters are required:

Parameter Description
thingTypeId The Thing type identifier.
thingId The Thing identifier.
logicalInterfaceId The identifier created for the logical interface.

You can also retrieve Thing state errors by using the following call:

iot-2/thing/type/${ThingTypeId}/id/${ThingId}/err/data

For more details, see the Platform Service HTTP REST API documentation.

Next Steps

Create rules that you can use to initiate an action when an event that is received by Platform Service causes a change in device or Thing state. For information about creating rules, see Creating embedded rules.