Serial Example

PART 3. ESF Examples
Serial Communication Example

 

Overview

·            Prerequisites

·         Optional Prerequisites

Serial Communication with ESF

·         Hardware Setup

·         Determine Serial Device Nodes

·         Implement the Bundle

·         Deploy the Bundle

·         Validate the Bundle

Cloud Enabled Serial Communication

·         Modify the Code

·         Redeploy the Bundle

·         Sending Messages to the Cloud

·         Receiving Messages from the Cloud

Overview

This section provides an example that shows how to create an ESF bundle that will communicate with a serial device.  In this example, you will communicate with a simple terminal emulator to demonstrate both transmitting and receiving data.  You will learn how to

 

·         Create a plugin that communicates to serial devices

·         Export the bundle

·         Install the bundle on the remote device

·         Test the communication with minicom (where minicom is acting as an attached serial device such as an NFC reader, GPS device, or some other ASCII based communication device)

 

In the second portion of the tutorial, as an optional exercise, you can “cloud-enable” the serial device by extending the bundle to transmit messages from the serial device to the Everyware Cloud, allowing them to be viewed in the Everyware Cloud Console.  You will also implement the CloudClientListener in ESF to receive messages from the Everyware Cloud, allowing them to be sent via the REST API through the cloud to the attached serial device.

 

Prerequisites

·         Setting up ESF Development Environment

·         Hello World Using the ESF Logger

·         Have appropriate hardware available:

o   Use an embedded device running ESF with two serial ports available.
(If the device does not have a serial port, usb to serial adapters can be used.)

o   Ensure minicom is installed on the embedded device.

Optional Prerequisites

·         To communicate serial data through the Everyware Cloud, have your Everyware Cloud account credentials handy.  If you do not have an account, contact your Eurotech sales representative.

·         See Connecting to Everyware Cloud.

 


Serial Communication with ESF

This section of the tutorial covers setting up the hardware, determining serial port device nodes, implementing the basic serial communication bundle, deploying the bundle, and validating its functionality.  After completing this section, you should be able to communicate with any ASCII-based serial device attached to an ESF-enabled embedded gateway.  In this example, we are using ASCII for clarity, but these same techniques can be used to communicate with serial devices that communicate using binary protocols.

 

 

Hardware Setup

Your setup requirements will depend on your hardware platform.  At a minimum, you will need two serial ports with a null modem serial cross-over cable connecting them together. 

 

·         If your platform has integrated serial ports, you only need to connect them using a null modem serial cable. 

·         If you do not have integrated serial ports on your platform, you will need to purchase USB-to-Serial adapters.  It is recommended to use a USB-to-Serial adapter with either the PL-2303 or FTDI chipset, but others may work depending on your hardware platform and underlying Linux support.  Once you have attached these to your device, you can attach the null modem serial cable between the two ports.

 

 

Determining Serial Device Nodes

This step is hardware specific.  If your hardware device has integrated serial ports, contact your hardware device manufacturer or review the documentation to find out how the ports are named in the operating system.  The device identifiers should be similar to the following:

 

/dev/ttySxx

/dev/ttyUSBxx

/dev/ttyACMxx

 

If you are using USB-to-Serial adapters, the associated device nodes are typically allocated dynamically by Linux at insertion time.  In order to determine what they are, run the following command at a terminal on the embedded gateway:

 

 

tail -f /var/log/syslog

 

 

Note: /var/log/syslog may not be the right file depending on your specific Linux implementation.  Other potential log files may be /var/log/kern.log, /var/log/kernel, or /var/log/dmesg.

 

With the above command running, insert your USB-to-Serial adapter.  You should see output similar to the following:

 

 

root@localhost:/root> tail -f /var/log/syslog

Aug 15 18:43:47 localhost kernel: usb 3-2: new full speed USB device using uhci_hcd and address 3

Aug 15 18:43:47 localhost kernel: pl2303 3-2:1.0: pl2303 converter detected

Aug 15 18:43:47 localhost kernel: usb 3-2: pl2303 converter now attached to ttyUSB10

 

 

 

In this example, our device is a pl2303 compatible device and was allocated a device node of “/dev/ttyUSB10”.  Your results may be different, but the important thing is to identify the “tty” device that was allocated.  For the rest of this tutorial, this device will be referenced as [device_node_1], which in this example is equal to /dev/ttyUSB10.  It is also important to note that these values are dynamic.  From one boot to the next and one insertion to the next, these values may change.  Keep this in mind as you are developing.  To stop ‘tail’ from running in your console, escape with ‘<CTRL> c’.

 

If you are using two USB-to-Serial adapters, repeat the above procedure for the second serial port.  The resulting device node will be referred to as [device_node_2].

 

 

Implementing the Bundle

Now that you have two serial ports connected to each other, you are ready to implement the code.  You will use the same general method for implementing the bundle as in Hello World Using the ESF Logger, but the actual code in this example will have the following differences from the Hello World example:

 

·         Name the new Plug-in Project “com.eurotech.example.serial” instead of “com.eurotech.example.hello_osgi”

·         Create a class named “SerialExample” in the package com.eurtoech.example.serial

·         In the Automated Management of Dependencies section of the Dependencies tab of the MANIFEST.MF include the following bundles:

o   com.eurotech.framework.api

o   slf4j.api

o   org.eclipse.osgi

o   org.eclipse.osgi.services

o   org.eclipse.osgi.util

 

Now you need to write the source code.  Below are the four files that need to be implemented:

 

·         META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and it’s dependencies

·         OSGI-INF/component.xml - declarative services definition describing what services are exposed by and consumed by this bundle

·         OSGI-INF/metatype/com.eurotech.example.serial.SerialExample.xml - configuration description of the bundle and its parameters, types, and defaults

·         com.eurotech.example.serial.SerialExample.java - main implementation class

 

The META-INF/MANIFEST.MF file should look as follows when complete.  Also note whitespace is significant in this file.  Make sure yours matches this file exactly, except that the Execution Environment may be JavaSE-1.6 or JavaSE-1.7 depending on the Java installation of your device.

 

 

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: Serial Example

Bundle-SymbolicName: com.eurotech.example.serial;singleton:=true

