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
An Electric Imp
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