Archive

Posts Tagged ‘electric imp’

How to handle JSON data using the electric imp.

January 7th, 2013

I’ve had more requests for examples of accessing JSON data using an electric imp.  I use it to collect weather information from weather underground. Here’s some skeleton code to highlight what you need..

 

local astronomy = OutputPort("Astronomy","number");
function getAstronomyData() {
    astronomy.set(1); //initiates outbound connection to retreive astronomy data
}

function dumptable(p, t) {
    foreach(key, value in t) {
        if (typeof value == "table") {
            dumptable(p+"."+key, value);
        }
        else server.log(p+"."+key + " = " + value);
    }
}

//this class receives the json data
class Astronomy extends InputPort {
    function set(payload) {
        //to figure out json structure uncomment the following and check the log output
        //dumptable("",payload);
       
        //all the data is considered a string, so convert to integer or whatever as necessary 
        local variable = payload.moon_phase.sunset.hour.tointeger(); 
        doSomethingWith(variable);
       
        //schedule another update in 1 minute
        imp.wakeup(60, getAstronomyData);
    }
}

function boot() {
    //invoke a call to get the astronomy data here
    getAstronomyData(); // or use imp.wakeup() to specify a time to invoke
}

imp.configure("Outdoor Automation", [Astronomy("astronomy","string") ], [astronomy]);

 

In the planner, setup an HTTP request which sends the request in the form of a GET request specifying the url (which, in the case of weather underground, includes the api key).  Set the content type to json.

 

image

 

Connected an arrow from your application to the HTTP request and one from the HTTP request back to the application.

 

The way it works is that when you write to the HTTP request, the URL is called.  When data is returned, it will invoke Astronomy.set() (defined in imp.configure(), which you need to provide) which then parses the data. 

A dumptable function is provided in order to help you figure out the structure of the json data the first time to know how to extract it.

Hope this helps.

Electronics

Electric Imp & SHTxx sensors

December 17th, 2012

There have been a couple people requesting the code to drive an SHT temp/humidity sensor from an electric imp, so I’ll post it below.  No warrantee implied..  Also, it’s ugly as someone else wrote it for some other microprocessor and I just tweaked it; I would never write such aesthetically displeasing code.    Obviously, I’m big banging pins 8 and 9; adjust to suite your needs.  Don’t forget the pullup resistor on one of those lines.  This is also written for the SHT71, tweak for whichever unit you are using.

 

class SHT {
       
    function delay_us(x) {imp.sleep(0.000001 * x);}

     noACK =0;
     ACK=1;
                                //adr  command  r/w
     STATUS_REG_W =0x06;   //000   0011    0
     STATUS_REG_R =0x07;   //000   0011    1
     MEASURE_TEMP =0x03;   //000   0001    1
     MEASURE_HUMI =0x05;   //000   0010    1
     RESET        =0x1e;   //000   1111    0
    
    data_output = true;
   
    function constructor() {
        hardware.pin8.configure(DIGITAL_OUT);
        hardware.pin9.configure(DIGITAL_OUT);
        s_softreset( );
    }
   
   
   
    function sck_set(x) {
        hardware.pin8.write(x);
       
    }
    function data_set(x) {
        if (!data_output) {
            hardware.pin9.configure(DIGITAL_OUT); 
            data_output = true;
        }
        hardware.pin9.write(x);
       
    }
   
    function data_get() {
        if (data_output) {
            hardware.pin9.configure(DIGITAL_IN);
            data_output = false;
            }
        return hardware.pin9.read();
    }
   
   
    function SCK( val) {
        if (val) {
            sck_set(1);
        } else {
            sck_set(0);
        }
    }
   
    function DATA( val) {
        if (val) {
            //input w/ pullup resistor
            data_get();
        } else  {
            //output – gnd
            data_set(0);
        }
    }           
   
   
    function sht_init() {
        s_write_statusreg(0, 0x00); //8/12 bit resolution
    }
   
   
       
   
   