Bundle-Version: 1.0.0.qualifier

Bundle-Vendor: EUROTECH

Bundle-RequiredExecutionEnvironment: JavaSE-1.6

Service-Component: OSGI-INF/*.xml

Bundle-ActivationPolicy: lazy

Import-Package: com.eurotech.framework.comm,

 com.eurotech.framework.configuration,

 javax.microedition.io;resolution:=optional,

 org.osgi.service.component;version="1.2.0",

 org.osgi.service.io;version="1.0.0",

 org.slf4j;version="1.6.4"

Require-Bundle: org.eclipse.equinox.io

Bundle-ClassPath: .

 

 

 

The OSGI-INF/component.xml should look as follows when complete.

 

 

<?xml version="1.0" encoding="UTF-8"?>

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"

     name="com.eurotech.example.serial.SerialExample" activate="activate"

     deactivate="deactivate" modified="updated" enabled="true" immediate="true"

     configuration-policy="require">

     <implementation class="com.eurotech.example.serial.SerialExample" />

 

     <!-- If the component is configurable through the ESF ConfigurationService,

           it must expose a Service. -->

     <property name="service.pid" type="String"

           value="com.eurotech.example.serial.SerialExample" />

     <service>

           <provide interface="com.eurotech.example.serial.SerialExample" />

     </service>

 

     <reference bind="setConnectionFactory" cardinality="1..1"

           interface="org.osgi.service.io.ConnectionFactory" name="ConnectionFactory"

           policy="static" unbind="unsetConnectionFactory" />

 

</scr:component>

 

 

 

The OSGI-INF/metatype/com.eurotech.example.serial.SerialExample.xml file should look as follows when complete, with the exception of the “serial.device” parameter.  You should set its “default” property to [device_node_1] that you found earlier in this tutorial.

 

 

<?xml version="1.0" encoding="UTF-8"?>

<MetaData xmlns="http://www.osgi.org/xmlns/metatype/v1.2.0" localization="en_us">

    <OCD id="com.eurotech.example.serial.SerialExample"

         name="SerialExample"

         description="Example of a Configuring ESF Application echoing data read from the serial port.">

       

        <Icon resource="http://sphotos-a.xx.fbcdn.net/hphotos-ash4/p480x480/408247_10151040905591065_1989684710_n.jpg" size="32"/>

       

        <AD id="serial.device" 

            name="serial.device"

            type="String"

            cardinality="0"

            required="false"

            default="/dev/ttyUSB10"

            description="Name of the serial device (e.g. /dev/ttyS0, /dev/ttyACM0, /dev/ttyUSB0)."/> 

 

        <AD id="serial.baudrate" 

            name="serial.baudrate"

            type="String"

            cardinality="0"

            required="true"

            default="9600"

            description="Baudrate."> 

           <Option label="9600" value="9600"/>

           <Option label="19200" value="19200"/>         

           <Option label="38400" value="38400"/>

           <Option label="57600" value="57600"/>

           <Option label="115200" value="115200"/>        

        </AD>

       

        <AD id="serial.data-bits" 

            name="serial.data-bits"

            type="String"

            cardinality="0"

            required="true"

            default="8"

            description="Data bits."> 

           <Option label="7" value="7"/>

           <Option label="8" value="8"/>         

        </AD>

       

        <AD id="serial.parity" 

            name="serial.parity"

            type="String"

            cardinality="0"

            required="true"

            default="none"

            description="Parity."> 

           <Option label="none" value="none"/>

           <Option label="even" value="even"/>

           <Option label="odd" value="odd"/>

        </AD>

 

        <AD id="serial.stop-bits" 

            name="serial.stop-bits"

            type="String"

            cardinality="0"

            required="true"

            default="1"

            description="Stop bits."> 

           <Option label="1" value="1"/>

           <Option label="2" value="2"/>         

        </AD>       

    </OCD>

    <Designate pid="com.eurotech.example.serial.SerialExample">

        <Object ocdref="com.eurotech.example.serial.SerialExample"/>

    </Designate>

</MetaData>

 

 

 

The com.eurotech.example.serial.SerialExample.java file should look as follows when complete.

 

 

package com.eurotech.example.serial;

 

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.Future;

import java.util.concurrent.ScheduledThreadPoolExecutor;

 

import org.osgi.service.component.ComponentContext;

import org.osgi.service.io.ConnectionFactory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

import com.eurotech.framework.comm.CommConnection;

import com.eurotech.framework.comm.CommURI;

import com.eurotech.framework.configuration.ConfigurableComponent;

 

public class SerialExample implements ConfigurableComponent {

 

     private static final Logger s_logger = LoggerFactory.getLogger(SerialExample.class);

 

     private static final String   SERIAL_DEVICE_PROP_NAME= "serial.device";

     private static final String   SERIAL_BAUDRATE_PROP_NAME= "serial.baudrate";

     private static final String   SERIAL_DATA_BITS_PROP_NAME= "serial.data-bits";

     private static final String   SERIAL_PARITY_PROP_NAME= "serial.parity";

     private static final String   SERIAL_STOP_BITS_PROP_NAME= "serial.stop-bits";

 

     private ConnectionFactory m_connectionFactory;

     private CommConnection m_commConnection;

     private InputStream m_commIs;

     private OutputStream m_commOs;

 

     private ScheduledThreadPoolExecutor m_worker;

     private Future<?>           m_handle;

 

     private Map<String, Object> m_properties;

 

     // ----------------------------------------------------------------

     //

     //   Dependencies

     //

     // ----------------------------------------------------------------

 

     public void setConnectionFactory(ConnectionFactory connectionFactory) {

           this.m_connectionFactory = connectionFactory;

     }

 

     public void unsetConnectionFactory(ConnectionFactory connectionFactory) {

           this.m_connectionFactory = null;

     }

 

 

     // ----------------------------------------------------------------

     //

     //   Activation APIs

     //

     // ----------------------------------------------------------------

 

     protected void activate(ComponentContext componentContext, Map<String,Object> properties) {

           s_logger.info("Activating SerialExample...");

           m_worker = new ScheduledThreadPoolExecutor(1);

           m_properties = new HashMap<String, Object>();

           doUpdate(properties);

           s_logger.info("Activating SerialExample... Done.");

     }

 

     protected void deactivate(ComponentContext componentContext) {

           s_logger.info("Deactivating SerialExample...");

 

        // shutting down the worker and cleaning up the properties

        m_handle.cancel(true);

        m_worker.shutdownNow();

       

        //close the serial port

           closePort();

           s_logger.info("Deactivating SerialExample... Done.");

     }

 

     public void updated(Map<String,Object> properties) {

           s_logger.info("Updated SerialExample...");

           doUpdate(properties);

           s_logger.info("Updated SerialExample... Done."); 

     }

 

     // ----------------------------------------------------------------

     //

     //   Private Methods

     //

     // ----------------------------------------------------------------

 

     /**

      * Called after a new set of properties has been configured on the service

      */

     private void doUpdate(Map<String, Object> properties) {

           try {

                for (String s : properties.keySet()) {

                     s_logger.info("Update - "+s+": "+properties.get(s));

                }

               

            // cancel a current worker handle if one if active

            if (m_handle != null) {

                    m_handle.cancel(true);

            }

 

            //close the serial port so it can be reconfigured

                closePort();

 

                //store the properties

                m_properties.clear();

                m_properties.putAll(properties);

 

                //reopen the port with the new configuration

                openPort();

 

                //start the worker thread

                m_handle = m_worker.submit(new Runnable() {

                     @Override

                     public void run() {

                           doSerial();

                     }

                });

           } catch (Throwable t) {

                s_logger.error("Unexpected Throwable", t);

           }

     }

 

     private void openPort() {

           String port = (String) m_properties.get(SERIAL_DEVICE_PROP_NAME);

 

           if (port == null) {

                s_logger.info("Port name not configured");

                return;

           }

 

           int baudRate = Integer.valueOf((String) m_properties.get(SERIAL_BAUDRATE_PROP_NAME));

           int dataBits = Integer.valueOf((String) m_properties.get(SERIAL_DATA_BITS_PROP_NAME));

           int stopBits = Integer.valueOf((String) m_properties.get(SERIAL_STOP_BITS_PROP_NAME));

 

           String sParity = (String) m_properties.get(SERIAL_PARITY_PROP_NAME);

 

           int parity = CommURI.PARITY_NONE;

           if (sParity.equals("none")) {

                parity = CommURI.PARITY_NONE;

           } else if (sParity.equals("odd")) {

                parity = CommURI.PARITY_ODD;

           } else if (sParity.equals("even")) {

                parity = CommURI.PARITY_EVEN;

           }

 

           String uri = new CommURI.Builder(port)

           .withBaudRate(baudRate)

           .withDataBits(dataBits)

           .withStopBits(stopBits)

           .withParity(parity)

           .withTimeout(1000)

           .build().toString();

 

           try {

                m_commConnection = (CommConnection) m_connectionFactory.createConnection(uri, 1, false);

                m_commIs = m_commConnection.openInputStream();

                m_commOs = m_commConnection.openOutputStream();

 

                s_logger.info(port+" open");

           } catch (IOException e) {

                s_logger.error("Failed to open port " + port, e);

                cleanupPort();

           }

     }

 

     private void cleanupPort() {

           if (m_commIs != null) {

                try {

                     s_logger.info("Closing port input stream...");

                     m_commIs.close();

                     s_logger.info("Closed port input stream");

                } catch (IOException e) {

                     s_logger.error("Cannot close port input stream", e);

                }

                m_commIs = null;

           }

           if (m_commOs != null) {

                try {

                     s_logger.info("Closing port output stream...");

                     m_commOs.close();

                     s_logger.info("Closed port output stream");

                } catch (IOException e) {

                     s_logger.error("Cannot close port output stream", e);

                }

                m_commOs = null;

           }

           if (m_commConnection != null) {

                try {

                     s_logger.info("Closing port...");

                     m_commConnection.close();

                     s_logger.info("Closed port");

                } catch (IOException e) {

                     s_logger.error("Cannot close port", e);

                }

                m_commConnection = null;

           }

     }

 

     private void closePort() {

           cleanupPort();

     }

 

     private void doSerial() {

           if (m_commIs != null) {

                try {

                     int c = -1;

                     StringBuilder sb = new StringBuilder();

                    

                     while (m_commIs != null) {

                           if (m_commIs.available() != 0) {

                                c = m_commIs.read();

                           } else {

                                try {

                                     Thread.sleep(100);

                                     continue;

                                } catch (InterruptedException e) {

                                     return;

                                }

                          }

 

                           // on reception of CR, publish the received sentence

                           if (c==13) {

                                s_logger.debug("Received serial input, echoing to output: " + sb.toString());

                                sb.append("\r\n");

                                String dataRead = sb.toString();

                               

                                //echo the data to the output stream

                                m_commOs.write(dataRead.getBytes());

 

                                //reset the buffer

                                sb = new StringBuilder();

                           } else if (c!=10) {

                                sb.append((char) c);

                           }

                     }

                } catch (IOException e) {

                     s_logger.error("Cannot read port", e);

                } finally {

                     try {

                           m_commIs.close();

                     } catch (IOException e) {

                           s_logger.error("Cannot close buffered reader", e);

                     }

                }

           }

     }

}

 

 

 

