Turn a fan on when the temperature is too high! - Electric Imp Tutorial
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
- An Electric Imp
- Three female to female wires
- 10k resistor
- DHT11 humidity and temperature sensor
-A little fan
Wiring
This is how all the components should be connected:
…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:
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:
- Choose Electric imp as source and temperature (temp) as a variable.
- Put a condition when the 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”
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!