Developing an IoT application with COMPOSE: Smart Spaces Use Case Tutorial

Sep 16, 2015 |

OBJECTIVE

This tutorial has the objective of showing and end to end development of a use case application, with tips on how to configure the different features of COMPOSE and how to integrate them. We assume you have read the basic COMPOSE description and architecture and at least experimented with the basic tutorials.

The application we are building in this tutorial is based on a Smart Spaces scenario, where products become an interaction point with consumers to create enhanced experiences. From the functional point of view the application will allow users to:

  • Log in into the COMPOSE platform and get access to the application.
  • Search for products based on their semantic descriptions.
  • Access product information, combining static and dynamic information.
  • Access special offers based on their memberships status.
  • Use feedback on products.
  • Visualise statistics on products.

Checkout the code at: Code on github

TUTORIAL CONTENT

Following the steps in this tutorial, we are going to see how COMPOSE facilitates the materialisation of the planned functionality for the application. We will learn how to put together many of the core features of the COMPOSE platform to create an end to end application.

From the COMPOSE platform point of view, what you are going to learn after this tutorial is:

  • How to create users.
  • How to create Service Objects.
  • How to create Groups to limit visibility of Service Objects.
  • How to create Groups to grant special access to Service Objects.
  • How to authenticate users.
  • How to secure communication to/from Service Objects.
  • How to annotate Service Objects with semantic descriptions.
  • How to use Semantic Discovery to find Service Objects based on categories.
  • How to send Service Object stream data.
  • How to subscribe to Service Object stream data.
  • How to create applications to combine/process Service Object data and deploy them in the cloud.
  • How to evaluate the reputation of Service Objects.
  • How to integrate with other cloud services.

SAMPLE APPLICATION

CREATE A USER ACCOUNT

If you don’t have a developer account in the COMPOSE platform, you should create one following the instructions here.

MODEL YOUR SERVICE OBJECTS

One of the first steps is to define your Service Objects. A Service Object is the virtual representation of real object or device inside the COMPOSE platform. It defines the information that is going to be part of the object, either data sensed from the object or data pushed to it. For our application we want to model the products, their basic information and the interactions that users will do with them.

{ 
   name: "Prince START Naturel New", 
   customFields: { 
     photo: "http://proddb.kraft-hosting.net/prod_db/proddbimg/31536.png", 
     brand: "LU", 
     nutritional_facts: "{\"carbs\": \"2\", \"calories\": \"1.3\", \"fat\": \"0\", \"sugar\": \"<1%\", \"protein\": \"3\", \"salt\": \"0\", \"saturatedFat\": \"3\"}", 
     summary: "Chocolate chips" 
   }, 
   description: "LU Prince Biscuits with Cocoa creme filling are made with a cocoa cream filling between two crip flavoured biscuits.", 
   streams: { 
      price: { 
         channels: { 
            value: { 
               type: "Number", 
               unit: "euros" 
           } 
         }, 
         type: "sensor", 
         description: "Price information" 
      }, 
      dislikes: { 
         channels: { 
            user: { 
               type: "String", 
               unit: "id" 
            }, 
           location: { type: "geo_point", unit: "lat-long" } }, type: "sensor", description: "Dislikes" }, shares: { channels: { user: { type: "String", unit: "id" }, location: { type: "geo_point", unit: "lat-long" } }, type: "sensor", description: "Shares" }, tocart: { channels: { user: { type: "String", unit: "id" }, location: { type: "geo_point", unit: "lat-long" } }, type: "sensor", description: "ToCart" }, likes: { channels: { user: { type: "String", unit: "id" }, location: { type: "geo_point", unit: "lat-long" } }, type: "sensor", description: "Likes" }, checkins: { channels: { user: { type: "String", unit: "id" }, location: { type: "geo_point", unit: "lat-long" } }, type: "sensor", description: "Checkins" }, scans: { channels: { user: { type: "String", unit: "id" }, location: { type: "geo_point", unit: "lat-long" } }, type: "sensor", description: "Scans" } } }

