All Collections
IoT Projects Tutorials
Use Electric Imp to measure Human Thermal Comfort with Ubidots
Use Electric Imp to measure Human Thermal Comfort with Ubidots

Logging Temperature, Humidity and Dew Point with Electric Imp

David Sepúlveda avatar
Written by David Sepúlveda
Updated over a week ago

The Electric Imp is an amazing device for IoT projects and its integration with Ubidots makes it very simple to create graphs and SMS/Email alerts in a few minutes. This Electric Imp tutorial we'll teach you how use the Electric Imp breakout board with a DHT11 sensor to measure temperature and relative humidity, and then compute the Dew Point using Ubidots' math engine.

The Dew point can be used as an index for human perception of comfort in relation to the weather; a dew point between 13-16°C (55-59°F) makes you feel comfortable, but a Dew point above 21°C (70°F) will make you feel too warm because the air would have too much moisture and your body couldn't cool down:

Dew Point Human perception 24-26 °C 75-80°F Extremely uncomfortable, oppressive 21-24 °C 70-74°F Very Humid, quite uncomfortable 18-21 °C 65-69°F Somewhat uncomfortable for most people at upper edge 16-18 °C 60-64°F OK for most, but all perceive the humidity at upper edge 13-16 °C 55-59°F Comfortable 10-12 °C 50-54°F Very comfortable Under 10 °C Under 50°F A bit dry 

Luckily, there's a linear function to compute Dew point based on temperature and relative humidity.

 

1. Materials

  • An Imp

  • An Electric Imp Breakout Board 

  • Three female to female wires

  • 10k resistor

  • DHT11 humidity and temperature sensor

2. Wiring

Here's how the DHT11 sensor is wired to your Electric Imp board:

3. Code

Time to code! when working with Electric imp, you'll need two sections of code: one for device and another one for the agent. Here's the device code (a bit long since it has the class to handle the DHT11):

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);    }}rele <- hardware.pin9;spi  <- hardware.spi257;while(1){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);imp.sleep(1);}

view rawdevice.nut hosted with ❤ by GitHub

Thanks to Thomas Byrne for providing the class to handle the DHT11 sensor in Github.

As you can see, the Agent code is really simple, just don't forget to put your own auth token and Variable ID in the HTTP call:

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();});

view rawagent.nut hosted with ❤ by GitHub

4. Create a derived variable on Ubidots.

Just as you would add a new variable, go "Sources"--> "Electric Imp (your datasource name)"-->"Add new Variable":

Now enter this equation to calculate Dew point Value:

You should now see the Dew point data update every time your Imp pushed Temp and Humidity data to Ubidots!

5. Wrapping up

In this project we were able to connect an Imp to Ubidots, measuring and calculating physical variables to better understand our surroundings. You can explore more things like creating alerts when the Dew point is to high, or creating shareable graphs like the ones at the beginning of this article. 

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 18, 2014.

Did this answer your question?