com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_link3' is unknown.

Device Manufacturer Guide

This section gives you a quick introduction on how to integrate a new device with WSO2 IoT Server. For this purpose let's look at how Connected Cup gets connected to WSO2 IoT Server.

Planetbucks Connected Cup

Planetbucks is a local coffee vendor, well known and liked for their variety of exquisite coffee blends. They have a large customer base and most of the customers drop in on their way to work and after-work to grab a cup of coffee.

Planetbucks, Amy and Connected Cup

Amy, the manager of Planetbucks is amazed by the number of customers walking in and out of the store daily. She notices that most of these customers are in a hurry to grab a coffee and rush back to work/home. She feels that Planetbucks can get a competitive advantage in the market if they are able to take the coffee to the customer's work place/home, without them having to come to the store. With this idea in mind Amy moves on to start a Valued-Customer Program where all the Planetbucks regular customers are given a custom designed cup, which not only holds coffee but looks at including the following features:

  1. Display the level of coffee and temperature on the cup.

  2. Allow customers to order coffee by clicking a button on the cup.

  3. Allow customers to remotely monitor the cup and see the status of the coffee.

  4. Allow Planetbucks to study the customer drinking patterns and the coffee consumption.

Connected Cup and Steve

Amy approaches a local Device Manufacturer named Steve to get the connected cup designed, manufactured and connected. 

Steve is successful in manufacturing the hardware and is now in the look out for a suitable software platform to manage and control all the Connected Cups that Planetbucks hope to distribute to its customers. Steve searches through the internet and finds out that WSO2 IoTS is able to provide a viable solution to manage the cups that he manufactured.

He then starts using WSO2 IoT Server. Follow the steps given below for a walk through on how Steve got Connected Cup and the IoT Server to work together. You can follow the same steps to connect your device with WSO2 IoTS.

Downloading WSO2 IoT Server

To begin, Steve downloads WSO2 IoTS and starts it up on his production environment by following the steps given below.

  1. Download WOS2 IoT Server from the here.

  2. Copy the downloaded file to a preferred location and unzip it.

    The unzipped file will be called <IoT_HOME> throughout this documentation.

Writing the Connected Cup device plugin

In WSO2 IoTS, each device type is required to have its own device plugin. Therefore, Steve writes a device plugin for Connected Cup. 

WSO2 IoTS is built on top of the WSO2 Connected Device Management Framework (CDMF). A device plugin is an OSGI bundle that gets wired with WSO2 CDMF. For more information, see Writing Device Plugins.

Prerequisite

Open the Connected Cup sample, that is in the <IoTS_HOME>/samples/connectedcup directory via IntelliJ IDEA or a preferred IDE.