    //———————————————————————————-
    function s_write_byte( value) {
    //———————————————————————————-
    // writes a byte on the Sensibus and checks the acknowledge
      local error=0; 
   
      for (local i=0x80; i>0; i=i/2)             //shift bit for masking
      {
          if (i & value) DATA( 1);          //masking value with i , write to SENSI-BUS
          else DATA(0);                       
            delay_us(5);
          SCK( 1);                          //clk for SENSI-BUS
          delay_us(5);        //pulswith approx. 5 us     
          SCK( 0);
      }
      delay_us(5);
      DATA( 1);                           //release DATA-line
      SCK( 1);                            //clk #9 for ack
    
      error=data_get();                       //check ack (DATA will be pulled down by SHT11)
      SCK( 0);  
      return error;                     //error=1 in case of no acknowledge
    }
   
    //———————————————————————————-
    function s_read_byte( ack)
    //———————————————————————————-
    // reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"
    {
      local val=0;
      DATA( 1);                     //release DATA-line
      for (local i=0x80; i>0 ; i = i>>1)  {           //shift bit for masking
       SCK( 1);                    //clk for SENSI-BUS
        if (data_get()) val=(val | i);        //read bit 
        SCK( 0);                      
      }
      if (ack) {
          DATA(0);
      } else {
          DATA(1);
      }
     
      SCK( 1);                      //clk #9 for ack
      delay_us(5);          //pulswith approx. 5 us
      SCK( 0);                           
      DATA( 1);                     //release DATA-line
      return val;
    }
   
    //———————————————————————————-
    function s_transstart( )
    //———————————————————————————-
    // generates a transmission start
    //       _____         ________
    // DATA:      |_______|
    //           ___     ___
    // SCK : ___|   |___|   |______
    { 
       DATA( 1);
       SCK( 0);//Initial state
       delay_us(2);
       SCK( 1);
       delay_us(2);
       DATA( 0);
       delay_us(2);
       SCK( 0); 
       delay_us(6);
       SCK( 1);
       delay_us(2);
       DATA( 1);          
       delay_us(2);
       SCK( 0);          
    }
   
    //———————————————————————————-
    function s_connectionreset( )
    //———————————————————————————-
    // communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart
    //       _____________________________________________________         ________
    // DATA:                                                      |_______|
    //          _    _    _    _    _    _    _    _    _        ___     ___
    // SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |______
    { 
      server.log("connectionreset()");
      DATA( 1);
      SCK( 0);                    //Initial state
      for(local i=0;i<9;i++)                  //9 SCK cycle
      {
          SCK( 1); delay_us(1);
        SCK( 0); delay_us(1);
      }
      s_transstart();                   //transmission start
    }
   
    //———————————————————————————-
    function s_softreset( )
    //———————————————————————————-
    // resets the sensor by a softreset
    {
      local error=0; 
      s_connectionreset();              //reset communication
      error = s_write_byte( RESET);       //send RESET-command to sensor
      return error;                     //error=1 in case of no response form the sensor
    }
   
    //———————————————————————————-
    function  s_read_statusreg() {
    //———————————————————————————-
    // reads the status register with checksum (8-bit)
      local error=0;
      local ret = {};
      s_transstart();                   //transmission start
      error=s_write_byte(STATUS_REG_R); //send command to sensor
      ret.value <- s_read_byte(ACK);
      ret.checksum <- s_read_byte(noACK);
      ret.error <- error;
     
      return ret;                     //error=1 in case of no response form the sensor
    }
   