At this point the bundle implementation is complete.  Make sure to save all files before proceeding.

 

 

Deploying the Bundle

In order to proceed, you need to know the IP address of your embedded gateway that is running ESF.  Once you do, follow the mtoolkit instructions for installing a single bundle to install the bundle to the remote target unit.  When this installation completes successfully, you should see a message similar to the one below out of /var/log/esf.log, showing the bundle was successfully installed and configured. (You can also run this example in the emulation environment in a Linux or OS X environment, but make sure that your user account has owner permission for the serial device in /dev.)

 

 

21:49:22,238 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Activating SerialExample...

21:49:22,239 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - component.name: com.eurotech.example.serial.SerialExample

21:49:22,240 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.baudrate: 9600

21:49:22,240 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.device: /dev/ttyUSB10

21:49:22,240 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - objectClass: [Ljava.lang.String;@1546e3a

21:49:22,240 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.parity: none

21:49:22,241 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.stop-bits: 1

21:49:22,241 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - service.pid: com.eurotech.example.serial.SerialExample

21:49:22,241 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.data-bits: 8

21:49:22,241 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - component.id: 28

21:49:22,259 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - /dev/ttyUSB10 open

21:49:22,261 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Activating SerialExample... Done.

21:49:22,269 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurableComponentTracker  - Adding ConfigurableComponent com.eurotech.example.serial.SerialExample

21:49:22,269 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurationServiceImpl  - Registration of ConfigurableComponent com.eurotech.example.serial.SerialExample by com.eurotech.framework.core.configuration.ConfigurationServiceImpl@d64869...

21:49:22,279 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurationServiceImpl  - Registering com.eurotech.example.serial.SerialExample with ocd: com.eurotech.framework.core.configuration.metatype.Tocd@1ed98f8 ...

21:49:22,280 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurationServiceImpl  - Registration Completed for Component com.eurotech.example.serial.SerialExample.

 

 

 

Validating the Bundle

Next, you need to test that your bundle does indeed echo characters back to us.  Open minicom and configure it to use [device_node_2] that you determined earlier.  Start by opening minicom, using the following command at a Linux terminal on the remote gateway device:

 

 

minicom -s

 

 

This command will open a view similar to the following screen capture.

 

Scroll down to Serial port setup and press <ENTER>.  This step will open a new dialog as shown.

 

Use the menu options on the left (A, B, C, etc) to change desired fields.  Set the fields to the same values as the previous screen capture with the exception that the Serial Device should match the [device_node_2] on your target device.  Once you have set this correctly, press <ENTER> to exit out of this menu.  In the main configuration menu, select Exit (do not select Exit from Minicom).  At this point, you have successfully started minicom on the second serial port attached to your null modem cable, and minicom is acting as a serial device that can send and receive commands to your ESF bundle.  You can try it by typing some characters and pressing <ENTER>.  The ESF application code is written such that <ENTER> or specifically a ‘\n’ character signals to the ESF application to echo the previously buffered characters back to the serial device (minicom in our case).  The following screen capture shows an example of that interaction.

 

Note that at startup, minicom sends an initialization string to the serial device.  In the example shown above, that initialization string was ‘AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0’.  Those characters were echoed back to your minicom terminal because they were echoed back by our ESF application listening on the port connected to the other end of the null modem cable.

 

Once you are done, you can exit minicom by pressing ‘<CTRL> a’ and then ‘q’ and then ‘<ENTER>’.  This will bring you back to the Linux command prompt.

 

This is the end of the required first part of this tutorial.  In this example so far, you have written and deployed an ESF bundle on your target device that listens to serial data (coming from the minicom terminal and received on [device_node_1]). The application outputs data back to the same serial port, which is received in minicom.  The minicom program is simulating a serial device that can both send and receive data.  The ESF application could send and receive binary data rather than ASCII if the device supports it.

 

 


Cloud Enabled Serial Communication

The second part of the tutorial is optional, depending on whether you have an active Everyware Cloud account.

 

In this section, you can enable the application bundle to communicate with the Everyware Cloud.  This capability will require making a fairly significant change to the ESF bundle application.  Instead of simply echoing characters to an attached serial device, ESF will send all incoming bytes to the Everyware Cloud using the CloudClient service.  ESF will also subscribe for incoming messages from the Everyware Cloud.  When a message is received, it will be sent to the serial device.  So, the ESF-enabled device will act as a gateway for the attached serial device, passing all messages to and from the Everyware Cloud.

 

Before continuing, make sure your embedded gateway is already connected to the Everyware Cloud as described here.

 

 

Modify the Code

You need to make the following changes to the code and metadata files:

 

·         Update the manifest to reflect the new dependencies on cloud capabilities in ESF.

·         Update the component.xml to reflect that the application now depends on the CloudService in ESF.

·         Add to the defined properties in the application.

·         Modify the code to integrate the new cloud capabilities.  This is mostly in the doSerial() method and the newly added CloudClientListener callback methods.  In addition, new set/unset methods are required for the new CloudService dependency.

 

All of these changes are shown in the following updated file contents.

 

The updated META-INF/MANIFEST.MF file should look as follows.  Note that whitespace is significant in this file.  Make sure yours matches this file exactly, except that the Execution Environment may be JavaSE-1.6 or JavaSE-1.7 depending on the Java installation of your device.

 

 

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: Serial Example

Bundle-SymbolicName: com.eurotech.example.serial;singleton:=true

Bundle-Version: 1.0.0.qualifier

Bundle-Vendor: EUROTECH

Bundle-RequiredExecutionEnvironment: JavaSE-1.6

Service-Component: OSGI-INF/*.xml

Bundle-ActivationPolicy: lazy

Import-Package: com.eurotech.framework.cloud,

 com.eurotech.framework.comm,

 com.eurotech.framework.configuration,

 com.eurotech.framework.message,

 javax.microedition.io;resolution:=optional,

 org.osgi.service.component;version="1.2.0",

 org.osgi.service.io;version="1.0.0",

 org.slf4j;version="1.6.4"

Require-Bundle: org.eclipse.equinox.io

Bundle-ClassPath: .

 

 

 

The updated OSGI-INF/component.xml should look as follows.

 

 

<?xml version="1.0" encoding="UTF-8"?>

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"

     name="com.eurotech.example.serial.SerialExample" activate="activate"

     deactivate="deactivate" modified="updated" enabled="true" immediate="true"

     configuration-policy="require">

     <implementation class="com.eurotech.example.serial.SerialExample" />

 

     <!-- If the component is configurable through the ESF ConfigurationService,

           it must expose a Service. -->

     <property name="service.pid" type="String"

           value="com.eurotech.example.serial.SerialExample" />

     <service>

           <provide interface="com.eurotech.example.serial.SerialExample" />

     </service>

 

     <reference bind="setConnectionFactory" cardinality="1..1"

           interface="org.osgi.service.io.ConnectionFactory" name="ConnectionFactory"

           policy="static" unbind="unsetConnectionFactory" />

 

     <reference name="CloudService" policy="static" bind="setCloudService"

           unbind="unsetCloudService" cardinality="1..1"

           interface="com.eurotech.framework.cloud.CloudService" />

 

</scr:component>

 

 

 

The updated OSGI-INF/metatype/com.eurotech.example.serial.SerialExample.xml file should look as follows when complete, with the exception of the “serial.device” parameter.  You should set the “default” parameter to the [device_node_1] for your target device.

 

 

<?xml version="1.0" encoding="UTF-8"?>

<MetaData xmlns="http://www.osgi.org/xmlns/metatype/v1.2.0" localization="en_us">

    <OCD id="com.eurotech.example.serial.SerialExample"

         name="SerialExample"

         description="Example of a Configuring ESF Application echoing data read from the serial port.">

       

        <Icon resource="http://sphotos-a.xx.fbcdn.net/hphotos-ash4/p480x480/408247_10151040905591065_1989684710_n.jpg" size="32"/>

       

        <AD id="serial.device" 

            name="serial.device"

            type="String"

            cardinality="0"

            required="false"

            default="/dev/ttyUSB10"

            description="Name of the serial device (e.g. /dev/ttyS0, /dev/ttyACM0, /dev/ttyUSB0)."/> 

 

        <AD id="serial.baudrate" 

            name="serial.baudrate"

            type="String"

            cardinality="0"

            required="true"

            default="9600"

            description="Baudrate."> 

           <Option label="9600" value="9600"/>

           <Option label="19200" value="19200"/>         

           <Option label="38400" value="38400"/>

           <Option label="57600" value="57600"/>

           <Option label="115200" value="115200"/>        

        </AD>

       

        <AD id="serial.data-bits" 

            name="serial.data-bits"

            type="String"

            cardinality="0"

            required="true"

            default="8"

            description="Data bits."> 

           <Option label="7" value="7"/>

           <Option label="8" value="8"/>         

        </AD>

       

        <AD id="serial.parity" 

            name="serial.parity"

            type="String"

            cardinality="0"

            required="true"

            default="none"

            description="Parity."> 

           <Option label="none" value="none"/>

           <Option label="even" value="even"/>

           <Option label="odd" value="odd"/>

        </AD>

 

        <AD id="serial.stop-bits" 

            name="serial.stop-bits"

            type="String"

            cardinality="0"

            required="true"

            default="1"

            description="Stop bits."> 

           <Option label="1" value="1"/>

           <Option label="2" value="2"/>         

        </AD>

       

        <AD id="publish.semanticTopic"

            name="publish.semanticTopic"

            type="String"

            cardinality="0"

            required="true"

            default="data"

            description="Default semantic topic to publish the messages to."/>

 

        <AD id="publish.qos"

            name="publish.qos"

            type="Integer"

            cardinality="0"

            required="true"

            default="0"

            description="Default QoS to publish the messages with.">

           <Option label="Fire and forget" value="0"/>

           <Option label="Al least once" value="1"/>

           <Option label="At most once" value="2"/>

        </AD>

 

        <AD id="publish.retain"

            name="publish.retain"

            type="Boolean"

            cardinality="0"

            required="true"

            default="false"

            description="Default retaing flag for the published messages."/>

       

        <AD id="publish.metric.name"

            name="publish.metric.name"

            type="String"

            cardinality="0"

            required="true"

            default="message"

            description="Metric name for messages coming from the serial device to be sent to Everyware Cloud"/>

       

        <AD id="subscribe.semanticTopic"

            name="subscribe.semanticTopic"

            type="String"

            cardinality="0"

            required="true"

            default="forward"

            description="Semantic topic for messages coming from Everyware Cloud to be forwarded to the Serial Device"/>

       

        <AD id="subscribe.metric.name"

            name="subscribe.metric.name"

            type="String"

            cardinality="0"

            required="true"

            default="message"

            description="Metric name for messages coming from Everyware Cloud to be forwarded to the Serial Device"/>

       

    </OCD>

    <Designate pid="com.eurotech.example.serial.SerialExample">

        <Object ocdref="com.eurotech.example.serial.SerialExample"/>

    </Designate>

</MetaData>

 

 

 

The updated com.eurotech.example.serial.SerialExample.java file should look as follows.

 

 

package com.eurotech.example.serial;

 

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.Future;

import java.util.concurrent.ScheduledThreadPoolExecutor;

 

import org.osgi.service.component.ComponentContext;

import org.osgi.service.component.ComponentException;

import org.osgi.service.io.ConnectionFactory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

import com.eurotech.framework.cloud.CloudClient;

import com.eurotech.framework.cloud.CloudClientListener;

import com.eurotech.framework.cloud.CloudService;

import com.eurotech.framework.comm.CommConnection;

import com.eurotech.framework.comm.CommURI;

import com.eurotech.framework.configuration.ConfigurableComponent;

import com.eurotech.framework.message.EsfPayload;

 

public class SerialExample implements ConfigurableComponent, CloudClientListener {

 

     private static final Logger s_logger = LoggerFactory.getLogger(SerialExample.class);

    

    // Cloud Application identifier

    private static final String APP_ID = "EXAMPLE_SERIAL_PUBLISHER";

 

     private static final String   SERIAL_DEVICE_PROP_NAME    = "serial.device";

     private static final String   SERIAL_BAUDRATE_PROP_NAME  = "serial.baudrate";

     private static final String   SERIAL_DATA_BITS_PROP_NAME = "serial.data-bits";

     private static final String   SERIAL_PARITY_PROP_NAME    = "serial.parity";

     private static final String   SERIAL_STOP_BITS_PROP_NAME = "serial.stop-bits";

 

     // Publishing Property Names

     private static final String   PUBLISH_TOPIC_PROP_NAME    = "publish.semanticTopic";

     private static final String   PUBLISH_QOS_PROP_NAME      = "publish.qos";

     private static final String   PUBLISH_RETAIN_PROP_NAME   = "publish.retain";

     private static final String   PUBLISH_METRIC_PROP_NAME   = "publish.metric.name";

 

     // Subscribing Property Names

     private static final String   SUBSCRIBE_TOPIC_PROP_NAME  = "subscribe.semanticTopic";

     private static final String   SUBSCRIBE_METRIC_PROP_NAME = "subscribe.metric.name";

    

     private CloudService m_cloudService;

     private CloudClient m_cloudClient;

 

     private ConnectionFactory m_connectionFactory;

     private CommConnection m_commConnection;

     private InputStream m_commIs;

     private OutputStream m_commOs;

 

     private ScheduledThreadPoolExecutor m_worker;

     private Future<?>           m_handle;

 

     private Map<String, Object> m_properties;

 

     // ----------------------------------------------------------------

     //

     //   Dependencies

     //

     // ----------------------------------------------------------------

 

     public void setConnectionFactory(ConnectionFactory connectionFactory) {

           this.m_connectionFactory = connectionFactory;

     }

 

     public void unsetConnectionFactory(ConnectionFactory connectionFactory) {

           this.m_connectionFactory = null;

     }

 

     public void setCloudService(CloudService cloudService) {

           m_cloudService = cloudService;

     }

 

     public void unsetCloudService(CloudService cloudService) {

           m_cloudService = null;

     }

 

 

     // ----------------------------------------------------------------

     //

     //   Activation APIs

     //

     // ----------------------------------------------------------------

 

     protected void activate(ComponentContext componentContext, Map<String,Object> properties) {

           s_logger.info("Activating SerialExample...");

           m_worker = new ScheduledThreadPoolExecutor(1);

           m_properties = new HashMap<String, Object>();

          

           try  {

 

            // Acquire a Cloud Application Client for this Application

                s_logger.info("Getting CloudApplicationClient for {}...", APP_ID);

                m_cloudClient = m_cloudService.newCloudClient(APP_ID);

                m_cloudClient.addCloudClientListener(this);

 

                // Don't subscribe because these are handled by the default

                // subscriptions and we don't want to get messages twice

 

                doUpdate(properties);

           } catch (Exception e) {

                s_logger.error("Error during component activation", e);

                throw new ComponentException(e);

        }

 

           s_logger.info("Activating SerialExample... Done.");

     }

 

     protected void deactivate(ComponentContext componentContext) {

           s_logger.info("Deactivating SerialExample...");

 

           // shutting down the worker and cleaning up the properties

           m_handle.cancel(true);

           m_worker.shutdownNow();

          

           // Releasing the CloudApplicationClient

        s_logger.info("Releasing CloudApplicationClient for {}...", APP_ID);

        m_cloudClient.release();

 

           //close the serial port

           closePort();

           s_logger.info("Deactivating SerialExample... Done.");

     }

 

     public void updated(Map<String,Object> properties) {

           s_logger.info("Updated SerialExample...");

           doUpdate(properties);

           s_logger.info("Updated SerialExample... Done."); 

     }

    

    

    // ----------------------------------------------------------------

    //

    //   Cloud Application Callback Methods

    //

    // ----------------------------------------------------------------

 

    @Override

    public void onControlMessageArrived(String deviceId, String appTopic,

           EsfPayload msg, int qos, boolean retain) {

    s_logger.info("Control message arrived on " + appTopic);

   

    String forwardTopic = (String) m_properties.get(SUBSCRIBE_TOPIC_PROP_NAME);

   

    if(appTopic.equals(forwardTopic)) {

           // this is a message that tells us to forward the data to the remote

           // serial device, so extract it from the message and send it along

           String message = (String) msg.getMetric((String) m_properties.get(SUBSCRIBE_METRIC_PROP_NAME));

           if(message != null && m_commOs != null) {

                try {

                     s_logger.info("Writing data to the serial port: " + message);

                     m_commOs.write(message.getBytes());

                     m_commOs.write("\r\n".getBytes());

                     m_commOs.flush();

                     } catch (IOException e) {

                           e.printStackTrace();

                     }

           } else {

                s_logger.info("Can't send incoming message to serial port");

           }

    }

    }

 

    @Override

    public void onMessageArrived(String deviceId, String appTopic,

           EsfPayload msg, int qos, boolean retain) {

    s_logger.info("Message arrived on " + appTopic);

    }

 

    @Override

    public void onConnectionLost() {

    s_logger.info("Connection was lost");

    }

 

    @Override

    public void onConnectionEstablished() {

    s_logger.info("Connection was established");

    }

 

    @Override

    public void onMessageConfirmed(int messageId, String appTopic) {

    s_logger.info("Message confirmed on " + appTopic);

    }

 

    @Override

    public void onMessagePublished(int messageId, String appTopic) {

    s_logger.info("Message published on " + appTopic);

    }

 

 

     // ----------------------------------------------------------------

     //

     //   Private Methods

     //

     // ----------------------------------------------------------------

 

     /**

      * Called after a new set of properties has been configured on the service

      */

     private void doUpdate(Map<String, Object> properties) {

           try {

                for (String s : properties.keySet()) {

                     s_logger.info("Update - "+s+": "+properties.get(s));

                }

 

                // cancel a current worker handle if one if active

                if (m_handle != null) {

                     m_handle.cancel(true);

                }

 

                //close the serial port so it can be reconfigured

                closePort();

 

                //store the properties

                m_properties.clear();

                m_properties.putAll(properties);

 

                //reopen the port with the new configuration

                openPort();

 

                //start the worker thread

                m_handle = m_worker.submit(new Runnable() {

                     @Override

                     public void run() {

                           doSerial();

                     }

                });

           } catch (Throwable t) {

                s_logger.error("Unexpected Throwable", t);

           }

     }

 

     private void openPort() {

           String port = (String) m_properties.get(SERIAL_DEVICE_PROP_NAME);

 

           if (port == null) {

                s_logger.info("Port name not configured");

                return;

           }

 

           int baudRate = Integer.valueOf((String) m_properties.get(SERIAL_BAUDRATE_PROP_NAME));

           int dataBits = Integer.valueOf((String) m_properties.get(SERIAL_DATA_BITS_PROP_NAME));

           int stopBits = Integer.valueOf((String) m_properties.get(SERIAL_STOP_BITS_PROP_NAME));

 

           String sParity = (String) m_properties.get(SERIAL_PARITY_PROP_NAME);

 

           int parity = CommURI.PARITY_NONE;

           if (sParity.equals("none")) {

                parity = CommURI.PARITY_NONE;

           } else if (sParity.equals("odd")) {

                parity = CommURI.PARITY_ODD;

           } else if (sParity.equals("even")) {

                parity = CommURI.PARITY_EVEN;

           }

 

           String uri = new CommURI.Builder(port)

           .withBaudRate(baudRate)

           .withDataBits(dataBits)

           .withStopBits(stopBits)

           .withParity(parity)

           .withTimeout(1000)

           .build().toString();

 

           try {

                m_commConnection = (CommConnection) m_connectionFactory.createConnection(uri, 1, false);

                m_commIs = m_commConnection.openInputStream();

                m_commOs = m_commConnection.openOutputStream();

 

                s_logger.info(port+" open");

           } catch (IOException e) {

                s_logger.error("Failed to open port " + port, e);

                cleanupPort();

           }

     }

 

     private void cleanupPort() {

           if (m_commIs != null) {

                try {

                     s_logger.info("Closing port input stream...");

                     m_commIs.close();

                     s_logger.info("Closed port input stream");

                } catch (IOException e) {

                     s_logger.error("Cannot close port input stream", e);

                }

                m_commIs = null;

           }

           if (m_commOs != null) {

                try {

                     s_logger.info("Closing port output stream...");

                     m_commOs.close();

                     s_logger.info("Closed port output stream");

                } catch (IOException e) {

                     s_logger.error("Cannot close port output stream", e);

                }

                m_commOs = null;

           }

           if (m_commConnection != null) {

                try {

                     s_logger.info("Closing port...");

                     m_commConnection.close();

                     s_logger.info("Closed port");

                } catch (IOException e) {

                     s_logger.error("Cannot close port", e);

                }

                m_commConnection = null;

           }

     }

 

     private void closePort() {

           cleanupPort();

     }

 

     private void doSerial() {

          

        // fetch the publishing configuration from the publishing properties  

        String  topic  = (String) m_properties.get(PUBLISH_TOPIC_PROP_NAME);

        Integer qos    = (Integer) m_properties.get(PUBLISH_QOS_PROP_NAME);

        Boolean retain = (Boolean) m_properties.get(PUBLISH_RETAIN_PROP_NAME);

        String metricName = (String) m_properties.get(PUBLISH_METRIC_PROP_NAME);

          

           if (m_commIs != null) {

                try {

                     int c = -1;

                     StringBuilder sb = new StringBuilder();

 

                     while (m_commIs != null) {

                           if (m_commIs.available() != 0) {

                                c = m_commIs.read();

                           } else {

                                try {

                                     Thread.sleep(100);

                                     continue;

                                } catch (InterruptedException e) {

                                     return;

                                }

                           }

 

                           // on reception of CR, publish the received sentence

                           if (c==13) {

                                s_logger.debug("Received serial input, echoing to output: " + sb.toString());

                                sb.append("\r\n");

                                String dataRead = sb.toString();

 

                                //now instead of simplying echoing data back to the serial

                                //port, publish it to Everyware Cloud

                                try {

                                     EsfPayload esfPayload = new EsfPayload();

                                     esfPayload.setTimestamp(new Date());

                                     esfPayload.addMetric(metricName, dataRead);

                                     m_cloudClient.publish(topic, esfPayload, qos, retain);

                                } catch (Exception e) {

                                s_logger.error("Cannot publish topic: "+topic, e);

                        }

 

                                //reset the buffer

                                sb = new StringBuilder();

                           } else if (c!=10) {

                                sb.append((char) c);

                           }

                     }

                } catch (IOException e) {

                     s_logger.error("Cannot read port", e);

                } finally {

                     try {

                           m_commIs.close();

                     } catch (IOException e) {

                           s_logger.error("Cannot close buffered reader", e);

                      }

                }

           }

     }

}

 

 

 