Let's take a look at how Steve implemented the device plugin for Connected Cup by following the steps given below. You can follow the same to create a new device type plugin:

  1. Implement the DeviceManagementService by importing org.wso2.carbon.device.mgt.common.spi.DeviceManagementService, as shown in the ConnectedCupManagerService.java file that is in the <IoTS_HOME>/samples/connectedcup/component/plugin/src/main/java/org
    /coffeeking/connectedcup/plugin/impl
     directory. 

    Info from Steve

    In order to be identified as a device type in WSO2 CDMF, I implemented an interface for Connected Cup and registerd it as an OSGI service.

    Take a look at the DeviceManagementService interface implementation in WSO2 CDMF.

    The DeviceManagementService interface.
    public interface DeviceManagementService {
        void init() throws DeviceManagementException;
        String getType();
        OperationMonitoringTaskConfig getOperationMonitoringConfig();
        DeviceManager getDeviceManager();
        ApplicationManager getApplicationManager();
        ProvisioningConfig getProvisioningConfig();
        PushNotificationConfig getPushNotificationConfig();
        PolicyMonitoringManager getPolicyMonitoringManager();
    }
     Click here for more information on the methods used in the DeviceManager interface
    MethodDescription

    init()

    Includes the custom initialization implementations. The private variable should be initialized in the init() method as WSO2 CDMF calls this method when checking for implementations that have the deviceManagerService interface.

    Example:

    @Override
    public void init() throws DeviceManagementException 
    {
       this.deviceManager=new ConnectedCupManager();
    }
    getType()

    Retrieves the name of the device type.

    Example:

    @Override
    public String getType() 
    {
       return ConnectedCupConstants.DEVICE_TYPE;
    }

    getOperationMonitoringConfig()

    Returns an object, which is an implementation of the org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig interface. Example:

    @Override
    public OperationMonitoringTaskConfig getOperationMonitoringConfig() 
    {
       return null;
    }

    getDeviceManager()

    The implementation of this interface should have a private variable of the device manager. It returns an object, which is an implementation of the org.wso2.carbon.device.mgt.common.DeviceManager interface.

    Example:

    @Override
    public DeviceManager getDeviceManager() 
    {
       return deviceManager;
    }

    getApplicationManager()

    Returns an object, which is an implementation of the org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManager interface.

    Example:

    @Override
    public ApplicationManager getApplicationManager() 
    {
       return null;
    }
    getProvisioningConfig()

    Returns the provisioning details, which includes the name of the tenant domain that the device type needs to be registered to and indicates whether the device type is to be shared with all the tenants. true indicates that the device-type should be visible to all tenants and false indicates that it is not visible to other tenants).

    @Override
    public ProvisioningConfig getProvisioningConfig() 
    {
     return new ProvisioningConfig("carbon.super", true);
    }
    getPolicyMonitoringManager()

    Returns an object, which is an implementation of the org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager interface. Example:

    @Override
    public PolicyMonitoringManager getPolicyMonitoringManager() 
    {
      return null;
    }

     

  2. Implement the DeviceManager interface.

    Info from Steve

    Implement the interface DeviceManager for Connected Cup via the org.wso2.carbon.device.mgt.common.DeviceManager in order to implement the getDeviceManager() method that is shown in step 1. The DeviceManager interface will be used for enrolling, disenrolling, activating and deactivating a device.

    1. Create a Database Access Object (DAO) on the ConnectedCupManager interface to manage data source connections.
      Example: 

      @Override
      public boolean updateDeviceInfo(DeviceIdentifier deviceIdentifier, Device device) throws DeviceManagementException {
          boolean status;
          try {
              if (log.isDebugEnabled()) {
                  log.debug(
                      "updating the details of Connected Cup device : " + deviceIdentifier);
              }
              ConnectedCupDAOUtil.beginTransaction();
              status = CONNECTED_CUP_DAO_UTIL.getConnectedCupDeviceDAO().updateDevice(device);
              ConnectedCupDAOUtil.commitTransaction();
          } catch (ConnectedCupDeviceMgtPluginException e) {
              try {
                  ConnectedCupDAOUtil.rollbackTransaction();
              } catch (ConnectedCupDeviceMgtPluginException iotDAOEx) {
                  String msg = "Error occurred while roll back the update device info transaction :" + device.toString();
                  log.warn(msg, iotDAOEx);
              }
              String msg =
                  "Error while updating the Connected Cup device : " + deviceIdentifier;
              log.error(msg, e);
              throw new DeviceManagementException(msg, e);
          }
          return status;
      }
  3. Register the service as an OSGI service by creating the ConnectedCupServiceComponent.java file as shown in the  <IoTS_HOME>/samples/connectedcup/component/plugin/src/main/java/org/coffeeking/connectedcup/plugin/internal directory.

The implemented interface manages the device type data, such as information related to enrollment, status, ownership, claimable, license and tenant configuration. When the OSGI bundle  ConnectedCupServiceComponent is activated, the device type will be registered on WSO2 CDMF. The successfully configured Connected Cup plugin component consists of the the following primary classes:

ClassDescription
ConnectedCupManagerImplements the org.wso2.carbon.device.mgt.common.DeviceManager.
ConnectedCupManagerServiceImplements the DeviceManagementService.
ConnectedCupServiceComponentThe OSGI Service Component that registers the ManagementService.
ConnectedCupDAOAdditionally it consists of the ConnectedCupDAO and the ConnectedCupDAOImp classes that are Data Access specific.
ConnectedCupDAOImp

Writing device type APIs for Connected Cup

The Connected Cup needs to communicate with the user's mobile application that monitors the cup, and send details on the consumer buying patterns and the coffee consumption data to Planetbucks. Therefore, Steve creates APIs for the Connected Cup device to communicate with external devices, the server and the device management console.

For more information, see Writing Device APIs.

