In our last Electric Imp tutorial we learned how to measure temperature, humidity and overall thermal comfort with Ubidots. This time we are going to make a simple on-off fan control. We will log the temperature to Ubidots and trigger an event when it is over 30ºC, so that the Electric Imp turns on a fan, and then a trigger to turn it off when temperature is below 27ºC.

It really works like a charm, so here we go:

1. Materials

  • Three female to female wires
  • 10k resistor
  • DHT11 humidity and temperature sensor
  • A fan

3. Wiring

Connect components as follows:

 

...and just one more thing: plug in your fan!

4. Coding

  • Login to the Electric Imp IDE and take note of the url of your Imp:

Copy the next two codes. In the Agent code we will use a function to handle http requests to Ubidots, don't forget to put your Ubidots' token and variables id  .

  • Agent Code:
device.on("temp", function(value) {    //server.log("Trying to post to Ubi the value:");    //server.log(value);    local headers = { "Content-Type": "application/json", "X-Auth-Token": "NBbF3PWPxWc2IaO40aXOKnhIu8tOv92rYN3ibiEc7Jh6GV3KZUUCHtXuNz7Y" }; // Replace the token with yours    local url = "http://things.ubidots.com/api/v1.6/variables/53d2beb37625424630223dac/values"; // Replace the Variable ID with yours    local string = {"value": value};    local request = http.post(url, headers, http.jsonencode(string));    local response = request.sendsync();});device.on("hum", function(value) {    //server.log("Trying to post to Ubi the value:hola");    //server.log(value);    local headers = { "Content-Type": "application/json", "X-Auth-Token": "NBbF3PWPxWc2IaO40aXOKnhIu8tOv92rYN3ibiEc7Jh6GV3KZUUCHtXuNz7Y" }; // Replace the token with yours    local url = "http://things.ubidots.com/api/v1.6/variables/53e541e57625422c7d900a1d/values"; // Replace the Variable ID with yours    local string = {"value": value};    local request = http.post(url, headers, http.jsonencode(string));    local response = request.sendsync();});function requestHandler(request, response) {  try {    // check if the user sent led as a query parameter    if ("relay" in request.query) {      server.log("entre");      // if they did, and led=1.. set our variable to 1      if (request.query.relay == "1" || request.query.relay == "0") {        // convert the led query parameter to an integer        local relayState = request.query.relay.tointeger();        // send "led" message to device, and send ledState as the data        device.send("relay", relayState);       }    }    // send a response back saying everything was OK.    response.send(200, "OK");  } catch (ex) {    response.send(500, "Internal Server Error: " + ex);  }} // register the HTTP handlerhttp.onrequest(requestHandler);

view rawtempandRelayAgent.nut hosted with ❤ by GitHub

  • Device Code:

Note the last part of the code where there's a function to turn on/off the fan with the Powerswitch tail.

const SPICLK = 937.5;// Class to read the DHT11 temperature/humidity sensor// These sensors us a proprietary one-wire protocol. The imp// emulates this protocol with SPI. // To use://  - tie MOSI to MISO with a 10k resistor//  - tie MISO to the data line on the sensorclass DHT11 {    static STARTTIME_LOW     = 0.001000;    // 1 ms low time for start    static STARTTIME_HIGH    = 0.000020;  // 20 us min high time for start    static STARTTIME_SENSOR  = 0.000080;  // 80 us low / 80 us high "ACK" from sensor on START    static MARKTIME          = 0.000050;  // 50 us low pulse between 0 or 1 marks    static ZERO              = 0.000026; // 26 us high for "0"    static ONE               = 0.000075;  // 70 us high for "1"        spi                 = null;    clkspeed            = null;    bittime             = null;    bytetime            = null;    start_low_bits      = null;    start_low_bytes     = null;    start_high_bits     = null;    start_high_bytes    = null;    start_ack_bits      = null;    start_ack_bytes     = null;    mark_bits           = null;    mark_bytes          = null;    zero_bits           = null;    zero_bytes          = null;    one_bits            = null;    one_bytes           = null;        // class constructor    // Input:     //      _spi: a pre-configured SPI peripheral (e.g. spi257)    //      _clkspeed: the speed the SPI has been configured to run at    // Return: (None)    constructor(_spi, _clkspeed) {        this.spi = _spi;        this.clkspeed = _clkspeed;            bittime     = 1.0 / (clkspeed * 1000);        bytetime    = 8.0 * bittime;                start_low_bits      = STARTTIME_LOW / bittime;        start_low_bytes     = (start_low_bits / 8);        start_high_bits     = STARTTIME_HIGH / bittime;        start_high_bytes    = (start_high_bits / 8);        start_ack_bits      = STARTTIME_SENSOR / bittime;        start_ack_bytes     = (start_ack_bits / 8);        mark_bits           = MARKTIME / bittime;        mark_bytes          = (mark_bits / 8);        zero_bits           = ZERO / bittime;        zero_bytes          = (zero_bits / 8);        one_bits            = ONE / bittime;        one_bytes           = (one_bits / 8);    }        // helper function    // given a long blob, find times between transitions and parse to     // temp and humidity values. Assumes 40-bit return value (16 humidity / 16 temp / 8 checksum)    // Input:     //      hexblob (blob of arbitrary length)    // Return:     //      table containing:    //          "rh": relative humidity (float)    //          "temp": temperature in celsius (float)    //      if read fails, rh and temp will return 0    function parse(hexblob) {        local laststate     = 0;        local lastbitidx    = 0;                local gotack        = false;        local rawidx        = 0;        local result        = blob(5); // 2-byte humidity, 2-byte temp, 1-byte checksum            local humid         = 0;        local temp          = 0;                // iterate through each bit of each byte of the returned signal        for (local byte = 0; byte < hexblob.len(); byte++) {            for (local bit = 7; bit >= 0; bit--) {                                local thisbit = (hexblob[byte] & (0x01 << bit)) ? 1:0;                                if (thisbit != laststate) {                    if (thisbit) {                        // low-to-high transition; watch to see how long it is high                        laststate = 1;                        lastbitidx = (8 * byte) + (7 - bit);                    } else {                        // high-to-low transition;                        laststate = 0;                        local idx = (8 * byte) + (7 - bit);                        local hightime = (idx - lastbitidx) * bittime;                                                // we now have one valid bit of info. Figure out what symbol it is.                        local resultbyte = (rawidx / 8);                        local resultbit =  7 - (rawidx % 8);                        //server.log(format("bit %d of byte %d",resultbit, resultbyte));                        if (hightime < ZERO) {                            // this is a zero                            if (gotack) {                                // don't record any data before the ACK is seen                                result[resultbyte] = result[resultbyte] & ~(0x01 << resultbit);                                rawidx++;                            }                        } else if (hightime < ONE) {                            // this is a one                            if (gotack) {                                result[resultbyte] = result[resultbyte] | (0x01 << resultbit);                                rawidx++;                            }                        } else {                            // this is a START ACK                            gotack = true;                        }                    }                }            }        }                //server.log(format("parsed: 0x %02x%02x %02x%02x %02x",result[0],result[1],result[2],result[3],result[4]));        humid = (result[0] * 1.0) + (result[1] / 1000.0);        if (result[2] & 0x80) {            // negative temperature            result[2] = ((~result[2]) + 1) & 0xff;        }        temp = (result[2] * 1.0) + (result[3] / 1000.0);        if (((result[0] + result[1] + result[2] + result[3]) & 0xff) != result[4]) {            return {"rh":0,"temp":0};        } else {            return {"rh":humid,"temp":temp};        }    }        // read the sensor    // Input: (none)    // Return:    //      table containing:    //          "rh": relative humidity (float)    //          "temp": temperature in celsius (float)    //      if read fails, rh and temp will return 0    function read() {        local bloblen = start_low_bytes + start_high_bytes + (40 * (mark_bytes + one_bytes));        local startblob = blob(bloblen);        for (local i = 0; i < start_low_bytes; i++) {            startblob.writen(0x00,'b');        }        for (local j = start_low_bytes; j < bloblen; j++) {            startblob.writen(0xff,'b');        }                //server.log(format("Sending %d bytes", startblob.len()));        local result = spi.writeread(startblob);        return parse(result);    }}relay <- hardware.pin8;spi  <- hardware.spi257;rele.configure(DIGITAL_OUT);function setRelay(relayState){    server.log("relayState:" + relayState );    relay.write(relayState);}  agent.on("relay", setRelay);function mainLoop(){imp.wakeup(1.0, mainLoop);clkspeed <- spi.configure(MSB_FIRST, SPICLK);dht11 <- DHT11(spi, clkspeed);data <- dht11.read();server.log(format("Relative Humidity: %0.1f",data.rh)+" %");server.log(format("Temperature: %0.1f C",data.temp));agent.send("temp",data.temp);agent.send("hum",data.rh);}mainLoop();

view rawtempandRelayDevice.nut hosted with ❤ by GitHub

5. Set up Ubidots Events

  • In your Ubidots account, create one data source with two variables: Temperature and Humidity
  • Click on the "Events" section and add one:
  • Choose Electric imp as source and temperature (temp) as variable.
  • Put a condition when temp is over 30ºC.
  • Choose Request URL " and type your Imp URL plus "?relay=1"
  • Add another event with this conditional.
  • Choose "Request URL"  and type your Imp URL plus "?relay=0"

5. Wrapping up

In this project we were able to control an electric fan from internet with Electric Imp. Just as we controlled a fan using temperature data, you could also log any other data and take actions based on it. For example, you could open your garage door whenever your cat approaches a motion sensor (meaning it wants to go out!).

Don't forget to check out some of our latest posts:

If you're new to Ubidots, click below to get started!

Originally Published in Ubidots Blog August 26, 2014

Did this answer your question?