Tuesday, June 14, 2016

How to send data to the cloud service Ubidots from a Sky mote using Contiki-OS?

Objective

I have a sensor node CM5000, which is compatible with a sky mote, and want to use it to send temperature data to the cloud service Ubidots. Currently, the node is working with the operating system Contiki-OS, specifically i am working with Instant-contiki-3.0.

I did some research and the web page below gives you the steps to send temperature data to Ubidots using a Z1 mote. I follow the steps of the web page, but since the sky mote is not compatible with a Z1 mote then it does not work.

http://wireless.ictp.it/school_2015/book/#_sending_data_to_ubidots

Here, i will show you how to send data to Ubidots using Sky motes modifying the code from the web page above.

Step 1: Create an account in Ubidots

  • Create a Data Source by clicking
    Sources -> Add Data Source -> Generic -> Create
    

    Now, you must have a data source named My Datasource.

  • Create a variable by clicking
    Sources -> My Datasource -> Add Variable -> Name = Temperature -> Create
    

    Now, you must have a variable named Temperature.

  • Keep in mind the variable's ID: Click in
    Sources -> My Datasource 
    

    Each variable at the top right-hand corner have an i, and if you click it, then it will show you the variable's ID. My variable's ID is:

    567a05d07625424d60d32a31 
    
  • Keep in mind your API Key: Click in
    My Profile -> API Keys
    

    There you will find your API Key. My API Key is:

    2eed47ae4097bbbfd26ae57c8eb799cc450d0416 
    
  • Create a Dashboard by clicking
    Dashboard -> + -> Line Chart -> My Datasource -> Temperature -> Finish
    

Step 2: Create the serial-ubidots App

  • Go to the folder /contiki-3.0/apps
    cd /home/user/contiki-3.0/apps
    
  • Create a folder named serial-ubidots
  • Within that folder, you must create a Makefile named Makefile.serial-ubidots with the following code in it:
    serial-ubidots_src = serial-ubidots.c
    
  • Within that folder, you must create a file named serial-ubidots.c with the following code in it:
    #include 
    #include "serial-ubidots.h"
    void
    send_to_ubidots(const char *api, const char *id, uint16_t val) // api = API KEY, ID = Variable's ID, Val = Value of temperature
    {
        unsigned char buf[6];
        snprintf(buf, 6, "%d", val); 
        printf("***%s\t", api); // The *** indicate the start of the data sent to Ubidots
        printf("%s\t", id);
        printf("%s***\n", buf); // The *** indicate the end of the data sent to Ubidots
     }
    
  • Within that folder, you must create a file named serial-ubidots.h with the following code in it:
    #define VAR_LEN 24
     #define UBIDOTS_MSG_LEN (VAR_LEN + 2)
     struct ubidots_msg_t {
       char var_key[VAR_LEN];
       uint8_t value[2];
     };
     void send_to_ubidots(const char *api, const char *id, uint16_t val);
    
  • Include the serial-ubidots App in the makefile of sky motes: Go to the folder /home/user/contiki-3.0/examples/sky
    cd /home/user/contiki-3.0/examples/sky
    

    Open the Makefile and add the following line

    APPS=serial-ubidots
    

    Now, the Makefile should look like this

    CONTIKI = ../..
    ifndef TARGET
    TARGET=sky
    endif
    
    all: blink sky-collect #rt-leds test-button test-cfs tcprudolph0
    
    APPS=serial-ubidots
    
    %.tgz: %.ihex
        mkdir $(basename $<) ; \
        mv $< $(basename $<) ; \
        echo $(basename $<)/$(basename $<).ihex 600 > $(basename $<)/runfile ; \
        tar czf $@ $(basename $<)
    
    CONTIKI_WITH_IPV4 = 1
    CONTIKI_WITH_RIME = 1
    include $(CONTIKI)/Makefile.include
    

Step 3: Create a contiki C file that reads the temperature and send it to the serial port via the serial-ubidots app previously created

  • Go to the folder /home/user/contiki-3.0/examples/sky
    cd /home/user/contiki-3.0/examples/sky
    

    Create a file named temperature.c with the following code in it

    
    #include "contiki.h"
     #include "dev/sht11/sht11-sensor.h"
     #include "dev/light-sensor.h"
     #include "dev/leds.h"
     #include 
     #include "serial-ubidots.h"
    
     //Declare the process
     PROCESS(send_sensor_info_process, "Print the Sensors Information");
    
    //Make the process start when the module is loaded
    AUTOSTART_PROCESSES(&send_sensor_info_process);
    
    static uint16_t 
    get_temp(void)
    {
      return ((sht11_sensor.value(SHT11_SENSOR_TEMP) / 10) - 396) / 10;
    }
    /*---------------------------------------------------------------------------*/
    
    //Define the process code
    PROCESS_THREAD(send_sensor_info_process, ev, data)
    {
    
      static struct etimer et;
      static const char api_key[] = "2eed47ae4097bbbfd26ae57c8eb799cc450d0416"; // This is your API Key previously copied from Ubidots
      static const char var_key[] = "567a05d07625424d60d32a31"; // This is your variable's ID previously copied from Ubidots
    
      PROCESS_BEGIN();
    
      uint16_t  raw;
    
      while(1){
        etimer_set(&et, CLOCK_SECOND * 15);
        SENSORS_ACTIVATE(sht11_sensor);
        PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
        raw = get_temp() ;
        send_to_ubidots(api_key, var_key, raw);
        etimer_reset(&et);
        SENSORS_DEACTIVATE(sht11_sensor);
     }
      PROCESS_END();
    } 
    
    
  • Upload the temperature.c code into the sky mote and login with the following command:
    make TARGET=sky temperature.upload && make login
    

    Then, you should be able to see this in the terminal every 15 seconds

    ***2eed47ae4097bbbfd26ae57c8eb799cc450d0416 567a05d07625424d60d32a31    29***
    

    That means that the sky mote is sending over the /dev/ttyUSB0/ the following information

            *** = Indicates start of frame
            2eed47ae4097bbbfd26ae57c8eb799cc450d0416 = Api Key
            \t = Tab key to separate data 
            567a05d07625424d60d32a31 = Variable's ID
            \t = Tab key to separate data
            29 = Temperature (Celsius) 
            *** = Indicates end of frame
    