You can follow the steps on how Steve wrote APIs for Connected Cup and do the same for your device type:

  1. Create a JAXRS web application for the controller and manager APIs as shown in the <IoTS_HOME>/sample/connectedcup/component/api/src/main/java/org/coffeeking/api directory.

    Info from Steve

    • The controller APIs are used by devices to communicate with the server, for the server to communicate with the devices and to communicate outside of WSO2 IoTS. 

    • The device management APIs are specifically used when carrying out internal functions. They are used for device-management tasks, such as enrolling, disenrolling, updating information and more. 

  2. Annotate the web app with the name and context, so that all the APIs of a device are grouped and can be identified instantly.
    Example: Take a look at the implemented api/ConnectedCupService.java file.

    @SwaggerDefinition(
        info = @Info(
            version = "1.0.0",
            title = "",
            extensions = {
                @Extension(properties = {
                    @ExtensionProperty(name = "name", value = "connectedcup"),
                    @ExtensionProperty(name = "context", value = "/connectedcup"),
                })
            }
        ),
        tags = {
            @Tag(name = "connectedcup", description = "")
        }
    )
    @Scopes(
        scopes = {
            @Scope(
                name = "Enroll device",
                description = "",
                key = "perm:connectedcup:enroll",
                permissions = {
                    "/device-mgt/devices/enroll/connectedcup"
                }
            )
        }
    )
  3. Annotate the APIs using the swagger annotations.  For more information on swagger annotations, see Annotations-1.5.X.
    Example:

    @Path("device/ordercoffee")
    @POST
    @ApiOperation(
        consumes = MediaType.APPLICATION_JSON,
        httpMethod = "POST",
        value = "Order Coffee",
        notes = "",
        response = Response.class,
        tags = "connectedcup",
        extensions = {
            @Extension(properties = {
                @ExtensionProperty(name = SCOPE, value = "perm:connectedcup:enroll")
            })
        }
    )
    Response orderCoffee(@QueryParam("deviceId") String deviceId);
  4. The resources used by external entities can be secured with WSO2 API Manager by including specific XML elements to the respective web.xml file of the web application that implements the APIs.
    Example:

     Click here for to view a configured web.XML file.
    <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
       <display-name>ConnectedCup-Webapp</display-name>
       <servlet>
          <servlet-name>CXFServlet</servlet-name>
          <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
          <load-on-startup>1</load-on-startup>
       </servlet>
       <servlet-mapping>
          <servlet-name>CXFServlet</servlet-name>
          <url-pattern>/*</url-pattern>
       </servlet-mapping>
       <context-param>
          <param-name>isAdminService</param-name>
          <param-value>false</param-value>
       </context-param>
       <context-param>
          <param-name>doAuthentication</param-name>
          <param-value>true</param-value>
       </context-param>
       <context-param>
          <param-name>isSharedWithAllTenants</param-name>
          <param-value>true</param-value>
       </context-param>
       <context-param>
          <param-name>providerTenantDomain</param-name>
          <param-value>carbon.super</param-value>
       </context-param>
       <!--publish to apim-->
       <context-param>
          <param-name>managed-api-enabled</param-name>
          <param-value>true</param-value>
       </context-param>
       <context-param>
          <param-name>managed-api-owner</param-name>
          <param-value>admin</param-value>
       </context-param>
    </web-app>
     Click here for more information on the XML properties

    JAXRS web applications are used to create and configure APIs. By default, a web application has a web.xml file. WSO2 IoTS secures the APIs through web.xml by configuring it as shown below:

    XML PropertyDescription
    doAuthentication
    APIs can be unauthenticated or authenticated where each API header will be validated to see if it meets the required conditions. If it's configured as true, the API is authenticated, and if it's configured as false, the API is unauthenticated.

    isSharedWithAllTenants

    Optional. If this tag is included in the web.xml file and is configured as true, it indicates that the APIs are shared with all the tenants. If it's configured as false, it indicates that the APIs are restricted to the tenant that created them.

    If this tag is not present in the web.xml file, the default action would be to share the APIs with all the tenants.

    managed-api-enabled
    WSO2 IoTS uses WSO2 API manager to secure APIs. The controller APIs are exposed to the public, whereas device management APIs are not exposed to the public as they are used to communicate internally. The API Manager has a gateway to handle the calls made to an API, and each time a specific API is called a token is generated. The following values can be assigned to the XML property managed-api-enabled:
    • true - The APIs in the respective JAXRS web application are secured via the API Manager. There will be a token issued to secure the API each time the API is called via the API Manager gateway.

      If managed-api-enabled is true, the APIs in the web application are identified as controller APIs in the context of WSO2 IoTS.

    • false -  The APIs in the respective JAXRS web application is not secured via the API Manager.

      If managed-api-enabled is false, the APIs in the web application are identified as device manager APIs in the context of WSO2 IoTS.

    For example of setting managed-api-enabled to false:

    <context-param>
       <param-name>managed-api-enabled</param-name>
       <param-value>false</param-value>
    </context-param>

Writing batch analytics for Connected Cup

Steve needs to gather data on the level of coffee in the cup and its temperature. Using the coffee level Planetbucks is able to know, if the customer requires a refill and promote the customer to order again. Knowing the temperature of the coffee will help the customer heat up the coffee via the Connected Cup. In this step let's take a look at how Steve uses the coffee level sensor to gather the data of the coffee level.

Each sensor needs to have a set of Data Analytic Server (DAS) artifacts. For more information, see Writing Analytics.

The sample DAS Capp folder structure to get the coffee level in the cup is shown below. The DAS Capp defines the artifacts, and ships them to DAS as an archive. 

  • receivers - Includes the content to bind the streams to the stores.

  • stores - Includes the schema to persist and format the streaming data.

  • streams - Includes the content to define the data format of the streaming data.

  • scripts - Includes the analytics script used to summarize data streams.

Follow the step on how Steve wrote batch analytics for the coffee level in the cup:

  1. Create the event stream artifact as shown in the <IoTS_HOME>/samples/connectedcup/component/analytics/src/main/resources/carbonapps
    /coffee_level/coffee_level_stream
     directory.
    1. Create the stream format JSON file using a unique name, such as org.wso2.iot.devices.coffeelevel_1.0.0, to stream the coffee level data.
      The stream JSON definition consists of 2 main sections named metaData and payloadData.

      Info from Steve

      Make sure to only modify the payloadData as it contains the data that will be published. If you wish to customize the metaData, you need to update the sparkscript too. The spark scripts are configured in step 4.

      Example: 

      Stream JSON format to gather data of the coffee level
      {
        "name": "org.wso2.iot.devices.coffeelevel",
        "version": "1.0.0",
        "nickName": "CoffeeLevel",
        "description": "Coffee Level data received from the Device",
        "metaData": [
          {"name":"owner","type":"STRING"},     
          {"name":"deviceType","type":"STRING"},
          {"name":"deviceId","type":"STRING"},  
          {"name":"time","type":"LONG"}
        ],
        "payloadData": [
          {
            "name": "coffeelevel","type": "FLOAT"
          }
        ]
      }
    2. Define the event stream as an artifact by configuring the artifact.xml file.

      Info from Steve

      The artifact.xml is added to notify WSO2 IoTS to refer the org.wso2.iot.devices.coffeelevel_1.0.0.json file for event streaming.

      Example:

      Sample artifact.xml
      <artifact name="coffee_level_stream" version="1.0.0" type="event/stream" serverRole="DataAnalyticsServer">
         <file>org.wso2.iot.devices.coffeelevel_1.0.0.json</file>
      </artifact>
  2. Create the event store artifact as shown in the <IoTS_HOME>/samples/connectedcup/component/analytics /src/main/resources/carbonapps
    /coffee_level/coffee_level_store
     directory.
    1. Create an XML file containing the details on how to persist data to the internal DAS tables.
      The <ColumnDefinition> tags are used to define the table definitions for the stream. The <Type> tag of the column supports primitive data types and a special data type named facet.  

      Info from Steve

      Facet is an attribute of indexed records, which is used to classify the records by the attribute value. For more information, see the WSO2 DAS docs on facets.

      Example:

      Sample XML configured to persist data
      <EventStoreConfiguration>
          <Source>
              <StreamId>org.wso2.iot.devices.coffeelevel:1.0.0</StreamId>
          </Source>
          <RecordStoreName>EVENT_STORE</RecordStoreName>
          <TableSchema>
            <ColumnDefinition>
               <Name>meta_owner</Name>
               <EnableIndexing>true</EnableIndexing>
               <IsPrimaryKey>true</IsPrimaryKey>
               <EnableScoreParam>false</EnableScoreParam>
               <Type>STRING</Type>
            </ColumnDefinition>
            <ColumnDefinition>
               <Name>meta_deviceType</Name>
               <EnableIndexing>true</EnableIndexing>
               <IsPrimaryKey>true</IsPrimaryKey>
               <EnableScoreParam>false</EnableScoreParam>
               <Type>STRING</Type>
            </ColumnDefinition>
            <ColumnDefinition>
               <Name>meta_deviceId</Name>
               <EnableIndexing>true</EnableIndexing>
               <IsPrimaryKey>true</IsPrimaryKey>
               <EnableScoreParam>false</EnableScoreParam>
               <Type>STRING</Type>
            </ColumnDefinition>
            <ColumnDefinition>
               <Name>meta_time</Name>
               <EnableIndexing>true</EnableIndexing>
               <IsPrimaryKey>true</IsPrimaryKey>
               <EnableScoreParam>false</EnableScoreParam>
               <Type>LONG</Type>
            </ColumnDefinition>
            <ColumnDefinition>
               <Name>coffeelevel</Name>
               <EnableIndexing>false</EnableIndexing>
               <IsPrimaryKey>false</IsPrimaryKey>
               <EnableScoreParam>false</EnableScoreParam>
               <Type>FLOAT</Type>
            </ColumnDefinition>
          </TableSchema>
      </EventStoreConfiguration>
    2. Define the event store as an artifact by configuring the artifact.xml file.

      Info from Steve

      The artifact.xml is added to notify the IoT Server to refer the org_wso2_iot_devices_coffeelevel.xml file for event storing.

      Example:

      <artifact name="coffee_level_store" version="1.0.0" type="analytics/eventstore" serverRole="DataAnalyticsServer">
          <file>org_wso2_iot_devices_coffeelevel.xml</file>
      </artifact>
  3. Creating the event receiver artifact as shown in the <IoTS_HOME>/samples/connectedcup/component/analytics /src/main/resources/carbonapps
    /coffee_level/coffee_level_receiver
     directory.
    1. Create an XML file containing the details on binding the stream to the table using receivers.  

      Example:

      <eventReceiver name="coffee_level_receiver" statistics="disable" trace="disable" xmlns="http://wso2.org/carbon/eventreceiver">
          <from eventAdapterType="wso2event">
              <property name="events.duplicated.in.cluster">false</property>
          </from>
          <mapping customMapping="disable" type="wso2event"/>
          <to streamName="org.wso2.iot.devices.coffeelevel" version="1.0.0"/>
      </eventReceiver>
    2. Define the event receiver as an artifact by configuring the artifact.xml file.

      Info from Steve

      The artifact.xml is added to notify the IoT Server to refer the coffee_level_receiver.xml file for event receiving.

      Example:

      <artifact name="coffee_level_receiver" version="1.0.0" type="event/receiver" serverRole="DataAnalyticsServer">
          <file>coffee_level_receiver.xml</file>
      </artifact>
  4. Create an analytics script artifact as shown in the <IoTS_HOME>/samples/connectedcup/component/analytics /src/main/resources/carbonapps
    /coffee_level/coffee_level_script
     directory.

    1. Create a Spark script to correctly summarize the content.
      Example:

      <Analytics>
         <Name>coffee_level_script</Name>
         <Script>CREATE TEMPORARY TABLE DeviceCoffeeLevelData USING CarbonAnalytics OPTIONS(tableName "ORG_WSO2_IOT_DEVICES_COFFEELEVEL");
      
              CREATE TEMPORARY TABLE DeviceCoffeeLevelSummaryData USING CarbonAnalytics OPTIONS (tableName "DEVICE_COFFEELEVEL_SUMMARY", schema "coffeelevel FLOAT, deviceType STRING -i, deviceId STRING -i, owner STRING -i, time LONG -i",primaryKeys "deviceType, deviceId, owner, time");
      
              insert into table DeviceCoffeeLevelSummaryData select coffeelevel, meta_deviceType as deviceType, meta_deviceId as deviceId, meta_owner as owner, cast(meta_time/1000 as BIGINT)as time from DeviceCoffeeLevelData group by coffeelevel, meta_deviceType, meta_deviceId, meta_owner, cast(meta_time/1000 as BIGINT);</Script>
         <CronExpression>0 0/5 * * * ?</CronExpression>
      </Analytics>
    2. Define the analytics script as an artifact by configuring the artifact.xml file.

      <artifact name="coffee_level_script" version="1.0.0" type="analytics/spark" serverRole="DataAnalyticsServer">
          <file>coffee_level_script.xml</file>
      </artifact>
  5. Create a deployable artifcat to create an archive of all the artifacts created above as shown in the <IoTS_HOME>/samples/connectedcup/component/analytics /src/main/resources/carbonapps
    /coffee-level/artifact.xml
     file.

    Example:

    <artifacts>
        <artifact name="coffee_level" version="1.0.0" type="carbon/application">
          <dependency artifact="coffee_level_stream" version="1.0.0" include="true" serverRole="DataAnalyticsServer"/>
          <dependency artifact="coffee_level_store" version="1.0.0" include="true" serverRole="DataAnalyticsServer"/>
          <dependency artifact="coffee_level_receiver" version="1.0.0" include="true" serverRole="DataAnalyticsServer"/>
          <dependency artifact="coffee_level_script" version="1.0.0" include="true" serverRole="DataAnalyticsServer"/>
        </artifact>
    </artifacts>
  6. Configure the build.xml for analytics as shown in the <IoTS_HOME>/samples/connectedcup/component/analytics directory.

    Info from Steve

    The build.xml file is used to create a normal .zip file with .car extension. The zip achieve contains all the artifacts and the artifacts.xml at the root level of the zip

    Example: 

    <project name="create-connectedcup-capps" default="zip" basedir=".">
       <property name="project-name" value="${ant.project.name}" />
       <property name="target-dir" value="target/carbonapps" />
       <property name="src-dir" value="src/main/resources/carbonapps" />
       <property name="ConnectedCup_dir" value="connected_cup" />
       <property name="CoffeeLevel_Sensor_dir" value="coffee_level" />
       <target name="clean">
          <delete dir="${target-dir}" />
       </target>
       <target name="zip" depends="clean">
          <mkdir dir="${target-dir}" />
          <zip destfile="${target-dir}/${ConnectedCup_dir}.car">
             <zipfileset dir="${src-dir}/${ConnectedCup_dir}" />
          </zip>
          <zip destfile="${target-dir}/${CoffeeLevel_Sensor_dir}.car">
             <zipfileset dir="${src-dir}/${CoffeeLevel_Sensor_dir}" />
          </zip>
       </target>
    </project>

Writing UI extensions for Connected Cup

Steve then looks at developing the User Interface. The UI of WSO2 IoTS is built using the WSO2 Unified UI Framework (UUF) allowing you to create extensions for customized UI developments.

For more information, see WSO2 Unified UI Framework.

  1. Write the device type view using the cdmf.unit.device.type.connectedcup.type-view unit as shown in the <IoTS_HOME>/samples/connectedcup/ui
    /src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.connectedcup.type-view
    directory. You need to explain the device type and its functionality, and t he steps to register an instance of the device in this jaggery application page.

    Info from Steve

    This unit gets fetched when you click on a specific device type from the device-type-listings page.

  2. Write the device details UI using the  cdmf.unit.device.type.connectedcup.device-view unit as shown in the <IoTS_HOME>/samples/connectedcup/ui
    /src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.connectedcup.device-view
     directory.

    Info from Steve

    • This unit that gets fetched when an end-user clicks on a specific instance of a device-type that he/she has already registered to.
    • You need to include the real time analytics UI unit when writing this UI init.

  3. Write the UI to represent the real time data received from the device using the cdmf.unit.device.type.connectedcup.realtime.analytics-view unit as shown in the  <IoTS_HOME>/samples/connectedcup/ui/src /main/resources/jaggeryapps/devicemgt/app/units
    /cdmf.unit.device.type.connectedcup.realtime.analytics-view
    directory.

  4. Write the UI to represent the historical data received from the device using the cdmf.unit.device.type.connectedcup.analytics-view unit as shown in the <IoTS_HOME>/samples/connectedcup/ui/src/main/resources/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.connectedcup.analytics-view directory.

Creating the Carbon feature for Connected Cup

Steve then identifies that WSO2 IoTS is a collection of Carbon components. It is developed by plugging various Carbon components that provide different features. Therefore, he follow the steps given below to convert the configured device type to a feature. Steve identifies that the following folder structure has to be maintained to create the feature as shown in the <IoTS_HOME>/samples/feature directory.

  1. Create and configure the agent.
    1. Define the device configurations in the /agent/deviceConfig.properties file as shown below:

      Info from steve

      The properties in the file will be replaced with the related information when the agent is being downloaded so that the information can be used to communicate with the IoT Server and the agent.

      owner=${DEVICE_OWNER}
      deviceId=${DEVICE_ID}
      device-name=${DEVICE_NAME}
      controller-context=/${deviceType}/controller
      mqtt-ep=${MQTT_EP}
      auth-method=token
      auth-token=${DEVICE_TOKEN}
      refresh-token=${DEVICE_REFRESH_TOKEN}
      push-interval=15
    2. Create the /agent/sketch.properties file. It contains the information for the IoT Server to find the agent template and the name of the zip file.

      templates=deviceConfig.properties
      zipfilename=connectedCup.zip
  2. Define the database scripts in the <IoTS_HOME>/samples/connectedcup/feature/connectedcup-feature/src/main/resources/datasources folder having the name in the <DEVICE_TYPE>- datasources.xml format.
    Example: connectedCup -datasources.xml file.

    <datasources-configuration xmlns:svns="http://org.wso2.securevault/configuration">
       <providers>
          <provider>org.wso2.carbon.ndatasource.rdbms.RDBMSDataSourceReader</provider>
       </providers>
       <datasources>
          <datasource>
             <name>ConnectedCupDM_DB</name>
             <description>The datasource used for the Connected Cup database</description>
             <jndiConfig>
                <name>jdbc/ConnectedCupDM_DB</name>
             </jndiConfig>
             <definition type="RDBMS">
                <configuration>
                   <url>jdbc:h2:repository/database/ConnectedCupDM_DB;DB_CLOSE_ON_EXIT=FALSE</url>
                   <username>wso2carbon</username>
                   <password>wso2carbon</password>
                   <driverClassName>org.h2.Driver</driverClassName>
                   <maxActive>50</maxActive>
                   <maxWait>60000</maxWait>
                   <testOnBorrow>true</testOnBorrow>
                   <validationQuery>SELECT 1</validationQuery>
                   <validationInterval>30000</validationInterval>
                </configuration>
             </definition>
          </datasource>
       </datasources>
    </datasources-configuration>
  3. Create the database scripts in the <IoTS_HOME>/samples/connectedcup/feature/connectedcup-feature/src/main/resources/dbscripts folder.
    A sample implementation of the database script is shown below, you will need to customize it to suite your requirement.

    -- -----------------------------------------------------
    -- Table `CONNECTED_CUP_DEVICE`
    -- -----------------------------------------------------
    CREATE TABLE IF NOT EXISTS `CONNECTED_CUP_DEVICE` (
      `CONNECTED_CUP_DEVICE_ID` VARCHAR(45) NOT NULL ,
      `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL,
      PRIMARY KEY (`CONNECTED_CUP_DEVICE_ID`) ); 
  4. Create the pom.xml file to create the device type as a feature in the P2 repository as shown in the <IoTS_HOME>/samples/connectedcup/feature/connectedcup-feature directory. The file contains information on the device type and configuration details used by Maven to build the feature.
    Example: 
    1. Include a task to create the databases based on the database scripts created in step 1, in the P2 repository.
      Example:

      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-antrun-plugin</artifactId>
         <executions>
            <execution>
               <!-- Creating Connected Cup Plugin Management schema -->
               <id>create-connected-cup-plugin-mgt-schema</id>
               <phase>package</phase>
               <goals>
                  <goal>run</goal>
               </goals>
               <configuration>
                  <tasks>
                     <property name="db.dir" value="target/maven-shared-archive-resources/database" />
                     <property name="userid" value="wso2carbon" />
                     <property name="password" value="wso2carbon" />
                     <property name="dbURL" value="jdbc:h2:file:${basedir}/${db.dir}/ConnectedCupDM_DB;DB_CLOSE_ON_EXIT=FALSE" />
                     <mkdir dir="${basedir}/${db.dir}" />
                     <sql driver="org.h2.Driver" url="${dbURL}" userid="${userid}" password="${password}" autocommit="true" onerror="continue">
                        <classpath refid="maven.dependency.classpath" />
                        <classpath refid="maven.compile.classpath" />
                        <classpath refid="maven.runtime.classpath" />
                        <fileset file="${basedir}/src/main/resources/dbscripts/h2.sql" />
                     </sql>
                  </tasks>
               </configuration>
            </execution>
         </executions>
      </plugin>
    2. Define a task to copy the JAXRS web application implemented for the controller and device manager APIs to the P2 repository.
      Example:

      <execution>
         <id>copy-jaxrs-war</id>
         <phase>package</phase>
         <goals>
            <goal>copy</goal>
         </goals>
         <configuration>
            <artifactItems>
               <artifactItem>
                  <groupId>org.coffeeking</groupId>
                  <artifactId>org.coffeeking.connectedcup.api</artifactId>
                  <type>war</type>
                  <overWrite>true</overWrite>
                  <outputDirectory>${project.build.directory}/maven-shared-archive-resources/webapps/</outputDirectory>
                  <destFileName>connectedcup.war</destFileName>
               </artifactItem>
               <artifactItem>
                  <groupId>org.coffeeking</groupId>
                  <artifactId>org.coffeeking.connectedcup.agent</artifactId>
                  <type>war</type>
                  <overWrite>true</overWrite>
                  <outputDirectory>${project.build.directory}/maven-shared-archive-resources/webapps/</outputDirectory>
                  <destFileName>connected-cup-agent.war</destFileName>
               </artifactItem>
            </artifactItems>
         </configuration>
      </execution>
    3. Optionally, if your device type includes a device agent, define a task to copy the respective JAXRS web application to the P2 repository.
      Example:

      <execution>
         <id>copy-jaxrs-agent-war</id>
         <phase>package</phase>
         <goals>
            <goal>copy</goal>
         </goals>
         <configuration>
            <artifactItems>
               <artifactItem>
                  <groupId>org.wso2.carbon.devicemgt-plugins</groupId>
                  <artifactId>org.coffeeking.agent</artifactId>
                  <type>war</type>
                  <overWrite>true</overWrite>
                  <outputDirectory>${project.build.directory}/maven-shared-archive-resources/webapps/</outputDirectory>
                  <destFileName>connected-cup-agent.war</destFileName>
               </artifactItem>
            </artifactItems>
         </configuration>
      </execution>
    4. Define a task to create the main feature plugin in the P2 repository.
      Example:

      <plugin>
         <groupId>org.wso2.maven</groupId>
         <artifactId>carbon-p2-plugin</artifactId>
         <executions>
            <execution>
               <id>p2-feature-generation</id>
               <phase>package</phase>
               <goals>
                  <goal>p2-feature-gen</goal>
               </goals>
               <configuration>
                  <id>org.coffeeking.connectedcup</id>
                  <propertiesFile>../../../features/etc/feature.properties</propertiesFile>
                  <adviceFile>
                     <properties>
                        <propertyDef>org.wso2.carbon.p2.category.type:server</propertyDef>
                        <propertyDef>org.eclipse.equinox.p2.type.group:true</propertyDef>
                     </properties>
                  </adviceFile>
                  <bundles>
                     <bundleDef>org.coffeeking:org.coffeeking.connectedcup.plugin:${wso2.iot.version}</bundleDef>
                  </bundles>
                  <importFeatures>
                     <importFeatureDef>org.wso2.carbon.core.server:${carbon.kernel.version}</importFeatureDef>
                     <importFeatureDef>org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version}</importFeatureDef>
                  </importFeatures>
               </configuration>
            </execution>
         </executions>
      </plugin>
    5. Define a task to copy the carbonapps and jaggeryapps to the P2 repository.
      Example:

      <execution>
         <id>unpack</id>
         <phase>package</phase>
         <goals>
            <goal>unpack</goal>
         </goals>
         <configuration>
            <artifactItems>
               <artifactItem>
                  <groupId>org.wso2.carbon.devicemgt-plugins</groupId>
                  <artifactId>org.coffeeking.connectedcup.analytics</artifactId>
                  <version>${project.version}</version>
                  <type>zip</type>
                  <overWrite>true</overWrite>
                  <outputDirectory>${project.build.directory}/maven-shared-archive-resources/carbonapps</outputDirectory>
                  <includes>*/</includes>
               </artifactItem>
               <artifactItem>
                  <groupId>org.wso2.carbon.devicemgt-plugins</groupId>
                  <artifactId>org.coffeeking.connectedcup.ui</artifactId>
                  <version>${project.version}</version>
                  <type>zip</type>
                  <overWrite>true</overWrite>
                  <outputDirectory>${project.build.directory}/maven-shared-archive-resources/jaggeryapps/devicemgt
                  </outputDirectory>
                  <includes>*/</includes>
               </artifactItem>
            </artifactItems>
         </configuration>
      </execution>
  5. Create the p2.inf file. It contains the details on copying the files from the P2 repository to the WSO2 IoTS pack.
    Example: A configured p2.inf file.

    instructions.configure = \
    org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../conf/device-types/);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/configs/,target:${installFolder}/../../conf/device-types/,overwrite:true);\
    org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\
    org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/carbonapps/);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/carbonapps/,target:${installFolder}/../../deployment/server/carbonapps/,overwrite:true);\
    org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/);\
    org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/connectedcup/);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/agent/,target:${installFolder}/../../resources/sketches/connectedcup/,overwrite:true);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/dbscripts/,target:${installFolder}/../../../dbscripts/cdm/plugins/connectedcup,overwrite:true);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/datasources/,target:${installFolder}/../../conf/datasources/,overwrite:true);\
    org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/jaggeryapps/);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\
    org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../database/);\
    org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.coffeeking.connectedcup_${feature.version}/database/,target:${installFolder}/../../database/,overwrite:true);\

    For more information on the P2 touch point commands, see provisioning actions and touch points.

  6. Configure the samples-deployer.xml file as shown in the <IoTS_HOME>/samples-deployer.xml.

    Info from Steve

    I am using the the samples-deployer.xml file in this use case as this is a sample scenario. When creating your device type, you need add the content in this step to the <IoT_HOME>/plugins/device-deployer.xml file.

     

    1. Add the new module under the <modules> tag.
      Example:

      <modules>
         <module>samples/connectedcup</module>
      </modules>
    2. Add the device type feature under the <featureArtifacts> tag.

      <featureArtifactDef>
         org.coffeeking:org.coffeeking.connectedcup.feature:1.0.0-SNAPSHOT
      </featureArtifactDef>
    3. Add the device type feature group under the <features> tag.

      <features>
         <feature>
            <id>org.coffeeking.connectedcup.feature.group</id>
            <version>1.0.0-SNAPSHOT</version>
         </feature>
      </features>

