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

Writing the Device Feature

A collection of Carbon components are required to create a new device type in WSO2 IoT Server. It is developed simply by plugging various Carbon components that provide different features. The following folder structure is recommended to create the feature, but you are able to customize it to suit your requirement.

Example: The folder structure of the Raspberry Pi plugin that is in the <CARBON_DEVICE_MGT_PLUGINS>/features directory.

Before you begin

  1. Download WSO2 IoT Server.

  2. Clone and build the WSO2 Carbon Device Management Plugins repository:

    • Clone the WSO2 Carbon Device Management Plugins repository. It will be referred to as <CARBON_DEVICE_MGT_PLUGINS> throughout this document.

      git clone https://github.com/wso2/carbon-device-mgt-plugins.git
    • Build the repo you just cloned.

      cd <CARBON_DEVICE_MGT_PLUGINS>
      mvn clean install

Let's take a look at how each directory contributes to your device type and why it's used:

Agent directory

When enrolling a device with WSO2 IoT Server you require agents to communicate with the device and the server. You can configure the agent and host it on a separate location or have it within WSO2 IoT Server. If you are configuring the agent via WSO2 IoT Server all the agent related files can be included in this directory. 

This directory is not mandatory. Create this directory only if your device type requires an agent to communicate with the device and the server.

More Inofrmation

For more information, see Writing Device Agents.

Each device type has its own enrollment mechanism. Take a look at the different ways of enrolling devices:

  • Enrolling via a Software Development Kit (SDK).
    Example: This mechanism is used when enrolling an Android device with WSO2 IoTS.
  • Enrolling a device my installing a sketch or an agent on a device.
    Example: Enrolling a Raspberry Pi or Arduino device

 Example: Configuring an agent for a Raspberry Pi device
  1. Define the device configurations in the deviceConfig.properties as shown below:

    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.

    Example: Configurations for Raspberry Pi

    [Device-Configurations]
    server-name=${SERVER_NAME}
    owner=${DEVICE_OWNER}
    deviceId=${DEVICE_ID}
    device-name=${DEVICE_NAME}
    controller-context=/raspberrypi/controller
    mqtt-sub-topic=${SERVER_NAME}/{owner}/raspberrypi/{deviceId}
    mqtt-pub-topic=${SERVER_NAME}/{owner}/raspberrypi/{deviceId}/publisher
    https-ep=${HTTPS_EP}
    http-ep=${HTTP_EP}
    apim-ep=${APIM_EP}
    mqtt-ep=${MQTT_EP}
    xmpp-ep=${XMPP_EP}
    auth-method=token
    auth-token=${DEVICE_TOKEN}
    refresh-token=${DEVICE_REFRESH_TOKEN}
    push-interval=15
  2. Create the sketch.properties. It contains the information for the IoT Server to find the agent template that was explained in step 1 and where to get the zip file when a user clicks download agent.

    templates=deviceConfig.properties
    zipfilename=RaspberryPiAgent.zip
  3. You might require scripts to start the downloaded agent. Add all the configurations and files required for the agent in this directory.

Please note that this is just an example. You can configure your agent anyway your prefer. Take a look at the Arduino agent directory to see another way of how the agent is configured.

Datasources directory

A datasource provides the information that is required for a server to connect to a database or to an external data store.

For more information, see Configuring the master-datasources.xml.

 Example: raspberrypi-datasources.xml file
<?xml version="1.0" encoding="UTF-8"?>
<datasources-configuration xmlns:svns="http://org.wso2.securevault/configuration">
   <providers>
      <provider>org.wso2.carbon.ndatasource.rdbms.RDBMSDataSourceReader</provider>
   </providers>
   <datasources>
      <datasource>
         <name>RaspberryPi_DB</name>
         <description>The datasource used for the RaspberryPi database</description>
         <jndiConfig>
            <name>jdbc/RaspberryPiDM_DB</name>
         </jndiConfig>
         <definition type="RDBMS">
            <configuration>
               <url>jdbc:h2:repository/database/RaspberryPiDM_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>

DB scripts directory

WSO2 IoTS runs on top of WSO2 CDMF. Each device type that you configure to enroll with WSO2 IoTS will have details specific to them. Therefore you need to create the required database scripts in the dbscripts folder for these details to be passed into CDMF to create the respective databases in CDMF.

When a plugin is created it will get access to the following common APIs that is made available via WSO2 CDMF. These APIs too will refer to the database to know which fields need to be updated when one of the respective APIs are called. The APIs are:

  • Adding a device.
  • Updating the device details.
  • Getting the device.
  • Getting all the devices in WSO2 IoTS.
  • Removing the device.
 Click here for a sample implementation of the Raspberry Pi H2 database script.
-- -----------------------------------------------------
-- Table `RASPBERRYPI_DEVICE`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `RASPBERRYPI_DEVICE` (
  `RASPBERRYPI_DEVICE_ID` VARCHAR(45) NOT NULL ,
  `DEVICE_NAME` VARCHAR(100) NULL DEFAULT NULL,
  PRIMARY KEY (`RASPBERRYPI_DEVICE_ID`) );