At this point, the bundle implementation is complete.  Make sure to save all files before proceeding.

 

 

Re-deploying the Bundle

Follow the mtoolkit instructions for installing a single bundle to install the bundle to the remote target device.  When this installation completes successfully, you should see a message similar to the following one out of /var/log/esf.log, showing the bundle was successfully installed and configured.  This process should go exactly as in the first part of this tutorial, except you will be prompted that the bundle is already installed and asked if you want to install the new copy.  Select yes when prompted.

 

 

23:49:42,886 [mToolkit Worker #1] INFO  c.e.f.c.c.ConfigurableComponentTracker  - Removed  ConfigurableComponent com.eurotech.example.serial.SerialExample

23:49:42,887 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Deactivating SerialExample...

23:49:42,888 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Releasing CloudApplicationClient for EXAMPLE_SERIAL_PUBLISHER...

23:49:43,438 [mToolkit Worker #1] ERROR c.e.f.l.n.u.LinuxNetworkUtil  - error executing command --- ifconfig 1-3.1 --- exit value = 1

23:49:43,438 [mToolkit Worker #1] WARN  c.e.f.l.n.r.NetworkServiceImpl  - Could not get MTU for 1-3.1

23:49:43,582 [mToolkit Worker #1] INFO  c.e.f.c.d.DataServiceImpl  - Storing message on topic :$EDC/#account-name/#client-id/MQTT/APPS, priority: 0

23:49:43,654 [mToolkit Worker #1] INFO  c.e.f.c.d.DataServiceImpl  - Stored message on topic :$EDC/#account-name/#client-id/MQTT/APPS, priority: 0

23:49:43,659 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Closing port input stream...

23:49:43,661 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Closed port input stream

23:49:43,661 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Closing port output stream...

23:49:43,661 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Closed port output stream

23:49:43,661 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Closing port...

23:49:43,905 [MQTT Call: serial-example] INFO  c.e.f.c.c.CloudServiceImpl  - Ignoring feedback message from $EDC/edcguest/serial-example/BA/BIRTH

23:49:44,337 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Closed port

23:49:44,337 [mToolkit Worker #1] INFO  c.e.e.s.SerialExample  - Deactivating SerialExample... Done.

23:49:44,421 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Activating SerialExample...

23:49:44,422 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Getting CloudApplicationClient for EXAMPLE_SERIAL_PUBLISHER...

23:49:45,052 [Component Resolve Thread (Bundle 6)] ERROR c.e.f.l.n.u.LinuxNetworkUtil  - error executing command --- ifconfig 1-3.1 --- exit value = 1

23:49:45,052 [Component Resolve Thread (Bundle 6)] WARN  c.e.f.l.n.r.NetworkServiceImpl  - Could not get MTU for 1-3.1

23:49:45,197 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.d.DataServiceImpl  - Storing message on topic :$EDC/#account-name/#client-id/MQTT/APPS, priority: 0

23:49:45,290 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.d.DataServiceImpl  - Stored message on topic :$EDC/#account-name/#client-id/MQTT/APPS, priority: 0

23:49:45,292 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - component.name: com.eurotech.example.serial.SerialExample

23:49:45,292 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - subscribe.metric.name: message

23:49:45,292 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.baudrate: 9600

23:49:45,292 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.device: /dev/ttyUSB10

23:49:45,293 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - objectClass: [Ljava.lang.String;@19a67a3

23:49:45,293 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.parity: none

23:49:45,293 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - subscribe.semanticTopic: forward

23:49:45,293 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - publish.semanticTopic: data

23:49:45,293 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.stop-bits: 1

23:49:45,293 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - service.pid: com.eurotech.example.serial.SerialExample

23:49:45,294 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - serial.data-bits: 8

23:49:45,294 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - component.id: 32

23:49:45,294 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - publish.metric.name: message

23:49:45,294 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - publish.qos: 0

23:49:45,295 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Update - publish.retain: false

23:49:45,317 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - /dev/ttyUSB10 open

23:49:45,319 [Component Resolve Thread (Bundle 6)] INFO  c.e.e.s.SerialExample  - Activating SerialExample... Done.

23:49:45,336 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurableComponentTracker  - Adding ConfigurableComponent com.eurotech.example.serial.SerialExample

23:49:45,337 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurationServiceImpl  - Registration of ConfigurableComponent com.eurotech.example.serial.SerialExample by com.eurotech.framework.core.configuration.ConfigurationServiceImpl@d64869...

23:49:45,347 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurationServiceImpl  - Registering com.eurotech.example.serial.SerialExample with ocd: com.eurotech.framework.core.configuration.metatype.Tocd@1f9d1a0 ...

23:49:45,348 [Component Resolve Thread (Bundle 6)] INFO  c.e.f.c.c.ConfigurationServiceImpl  - Registration Completed for Component com.eurotech.example.serial.SerialExample.

 

 

 

Sending Messages to the Cloud

With the newly upgraded bundle installed, you can now re-establish the minicom session to see data flow to and from the minicom serial device.  As before, minicom will send data from [device_node_2] to [device_node_1] through the null modem cable, which will be processed by the newly upgraded ESF bundle, and then data will be published to the Everyware Cloud. 

 

Open and configure minicom to [device_node_2] as in the first part of this tutorial.  Type some characters and press <Enter>.  Next, open a web browser and go to the Everyware Cloud Console.  Select Data by Asset (or Data by Topic, if you prefer) and query the data for your device on the topic EXAMPLE_SERIAL_PUBLISHER/data.  You should see that the data you typed in the minicom session has appeared in the Everyware Cloud data store.  The following screen capture shows some data from the minicom serial device including a hand-typed message (“Hello from cloud enabled serial example”), as well as the minicom initialization string previously mentioned. 

 

Note if this were a real serial device that continuously streams data, all of that data would be appearing in the Everyware Cloud as new data messages.  Be aware that this simple example is only intended for illustration, and in designing your application you need to be aware of data costs and design the application accordingly.

 

serial1.png

 

Receiving Messages from the Cloud

The updated bundle includes the ability for the device to receive data from the Everyware Cloud.  However, this cannot be done from within the Everyware Cloud Console.  Instead, you can do this using a ‘curl’ command and a simple XML file.  To post an XML file to the REST API of Everyware Cloud, you will need a computer that has the ‘curl’ command installed (this could be done from the Linux command line on the target device itself, if necessary).  For more information, see the REST API documentation available on the Everyware Cloud Developers' Guide and Everyware Cloud API.

 

Create a file named “message.xml” that contains the simple XML content that follows.  Replace the following two parameters with the account name of your Everyware Cloud account and the asset ID of your target device:

 

·         [account_name]

·         [asset_id]

 

 

<?xml version="1.0" encoding="UTF-8"?>

<message xmlns="http://eurotech.com/edc/2.0">

     <topic>$EDC/[account_name]/[asset_id]/EXAMPLE_SERIAL_PUBLISHER/forward</topic>

     <receivedOn></receivedOn>

     <payload>

           <sentOn>1376608860</sentOn>

           <metrics>

                <metric>

                     <name>message</name>

                     <type>String</type>

                     <value>hello</value>

                </metric>

           </metrics>

           <body></body>

     </payload>

</message>

 

 

Now from the same directory, run the following ‘curl’ command.  Replace the following two parameters with a valid username and password of your Everyware Cloud account:

 

·         [user_name]  (This must be a user with at least the following permissions: account:view, broker:connect, and data:manage.)

·         [password]  (Use the backslash character \ before symbols in the password to ensure they are “escaped”.)

 

Note if you have a production account, the URL will be https://api.everyware-cloud.com/v2/messages/publish instead of https://api-sandbox.everyware-cloud.com/v2/messages/publish.

 

 

curl -v -k -X POST -H "Content-Type: application/xml" --data "@message.xml" -u [user_name]:[password] https://api-sandbox.everyware-cloud.com/v2/messages/publish

 

 

After running this command, you should see the content of the message (in this case ‘hello’) come out on the minicom session that you have open on the embedded gateway.

 

Once you are done, you can exit minicom by pressing ‘<CTRL> a’ and then ‘q’ and then ‘<ENTER>’.  This will bring you back to the Linux command prompt.

 

This is the end of the optional second part of this tutorial, in which ESF has published data from a serial device to the Everyware Cloud, and also sent data to a local serial device that was received from the Everyware Cloud.