Step 4: Create a Python Script to read the data from the serial port and send it to Ubidots

  • Install Python in your computer
    sudo apt-get install build-essential checkinstall
     sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev
     cd ~/Downloads/
     wget http://python.org/ftp/python/2.7.5/Python-2.7.5.tgz
     tar -xvf Python-2.7.5.tgz
     cd Python-2.7.5
     ./configure
     make
    
  • Install pip in Linux
     sudo easy_install pip
    
  • Install the Python library Ubidots for python
     sudo pip install ubidots==1.6.1
    
  • Go to the folder /home/user/contiki-3.0/examples/sky
     cd /home/user/contiki-3.0/examples/sky
    
  • Create a file named UbidotsPython.py with the following code in it:
    # -*- coding: utf-8 -*-
     # ----------------------------------------------------------------------------#
     # Simple application to relay data to Ubidots from a Contiki serial-based conn
     # ----------------------------------------------------------------------------#
    
    
     import serial
     from time import sleep
     from ubidots import ApiClient
    
     # Use as default
     PORT = "/dev/ttyUSB0"
    
     # ----------------------------------------------------------------------------#
     # Create a serial object and connect to mote over USB
     # ----------------------------------------------------------------------------#
     def connectMote(port):
       try:
         ser = serial.Serial(port, 115200,timeout=0, parity=serial.PARITY_NONE,
                   stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS)
       except:
         sys.exit("Error connecting to the USB device, aborting")
       return ser
    
       # ----------------------------------------------------------------------------#
       # Parse the serial data and publish to Ubidots, this assumes the following:
       # \r\n API_KEY \t VAR_KEY \t VALUE \r\n
       # ----------------------------------------------------------------------------#
       def process_data(raw):
    
       # Search for start and end of frame and slice, discard incomplete
    
       if "***" in raw:
        raw = raw[(raw.index("***") + 3):]
    
        if "***" in raw:
          raw = raw[:raw.index("***")]
    
          # We should have a full frame, parse based on tab and create a list
          ubidots_raw = raw.split("\t")
          # Create a Ubidots client and get a pointer to the variable
          client = ApiClient(ubidots_raw[0])
          try:
            my_variable = client.get_variable(ubidots_raw[1])
          except Exception, e:
            print "Ubidots error: %s" % e
            return
          # Update the variable
          my_variable.save_value({'value':int(ubidots_raw[2])})
    
     # ----------------------------------------------------------------------------#
     # MAIN APP
     # ----------------------------------------------------------------------------#
     if __name__=='__main__':
    
       # Create the serial object and connect to the mode
       # Do not check the serial port object as the function already does it
       s = connectMote(PORT)
    
       # Loop forever and wait for serial data
       while True:
         queue = s.inWaiting()
         if queue > 0:
           data = s.read(1000)
           process_data(data)
         sleep(0.2)
    

Step 5:Send data to Ubidots

  • Go to the folder /home/user/contiki-3.0/examples/sky
     cd /home/user/contiki-3.0/examples/sky
    
  • Upload the temperature.c code
     make TARGET=sky temperature.upload
    
  • Execute the script UbidotsPython.py
     python UbidotsPython.py
    
    

    Wait approximately 15 seconds for the first data to appear in the dashboard of Ubidots.

2 comments:

  1. can we do this for other motes like z1 mote(cc2538 soc based)

    ReplyDelete
  2. Hi Sergio,

    NICE topics! Thanks for sharing.

    I'm try to do something similar.

    I'm tried to send sky mote data to ibm cloud service without sucess till now.

    I have 4 sky motes and one RPI.

    - 1 sky mote as border router connected to RPI3 with tunslip6 (sudo ./tunslip6 212:7400:13e3::1/64 -t tun0 -s /dev/ttyUSB0)
    - 3 sky motes with contiki example ipv6/sky-websense.c

    Now you know how i can get the data from the sensors on python ? to further send the data to cloud service ?

    Is possible to use MQTT on sky motes?
    I tried to modify this example for mote Z1 :
    https://github.com/contiki-os/contiki/tree/master/examples/nrf52dk/mqtt-demo

    But without sucess... :_(

    ReplyDelete