IoT Projects

Turn a fan on when the temperature is too high! - Electric Imp Tutorial

Luis Duarte
· 7 min read
Send by email

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 the temperature is below 27ºC.

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

Materials

electricimp

impboard

  • Three female to female wires

female-Wiresjpg

  • 10k resistor

10kresistor

  • DHT11 humidity and temperature sensor

dh11

-A little fan

fan

-A PowerSwitch tail

power

Wiring

This is how all the components should be connected:

tempImprelay

…and just one thing left: plug in your fan!

Coding

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

Impurl

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 handler
http.onrequest(requestHandler);
  • 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 sensor
class 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();

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:

Event_step1

  • Choose Electric imp as source and temperature (temp) as a variable.

Event_Step2

  • Put a condition when the temp is over 30ºC.

Event_step3

  • Choose Request URL ” and type your Imp URL plus “?relay=1”

Event_step4

  • Add another event with this conditional.

Event_step5

  • Choose “Request URL” and type your Imp URL plus “?relay=0”

Event_step6

Wrapping up

In this project, we were able to control an electric fan from the 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, check out this great starter piece and sign up for free today!