Integrating SIGFOX data on ARTIK Cloud

Editor’s note: The following is a guest post from our partner SIGFOX, demonstrating an integration between its SIGFOX network and ARTIK Cloud.

A couple of weeks before SDC 2016, we decided to build a simple demo showcasing the integration of data coming from the SIGFOX network to ARTIK Cloud.

The end result looks like this:

Charts-1024x595

All of this took only a few hours, thanks to the advanced features offered by ARTIK Cloud.

What is SIGFOX?

SIGFOX is an IoT connectivity solution provider.

We are deploying on our network, dedicated to the Internet of Things and focused on maximum energy efficiency. Messages on the SIGFOX network are small ones, up to 12 bytes of useful payload, and the network is currently operating in 19 countries.

Check out this page for more information about the technology & the service.

The device

First of all, we need a device to send messages to the ARTIK Cloud over the internet.

We’re using a Sensit to demonstrate SIGFOX.

Embedding several sensors (temperature, movement, magnetic, light, etc.), it has two modes of operation:

  • Sends the active sensor value/state every interval. (Every hour, every 10 mins, etc. The interval can be updated through the SIGFOX network.)
  • Sends the active sensor value/state whenever the button is pressed.

SensitSensit-open-1-1024x768

This demo uses solely the temperature & humidity sensors.

ARTIK Cloud setup

Device type

First, we need to create a custom device type, able to handle the messages we send.

As the messages sent through the SIGFOX network are only a few bytes long, we normally can’t expect to receive intelligible data. Instead, we receive a few bytes and would need to apply quite a lot of binary operations to extract the meaning of the received message.

That’s where ARTIK Cloud is really powerful in our case: using the Advanced Manifest feature, we’re able to compute the incoming data before sending it to the Data Logs.

This means we don’t need a proxy server to do the work, or to activate an extra worker to do the job!

Here is our Advanced Manifest:

  import groovy.json.JsonSlurper
  import groovy.json.JsonBuilder
  import javax.measure.unit.NonSI
  import com.samsung.sami.manifest.Manifest
  import com.samsung.sami.manifest.fields.*
  import static com.samsung.sami.manifest.fields.StandardFields.*
  import static com.samsung.sami.manifest.groovy.JsonUtil.*
  import java.util.regex.*

  public class TestJsonUtilGroovyManifest implements Manifest {
    // Custom FieldDesc
    static final DEVICE_ID = new FieldDescriptor("deviceId", String.class)
    static final MODE = new FieldDescriptor("mode", Integer.class)
    static final ACTION = new FieldDescriptor("action", String.class)
    static final HUMIDITY = new FieldDescriptor("humidity", Double.class)

    @Override
    List<Field> normalize(String input) {
      def slurper = new JsonSlurper()
      def builder = new JsonBuilder()
      def json = slurper.parseText(input)

      def frame = json.data
      def output = builder{}
      def action = -1;

      try{
        output.bytes = frame.decodeHex()
        output.mode = output.bytes[0] & 0b111
        //frame type: bits 6 & 7
        action = (output.bytes[0] >> 5) & 0b11;
      }
      catch (Exception e){
        output.bytes = null
        output.mode = 0
      }
      switch (action){
        case 0: 
          output.action = "Classic"
          break
        case 1: 
          output.action = "Button"
          break
        case 2: 
          output.action = "Alert"
          break
        case 3: 
          output.action = "NewMode"
          break
        default: 
          output.action = "Unknown {"+frameType+"}"
      }
      switch (output.mode){
        case 0:
          //Missing or invalid data frame 
          break
        case 1:
          output.temp = getTemperature(output.bytes)
          if (output.action == "Button")
            output.humidity = null
          else
            output.humidity = getHumidity(output.bytes)
            break
      }

      def fields = []
      addToList(fields, json, DEVICE_ID)
      addToList(fields, output, MODE)
      addToList(fields, output, TEMPERATURE)
      addToList(fields, output, NonSI.PERCENT, HUMIDITY)
      addToList(fields, output, ACTION)

      return fields
    }

    @Override
    List<FieldDescriptor> getFieldDescriptors() {
      return [
        DEVICE_ID, TEMPERATURE, MODE, HUMIDITY, ACTION
      ]
    }

    Double getTemperature(bytes){
      //MSB : First 4 bits of 2ndbyte 2
      //LSB : last 6 bits of 3rd byte
      //T°C = MSB+LSB-200 / 8
      def MSB = bytes[1] >> 4 << 6
      def LSB = bytes[2] & 0b111111

      def temp = MSB+LSB-200
      temp /= 8

      return temp
    }
    Double getHumidity(bytes){
      return (bytes[3] & 0xFF) / 2;
    }
  }

(Yes, this is Groovy code within a .json file. Weird enough, but it works well 🙂 )

The interesting bits:

  • As our Sensit is sending different frames depending on this active mode, we first need to extract the frame type and active mode from the first byte:
    output.mode = output.bytes[0] & 0b111
    //frame type: bits 6 & 7
    action = (output.bytes[0] >> 5) & 0b11;
    
  • Depending on these values, we either:
    • Do nothing if the active mode doesn’t contain temperature or humidity information;
    • Extract the temperature only, if the message was sent after a user action (button);
      Double getTemperature(bytes){ 
      //MSB : First 4 bits of 2ndbyte 2 
      //LSB : last 6 bits of 3rd byte 
      //T°C = MSB+LSB–200 / 8 
      def MSB = bytes[1] >> 4 << 6 
      def LSB = bytes[2] & 0b111111
      
      def temp = MSB+LSB–200 
      temp /= 8
      
      return temp 
      }
    • Extract both temperature and humidity if the message was a scheduled one (classic).
      Double getHumidity(bytes){ return (bytes[3] & 0xFF) / 2; } 

    Sending data to ARTIK Cloud

    SIGFOX interface

    As soon as a message is sent by the device & received by our network, it pops up on the SIGFOX cloud interface.

    Sigfox-messages

    Pushing to ARTIK Cloud

    Once messages are received, we need to forward them to ARTIK Cloud.

    To do this, we rely on the SIGFOX callbacks mechanism: simply describe the way the HTTP request must be formatted (URI, headers, request body), and it will be called for every message received.

    Here is what the configuration looks like to push our messages to ARTIK Cloud: 

    callback

    What’s happening here?

    • URL: We use the REST API message creation endpoint.
    • We set the Authorization header, with the Bearer token provided by ARTIK Cloud (see below).
    • Set the Content-Type to application/json to comply with ARTIK Cloud’s API.
    • Within the request body, we set the following values:
      • sdid : use the device ID as known on ARTIK Cloud.
      • data : {data} is the raw frame sent through SIGFOX (81572987, for example).

    The green arrow on the SIGFOX messages page tells that the callback was called, and received a 200 OK response from ARTIK Cloud.

    End result

    Once messages are processed by our Advanced Manifest, they show up in the Data Logs:

    logs-1024x420

    And you can add nice charts to your dashboard: 

    Charts-1024x595

    You can also trigger any action depending on the incoming value, using the ARTIK Cloud Rules to send an email or a device-specific action.

    Up next

    • Handle all the Sensit sensors, and not only temperature & humidity
    • Improve callback integration :
      • SIGFOX callbacks are defined on the device type level
      • ARTIK Cloud’s API is device related
      • Meaning that the callback needs to present a device token
      • Fine when you have a one-device device-type, but not for fleets
    • Release publicly the Sensit device type

Looking to connect many devices to the cloud and build innovative IoT solutions? Click here to get started for free.