Starting Connected Cup

It's finally time to rejoice! Steve is successful in making the Connected Cup and WSO2 IoT Server to work together. He then let's Amy run the Connected and try it out by following the steps given below.

Stop the WSO2 IoT Server if you have started it previously. You need to stop all the three profiles, i.e, WSO2 Message Broker, WSO2 Connected Device Management Framework (WSO2 CDMF) and WSO2 Data Analytics Server profiles, to stop WSO2 IoTS.

  1. Build the Connected Cup device type.

    cd <IoT_HOME>/samples/connectedcup
    mvn clean install
  2. Run the samples-deployer.xml file.

    cd <IoT_HOME>/samples
    mvn clean install -f samples-deployer.xml
  3. Run the device-deployer.xml file.

    You can skip this step if you have already run this file when trying out the WSO2 IoTS Quick Start Guide or the Tutorials.

    cd <IoT_HOME>/plugins
    mvn clean install -f device-deployer.xml
  4. Start or restart WSO2 IoTS.

     Click here for more information.
  5. Access the device management console and log in using admin as both the username and password.
    Example: https://localhost:9443/devicemgt

    For more information, see accessing the device management console.

    You will see the connected cup device in the device page.

  6. Click Try Out next to Connected Cup and create an instance.
  7. Try out the Connected Cup device type.

Amy is over joyed with the new Connected Cup and the software platform used (WSO2 IoT Server). When she introduces the Connected Cup to the Planetbucks top management. They strongly believe that it would give them a competitive advantage in the market place. 

What's next?

Are you planning on writing your own device? If yes, the following sections will guide you on how to create your own device type.

com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links2' is unknown.