The Service Object for a product has the following:

  • Streams:
    • price: it contains a unique channel that captures the current price of the product.
    • dislikes, shares, tocart, likes, checkins, scans: interactions done by the users. They contain two channels, the userId and the location where the interaction was originated.
  • Custom Fields:
    • photo: link to a photo of the product
    • brand: name of the brand
    • nutritional facts

CREATE YOUR SERVICE OBJECTS

Once the data for the model is defined, you have to create the actual Service Objects in the system. This can be done either in gluethings or by invoking the COMPOSE LCM API directly. This will prepare the Service Object and the necessary metadata to support security and semantics.

    token = YOUR_API_TOKEN
    product_so = YOUR_PRODUCT_JSON_MODEL
    lcmEndpoint = LCM_COMPOSE_ENDPOINT
    headers = {
      "Authorization": "Bearer " + token,
      "Content-Type": "application/json"
    }
    request = Request(lcmEndpoint, data=product_so, headers=headers)
    request.get_method = lambda: 'POST'
    response_body = urlopen(request).read()

Enable subscriptions

In order for the Service Object to provide real time information to specific users, subscriptions need to be created on the streams that we want to subscribe to, so we have to enable subscriptions for each stream of our Service Object.

    token = YOUR_API_TOKEN
    soid = YOUR_SERVICE_OBJECT_ID
    headers = {
               "Authorization": token,
               "Content-Type": "application/json"    
    }

    subscription = json.dumps({
                    "callback":"pubsub",
                    "destination": token
    })

    //How to enable subscription to the price stream
    priceSubscriptionURL = servioticyEndpoint + "/" + soid + "/streams/price/subscriptions"
    
    request = Request(priceSubscriptionURL , data=subscription, headers=headers)
    request.get_method = lambda: 'POST'
    response_body = urlopen(request).read()
    data = json.loads(response_body)
    print "  Subscription created for SOID: " + data["id"]

SEMANTIC MODEL

One of the features of COMPOSE is the ability to provide semantic descriptions for the different Service Objects, thanks to the integration with iServe (link). Service Objects can be annotated with domain ontologies to specify additional properties. In our application we want the user to be able to search products based on categories. For this we are using the semantic categories defined in Good Relations, a well known and extended ontology for e-commerce and products.

 
compose:ServiceObject 
     a msm:Service; 
     sawsdl:modelReference "http://www.productontology.org/id/Cookie"

Using this categorization, we can now use semantic discovery in our application. Discovery is based on the product category, but other properties could be used easily to define advanced search modes.

Annotate the Service Object

To annotate the Service Object the model needs to be attached to the Semantic Description of the Service Object. This description is available after the Service Object creation and can be easily attached by invoking iServe. To update the Service Object model, you have to obtain its semantic description first and then update the property.

 
def createModelReference(soid, model): 
   headers = { "Accept": "application/json" } 
   request = Request(iServeEndpoint + "/discovery/svc/search?q=" + soid, data="", headers=headers) 
   request.get_method = lambda: 'GET' 
   response_body = urlopen(request).read() 
   data = json.loads(response_body) 
   query_args = { 'property':'http://www.w3.org/ns/sawsdl#modelReference', 'value': model } 
   encoded_args = urllib.urlencode(query_args) 
   url = key + '/properties/?' + encoded_args 
   request = Request(url, data="", headers=headers) 
   request.get_method = lambda: 'POST' 
   response_body = urlopen(request).read() 
   data = json.loads(response_body) return 

Semantic Discovery

Now that our Service Object is semantically annotated we can use the categories for discovery.

var url = iServeURL; 
var queryData = { discovery: { "func-rdfs": { classes: { or: ["http://www.productontology.org/id/' + category + '"] }, type: "svc", matching: "subsume" } } }; httpService.doHTTP("POST", queryData, url, function (response) { 
           for (var service in response) { 
               var soid = response[service]["description"].split(" ").splice(-1); 
               //Process SOID 
           } 
});