    //———————————————————————————-
    function s_write_statusreg( p_value)
    //———————————————————————————-
    // writes the status register with checksum (8-bit)
    {
      local error=0;
      s_transstart();                   //transmission start
      error= error+s_write_byte( STATUS_REG_W);//send command to sensor
      error= error+s_write_byte( p_value);    //send value of status register
      return error;                     //error>=1 in case of no response form the sensor
    }
                                   
   
    function s_getHumidity( ) {
        local timer=0.0;
        local data=0.0;
        local a;
        local b;
        local crc;
        local result=0;
        local errorString="";
   
        s_transstart();
        if (s_write_byte( MEASURE_HUMI)) {
            server.log("s_getHumidity:writing data error");
            return 0;
        }
       
        // wait up until 2 seconds for DATA to go low
        while (timer < 2 && data_get()) {
            imp.sleep(0.01);
            timer = timer + 0.01;
        }
        // see if an error occured (data_get is still high) 
        if (data_get()) {
            server.log("s_getHumidity:no response");
            return 0;
        }
       
   
        a = s_read_byte( ACK); //MSB
        b = s_read_byte( ACK); //LSB
     
        crc = s_read_byte( noACK); //checksum
        result = a<<8 | b;
       
    //    data = -4.0 + (result * 0.0405) – (0.0000028 *result * result); 
   
        return result;
    //    return data;
    }
   
    function s_getTemperature( ) {
        local timer=0.0;
        local data=0.0;
        local a;
        local b;
        local crc;
        local result=0;
        local errorString="";
   
        s_transstart();
        if (s_write_byte( MEASURE_TEMP)) {
            server.log("s_getTemperature:writing data error");
            return 0;
        }
       
        // wait up until 2 seconds for DATA to go low
        while (timer < 2) {
            if (data_get() == 0) break;
            imp.sleep(0.01);
            timer = timer + 0.01;
        }
        // see if an error occured (data_get is still high) 
        if (data_get()) {
            server.log("s_getTemperature:no response");
            return 0;
        }
   
        a = s_read_byte( ACK); //MSB
        b = s_read_byte( ACK); //LSB
        crc = s_read_byte( noACK); //checksum
        result = a<<8 | b;
   
    //    data = -40.2 + ( .018 * result );
    //    return data;
        return result;
    }
   
    //—————————————————————————————-
    function get()
    //—————————————————————————————-
    // calculates temperature [°C] and humidity [%RH]
    // input :  humi [Ticks] (12 bit)
    //          temp [Ticks] (14 bit)
    // output:  humi [%RH]
    //          temp [°C]
    { local C1=-4.0;              // for 12 Bit
      local C2=0.0405;           // for 12 Bit
      local C3=-0.0000028;        // for 12 Bit
      local T1=0.01;             // for 14 Bit @ 5V
      local T2=0.00008;           // for 14 Bit @ 5V   
      local rh_lin;                     // rh_lin:  Humidity linear
      local rh_true;                    // rh_true: Temperature compensated humidity
      local t_C;                        // t_C   :  Temperature [°C]
   
    //  s_connectionreset();
    // imp.sleep(1);
         
      local hum_data=s_getHumidity();             // rh:      Humidity [Ticks] 12 Bit
      local temp_data=s_getTemperature();           // t:       Temperature [Ticks] 14 Bit
   
   
      t_C=temp_data*0.01 – 40;                  //calc. temperature from ticks to [°C]
      rh_lin=C3*hum_data*hum_data + C2*hum_data + C1;     //calc. humidity from ticks to [%RH]
      rh_true=(t_C-25)*(T1+T2*hum_data)+rh_lin;   //calc. temperature compensated humidity [%RH]
      if(rh_true>100)rh_true=100;       //cut if the value is outside of
      if(rh_true<0.1)rh_true=0.1;       //the physical possible range
     
      local t_F = t_C * 9 / 5 + 32;
     
      local ret = {};
      ret.temp <- t_F;
      ret.humidity <- rh_true;
     
      return ret;
    }
}

 

sht <- SHT(); //instantiate class only once

local tempHum = sht.get(); //call as often as you want
server.log("temp="+tempHum.temp+" hum="+tempHum.humidity);

Electronics ,