Device types

All device types generally have common elements, such as specific attributes, feature management methods, and transport sender mechanisms. WSO2 IoTS identified these common areas and created a template that includes all these details. Using this template you can create your own device plugin. 

For more information, see Writing Device Type via the Template. 
If your device requires special functions and need to be customized to meet a given requirement, see Writing Device Plugins via Java Code for more information.

 Click here to see the Raspberry Pi plugin that's configured using the template.
<DeviceTypeConfiguration name="raspberrypi">
    <Features>
        <Feature code="bulb">
            <Name>Control Bulb</Name>
            <Description>Control Bulb on Raspberrypi</Description>
            <Operation context="/raspberrypi/device/{deviceId}/bulb" method="POST">
                <QueryParameters>
                    <Parameter>state</Parameter>
                </QueryParameters>
            </Operation>
        </Feature>
    </Features>
    <ProvisioningConfig>
        <SharedWithAllTenants>false</SharedWithAllTenants>
    </ProvisioningConfig>
    <PushNotificationProvider type="MQTT">
        <FileBasedProperties>true</FileBasedProperties>
        <!--if file based properties is set to false then the configuration will be picked from platform configuration-->
        <ConfigProperties>
            <Property Name="mqtt.adapter.name">raspberrypi.mqtt.adapter</Property>
            <Property Name="url">tcp://localhost:1886</Property>
            <Property Name="username">admin</Property>
            <Property Name="dcrUrl">https://localhost:9443/dynamic-client-web/register</Property>
            <Property Name="qos">0</Property>
            <Property Name="scopes"/>
            <Property Name="clearSession">true</Property>
        </ConfigProperties>
    </PushNotificationProvider>
    <License>
        <Language>en_US</Language>
        <Version>1.0.0</Version>
        <Text>This is license text</Text>
    </License>
</DeviceTypeConfiguration>


p2.inf file

The p2.inf file contains the details on copying the files from the P2 repository to the WSO2 IoTS pack. 

 Click here to see a configured p2.inf file.
instructions.configure = \
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/webapps/,target:${installFolder}/../../deployment/server/webapps/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../resources/sketches/raspberrypi/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/agent/,target:${installFolder}/../../resources/sketches/raspberrypi/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/dbscripts/,target:${installFolder}/../../../dbscripts/cdm/plugins/raspberrypi,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.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/jaggeryapps/,target:${installFolder}/../../deployment/server/jaggeryapps/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/datasources/,target:${installFolder}/../../conf/datasources/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../database/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/database/,target:${installFolder}/../../database/,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.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/carbonapps/,target:${installFolder}/../../deployment/server/carbonapps/,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/devicetypes/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.device.mgt.iot.raspberrypi_${feature.version}/devicetypes/,target:${installFolder}/../../deployment/server/devicetypes/,overwrite:true);\


instructions.unconfigure = \
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/raspberrypi.war);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/webapps/raspberrypi);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../../dbscripts/cdm/plugins/raspberrypi);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../resources/sketches/raspberrypi);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../conf/datasources/raspberrypi-datasources.xml);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../database/RaspberryPiDM_DB.h2.db);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.device-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.type-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.analytics-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.realtime.analytics-view);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/jaggeryapps/devicemgt/app/units/cdmf.unit.device.type.raspberrypi.platform.configuration);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/carbonapps/raspberrypi.car);\
org.eclipse.equinox.p2.touchpoint.natives.remove(path:${installFolder}/../../deployment/server/devicetypes/raspberrypi.xml);\
For more information on the P2 touch point commands, see provisioning actions and touch points.

pom.xml file

Create the pom.xml file to package the new feature and create the device type as a feature in the P2 repository. The file contains information on the device type and configuration details used by Maven to build the feature. 

Example: The fully configured pom.xml file for the Raspberry Pi sample here.

To get a better understanding on what was explained up to this point, see Developing a Carbon Feature. Follow the sample given in this documentation and take a look at Step 3: Packaging the New Feature to know more on how to configure the pom.xml file.

plugins-deployer.xml file

The plugins-deployer.xml contains the information required to create the P2 repository in the device types folder. Configure the <IoT_HOME>/plugins/plugins-deployer.xml file.

  1. Add the device type feature under the <featureArtifacts> tag.

    <featureArtifactDef>
       {groupID}-plugin:{groupID}.{artifactID}.feature:{version}
    </featureArtifactDef>

    Example:

    <featureArtifactDef>
       org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.iot.raspberrypi.feature:${carbon.device.mgt.plugin.version}
    </featureArtifactDef>
  2. Add the device type feature group under the <features> tag.

    <features>
     <feature>
        <id>{groupID}.{artifactID}.feature.group</id>
        <version>{version}</version>
     </feature>
    </features>

    Example:

    <features>
     <feature>
        <id>org.wso2.carbon.device.mgt.iot.raspberrypi.feature.group</id>
        <version>${carbon.device.mgt.plugin.version}</version>
     </feature>
    </features>

What's next?

Now you are done creating the folder structure and creating the respective databases and datasources required for your device type. You can proceed to configure your device type further as explained below:


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