SECURITY MODEL

COMPOSE has a powerful built-in security model to guarantee the right access and security of the data generated around Service Objects. For our test application we will consider the following scenario:

  • All users of the application can read the product information.
  • Users labelled as “premium members” will have access to discounted products.
  • Users labelled as “admins” will have access to modify the product data.

In COMPOSE we can model this scenario in the following way:

  • One security group “premium-members” to which we need to add the premium users.
  • One security group “admins” to which we need to add the admin users.
  • A security policy that restricts the write operation for users not in the “admins” group
  • A security policy that restricts the visibility of offers for users not in the “premium-members” group

To configure this security aspects we need to:

Create groups

Groups can be created either from the gluethings dashboard (in the user’s profile)

Groups

Or by calling the corresponding API for group creation

def createIDMGroup(name):
    token = YOUR_API_TOKEN
    URL = idmEndpoint + '/idm/group/';
    idmData = '{"name":"'+name+'"}'    
    headers = {
               "Authorization": "Bearer " + token,
               "Content-Type": "application/json;charset=UTF-8"
    }
    
    response = requests.post(URL, data=idmData,headers=headers)        
    return response.json()

Security policy

The security policy restricting the write permissions in the “admins” group is set up as:

Coming soon…

The security policy restricting the read permissions in the “premium-members” group is set up as:

Coming soon…

Add Users to groups

Adding users to the group can be done from the gluethings dashboard by knowing their user id:

Groups

Or alternatively it can also be done from the API, by creating a membership:

def createMembership(groupId, userId):
    token = YOUR_API_TOKEN

    URL = idmEndpoint + '/idm/memberships/user/' + userId + "/";
    idmData = '{"group_id":"' + groupId + '", "role":"YOUR_ROLE"}' 
    
    headers = {
               "Authorization": "Bearer " + token,
               "Content-Type": "application/json;charset=UTF-8"
    }
    
    response = requests.post(URL, data=idmData, headers=headers)        
    return response.json()

Add Service Objects to group

Service Objects as well need to be added to the corresponding groups.

def addSOToGroup(soid,groupId):
    token = YOUR_API_TOKEN
    URL = idmEndpoint + '/idm/group_memberships/serviceobject/' + soid + '/';

    idmData = '{"group_id":"' + groupId +'"}'    
    headers = {
               "Authorization": "Bearer " + token,
               "Content-Type": "application/json;charset=UTF-8"
    }
    
    response = requests.post(URL, data=idmData,headers=headers)            
    return response.json()

COMPOSE CLOUD APPLICATIONS

COMPOSE infrastructure enables you to create applications in Node-RED and deploy them and monitor them in the cloud. In our case we have defined several COMPOSE applications that are used to aggregate the information of a Service Object to create a visualisation of it. We are mainly exposing additional endpoints that can be then integrated in the mobile application.

To create this endpoints you have to work with the gluethings Composer component, which is based on Node-RED, and deploy the correspondent workflow to the cloud. This will deploy the application in the COMPOSE infrastructure, where it can be invoked and monitored.

The example flows that you can find in this tutorial are:

  • Price Graph
  • Interactions Map
  • Sentiment Data

MOBILE APPLICATION

Once the COMPOSE platform is configured we can create the application. In the sample application we are using ionic, a mobile framework based on javascript. The application is developed on top of the Angular javascript framework, so we assume some knowledge on these platforms.

These application shows how to integrate the different flows needed to integrate the functionality of COMPOSE. You can take this application as an example to see how to integrate certain parts in your own apps, mainly:

  • User authentication
  • Service Object access, updates and notifications
  • Semantic Discovery
  • Security Policies
  • User of COMPOSE applications in the cloud

 

Posted in: End to End tutorials

Comments are closed.