Enter Your Electronics & Design Project for a chance to win a $100 Shopping Cart! | Project14 Home | |
Monthly Themes | ||
Monthly Theme Poll |
In part 1, Connor and I presented our three foundational blocks of Home Automation: Notification, Environmental Awareness, and Actuation. Part 2, we covered the first block - Notification. If you missed those blogs, you can check them out here: Home Automation Mojo You Must Know Part 1, Home Automation Mojo You Must Know Part
In this blog, we will dive into Environmental Awareness. To fully get the most out of Home Automation, you want your devices to have a mind of their own. In turn, they need to be fully aware of their environment so they can trigger appropriate actions.
In the devices that we'll build in Blog 5 of this series, we will use the following tech to survey our environment:
- Limit Switches
- Reed Switches Product LinkProduct Link(note these are sourced only through the UK with a freight fee)
- Nest Thermostat (Humidity, Room Temp, Away from Home, Fan Blowing, Heat On, AC On)
- Matrix Creator (Humidity, Temperature, Atmospheric Pressure, IMU, UV, Sound, Voice IR) Product LinkProduct Link
- PIR Sensors Product LinkProduct Link
- Moisture Sensors
- Temperature Probes Product LinkProduct Link
LIMIT SWITCHES
Limit Switches are great to sense when an actuator needs to stop, but it can also be set in its resting position. This could come in handy for things like lightening the interior of a cabinet. When the cabinet door opens, the light comes on. You could also use it to sensor windows opening as well, but most commonly, one would use a non-contact reed switch.
For further reading, here is a great blog on e14 that goes into the insides of a limit switches: How Limit Switches Can be Used as an Alternative to Sensors
Below is ESP8266 code to detect when a limit switch his hit that is wired to GPIO2 and ground:
#include <ESP8266WiFi.h> #include <WiFiClientSecure.h> constchar* ssid = "YOURSSID"; constchar* password = "YOURPASSWORD"; constchar* host = "api.pushbullet.com"; constint httpsPort = 443; constchar* PushBulletAPIKEY = "YOURPUSHBULLETKEY"; //get it from your pushbullet account // Use web browser to view and copy SHA1 fingerprint of the certificate. Click the lock by the address in the browser and then click view certificate. // Alternately, go to https://www.grc.com/fingerprints.htm and enter api.pushbullet.com constchar* fingerprint = "BB FC 9F 1B C1 3C D9 96 F2 68 A2 E3 41 29 D1 47 8F B9 33 BE"; void setup() { Serial.begin(115200); Serial.println(); Serial.print("connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); pushBullet("Booted"); pinMode(2,INPUT_PULLUP); } void pushBullet(String the_msg){ // Use WiFiClientSecure class to create TLS connection WiFiClientSecure client; Serial.print("connecting to "); Serial.println(host); if (!client.connect(host, httpsPort)) { Serial.println("connection failed"); return; } if (client.verify(fingerprint, host)) { Serial.println("certificate matches"); } else { Serial.println("certificate doesn't match"); } String url = "/v2/pushes"; String messagebody = "{\"type\": \"note\", \"title\": \"ESP8266\", \"body\": \""+the_msg+"\"}\r\n"; Serial.print("requesting URL: "); Serial.println(url); client.print(String("POST ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Authorization: Bearer " + PushBulletAPIKEY + "\r\n" + "Content-Type: application/json\r\n" + "Content-Length: " + String(messagebody.length()) + "\r\n\r\n"); client.print(messagebody); Serial.println("request sent"); //print the response while (client.available() == 0); while (client.available()) { String line = client.readStringUntil('\n'); Serial.println(line); } } void loop() { delay(200); if (digitalRead(2)==LOW) {//Wait for pin 2 to go to ground to trigger. pushBullet("Hello World!"); delay(5000); }
REED SWITCHES
Reed switches will either close or open a circuit when a magnet is nearby. This allows for non contact switching. However, they are still mechanical inside, so if you have fast switching such as to track wheel speed, use a Hal Effect Sensor instead. For our purposes, we just want to know if a window or door has opened, so a reed switch is the perfect device.
When I buy reed switches, I typically get the style that has a Normally Open or Normally Closed option. It doesn't add much to it and allows for flexibility. We will use a Normally Open reed in our window/door open detector. This will trigger a power latching circuit on an ESP8266 to ensure it boots up and sends our brain box a signal. Here is the circuit:
The code is the same as that of limit switches.
Nest Thermostat
If you have a Nest Thermostat, then you have a lot of data available. It even tracks if everyone is out of the home. This comes in very handy for auto arming custom IoT security.
You have to get you a Nest Developer account to access their API. Below is code to talk to your Nest Thermostat from an Arduino:
// include the library code: #include <WiFi101.h> //wifi setup char ssid[] = "YOURSSID";//REPLACE YOURSSID char pass[] = "YOURPASSWORD";//REPLACE YOURPASSWORD int keyIndex = 0; int status = WL_IDLE_STATUS; // Initialize the WiFi client library WiFiSSLClient client; String response; int statusCode = 0; void setup() { Serial.begin(9600); connectToAP(); // connect the board to the access point } void loop() { // set the cursor to column 0, line 1 // (note: line 1 is the second row, since counting begins with 0): getHumidity(); delay(5000); } void getHumidity(){ Serial.print("[making request]\n"); //sometimes I get redirected on the nest server. if (client.connectSSL("firebase-apiserver17-tah01-iad01.dapi.production.nest.com", 9553)) { Serial.print("[Connected!]\r\n"); delay(1000); client.println("GET /devices/thermostats/YOURSECRET/humidity HTTP/1.1"); //REPLACE YOURSECRET client.println("Host: firebase-apiserver17-tah01-iad01.dapi.production.nest.com"); client.println("Connection: close"); client.println("Content-Type: application/json"); client.println("Authorization: Bearer YOURBEARERCODE");//REPLACE YOURBEARERCODE client.println(); delay(3000); Serial.print("[Printed to client. Looping and waiting for data.]\n"); while (1==1) { if (client.available()) { char c = client.read(); Serial.write(c);//THIS WILL WRITE OUT THE HUMIDTY VALUE } else { Serial.print("\n[No Longer Available]\n"); client.stop(); break; } delay(10); } } } void connectToAP() { // check for the presence of the shield: Serial.print("\n\nconnecting WiFi\n"); // attempt to connect to Wifi network: while ( status != WL_CONNECTED) { // Connect to WPA/WPA2 network. Change this line if using open or WEP network: status = WiFi.begin(ssid, pass); // wait 3 second for connection: delay(3000); } Serial.print("[connected to wifi]\n\n"); }
To establish the necessary secret device code as shown in the lines 28 and 32, just follow the 7 quick steps in the Nest Guide: https://codelabs.developers.google.com/codelabs/wwn-api-quickstart/#0
Here is the code for the ESP8266:
/** * BasicHTTPClient.ino * * Created on: 24.05.2015 * */ #include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266WiFiMulti.h> #include <ESP8266HTTPClient.h> #define USE_SERIAL Serial ESP8266WiFiMulti WiFiMulti; void setup() { USE_SERIAL.begin(9600); // USE_SERIAL.setDebugOutput(true); USE_SERIAL.println(); USE_SERIAL.println(); USE_SERIAL.println(); for(uint8_t t = 4; t > 0; t--) { USE_SERIAL.printf("\n\n[SETUP] WAIT %d...\n", t); USE_SERIAL.flush(); delay(1000); } // Connect to WiFi WiFi.begin("YOURSSID","YOURPASSWORD"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); // Print the IP address Serial.println(WiFi.localIP()); } void loop() { // wait for WiFi connection if((WiFiMulti.run() == WL_CONNECTED)) { HTTPClient http; USE_SERIAL.print("[HTTP] begin...\n"); // configure traged server and url http.begin("https://firebase-apiserver17-tah01-iad01.dapi.production.nest.com:9553/devices/thermostats/YOUR THERMOSTAT CODE/humidity", "04 17 20 F0 E9 A9 FF 39 62 6C BB 92 31 F7 64 08 1C E0 16 94"); //HTTPS USE_SERIAL.print("[HTTP] GET...\n"); // start connection and send HTTP header http.addHeader("Content-Type","application/json"); http.addHeader("Authorization","Bearer YOUR BEARER"); int httpCode = http.GET(); // httpCode will be negative on error if(httpCode > 0) { if(httpCode == HTTP_CODE_OK) { String payload = http.getString(); USE_SERIAL.println(payload); } } else { USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); String payload = http.getString(); USE_SERIAL.println(payload); } http.end(); } delay(10000); }
Matrix Creator
The Matrix Creator is a hat for the Raspberry Pi. Throw a camera on it and you have the perfect Home Automation Hub. In Blog 6, we will use it to build our smart home hub.
The Matrix Creator has an array of 8 mics, making it great for Alexa implementation to "sense" voice and sound including direction of approach. To set up the Matrix Creator and get it ready for Alexa, here is their official guide: https://www.hackster.io/matrix-labs/matrix-voice-and-matrix-creator-running-alexa-c-version-9b9d8d
Below is C++ code to provide you with all sensor data from the Matrix. You would edit a text file (ie. sudo nano app.cpp) and paste this in it.
/* * Copyright 2016 <Admobilize> * MATRIX Labs [http://creator.matrix.one] * This file is part of MATRIX Creator HAL * * MATRIX Creator HAL is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <unistd.h> #include <cstdlib> #include <iomanip> #include <iostream> #include "matrix_hal/fw_data.h" #include "matrix_hal/humidity_data.h" #include "matrix_hal/humidity_sensor.h" #include "matrix_hal/imu_data.h" #include "matrix_hal/imu_sensor.h" #include "matrix_hal/matrixio_bus.h" #include "matrix_hal/mcu_firmware.h" #include "matrix_hal/pressure_data.h" #include "matrix_hal/pressure_sensor.h" #include "matrix_hal/uv_data.h" #include "matrix_hal/uv_sensor.h" namespace hal = matrix_hal; int main() { hal::MatrixIOBus bus; if (!bus.Init()) return false; hal::IMUSensor imu_sensor; imu_sensor.Setup(&bus); hal::PressureSensor pressure_sensor; pressure_sensor.Setup(&bus); hal::HumiditySensor humidity_sensor; humidity_sensor.Setup(&bus); hal::UVSensor uv_sensor; uv_sensor.Setup(&bus); hal::MCUFirmware mcu_firmware; mcu_firmware.Setup(&bus); hal::IMUData imu_data; hal::PressureData pressure_data; hal::HumidityData humidity_data; hal::UVData uv_data; hal::MCUData mcu_data; while (true) { mcu_firmware.Read(&mcu_data); imu_sensor.Read(&imu_data); pressure_sensor.Read(&pressure_data); humidity_sensor.Read(&humidity_data); uv_sensor.Read(&uv_data); std::system("clear"); std::cout << "yaw = " << imu_data.yaw << "°\t"; std::cout << "roll = " << imu_data.roll << "°\t"; std::cout << "pitch = " << imu_data.pitch << "°" << std::endl; std::cout << "accel = {" << imu_data.accel_x << ", " << imu_data.accel_y << "," << imu_data.accel_z << "}" << std::endl << std::endl; std::cout << "humidity = " << humidity_data.humidity << " %" << std::endl; std::cout << "temperature (from humidity sensor) = " << humidity_data.temperature << " °C" << std::endl << std::endl; std::cout << "pressure = " << pressure_data.pressure << " kPa" << std::endl; std::cout << "altitude = " << pressure_data.altitude << " meters" << std::endl; std::cout << "temperature (from altimeter) = " << pressure_data.temperature << " °C" << std::endl << std::endl; std::cout << "UV = " << uv_data.uv << std::endl << std::endl; std::cout << "MCU ID = 0x" << std::hex << mcu_data.ID << std::endl; std::cout << "MCU version = 0x" << mcu_data.version << std::endl << std::endl; usleep(200000); } return 0; }
You compile with the following line : g++ -o app app.cpp -std=c++11 -lmatrix_creator_hal
PIR Sensors
Passive Infrared Sensors are used for motion detection. They typically have 3 pins - on is a signal pin that is pulled up with a 10K resistor. The sensor takes an image of the surroundings and compares the signature over time. Any change in the radiation pattern, and it will pull the signal low or high depending on the manufacturer. We wouldn't want this happening all the time, so we will have our devices report to our Matrix Creator hub first. It will first check with the Nest to see if no one is home. If so, it will considered it "armed".
PIR Sensor code looks pretty much like limit switches. In the example Arduino code below, the PIR required a 10K pull down to switch.
const int LED = 3; const int motion = 7; void setup(){ Serial.begin(9600); pinMode(motion, INPUT);//A 10K pulldown resistor is mandatory. } //For the Panasonic EKMC1601111 PIR sensor: //Looking from the top down in with the offset middle facing away from you, the left is ground, middle signal, and right is //voltage. Voltage can be 3.3V or 5V. You get Vcc back from signal, so don't fry a 3.3V mC //A 10K pulldown resistor is mandatory. void loop(){ int readMotion = digitalRead(motion); Serial.println(readMotion); delay(150); }
MOISTURE SENSORS
A water pipe or hot water tank rupture can result in thousands of dollars of damage. If you are at work, having a 3/4" supply pipe gushing for hours will definitely make a memory. So, having a moisture sensor in key locations of the home are a great upgrade. They can actuate a shutoff valve to cut the water supply.
Moisture Sensors are a simpl device you simply lay on the lowest spot at the location of interest. For a hot water tank, a good spot would be by the relief valve discharge.
For our sensor, we will use the readily available hygrometers you often see for alerting when to water you plants. In our case, we'll trigger when we detect water.
Here is some simple code for detecting a water leak for an Arduino or ESP8266:
const int hygrometer = A0; //Hygrometer sensor analog pin output at pin A0 of Arduino int value; void setup(){ Serial.begin(9600); } void loop(){ value = analogRead(hygrometer); //Read analog value value = constrain(value,400,1023); //Keep the ranges! value = map(value,400,1023,100,0); //Map value : 400 will be 100 and 1023 will be 0 Serial.print("<10 Means Water is detected: "); Serial.print(value); Serial.println(); delay(2000); //pause for 2 seconds }
TEMPERATURE PROBES
Waterproof temperature probes are good for taking both ambient (air) temperature and the temperature of water. We will use one to check to see if the oven was left on.
Here is example code for the ESP8266 to call a IFTTT.com webhook if the temperature exceeds 100F and continues to do so for 20 minutes.
// Include the libraries we need #include "OneWire.h" #include "DallasTemperature.h" #include "ESP8266WiFi.h" #include "WiFiClientSecure.h" // Data wire is plugged into GPIO2 of the ESP8266 #define ONE_WIRE_BUS 2 const char* ssid = "........";//your home wifi router SSID const char* password = "........"; //your home wifi router password const char* host = "maker.ifttt.com";//we'll use IFTTT.com to trigger our Wemo Light Switch const int httpsPort = 443;//this is the SSL default port // Use web browser to view and copy // SHA1 fingerprint of the certificate const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C"; // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire); float myTemp = 0; unsigned long timer; unsigned long timeout; //used to monitor the temperature of oven. unsigned long duration = 10000; bool cooking = false;// used to keep track of assumed cooking is happening. /* * The setup function. We only start the sensors here */ void setup(void) { // Start up the Dallas temperature library sensors.begin(); } /* * Main function, get and show the temperature */ void loop(void) { sensors.requestTemperatures(); // Send the command to get temperatures. You can have many temperature probes on "one wire". myTemp = sensors.getTempCByIndex(0)*1.8 + 32; //convert to degrees F if (myTemp > 100 & !cooking) { cooking = true; timer = millis() + duration; timeout = millis() + (20 * 0 * 1000);//snap shot when this happened. Set a timeout to trigger webhook } if (cooking && (millis() > timer)) {//blink the light if beyond the duration HitIFTTT(); duration = duration / 4;//hit IFTTT again in a little bit timer = millis() + duration;//reset the timer } delay(1000);//just rest 1 second between polls for temperature } void HitIFTTT() { WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } // Use WiFiClientSecure class to create TLS connection WiFiClientSecure client; if (!client.connect(host, httpsPort)) { return; } //don't know if I actually needed this code from the example, so I kept the call anyway. if (client.verify(fingerprint, host)) { } //this just blinks the light String url = "/trigger/YourBlinkerEvent/with/key/YourWebHook";//change this to the IFTTT URL that toggles the lightswitch. //if in too long, then turn the light out for good. if (cooking && ((millis() > timeout))) { url = "/trigger/YourKillTheLightEvent/with/key/YourWebHook";//change this to the IFTTT URL that turns off the lightswitch } client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: BuildFailureDetectorESP8266\r\n" + "Connection: close\r\n\r\n"); // Send the hit to IFTTT.com at the above URL while (client.connected()) { String line = client.readStringUntil('\n'); if (line == "\r") { break; } } String line = client.readStringUntil('\n'); }
ENVIRONMENTAL AWARENESS CONCLUSION
With these sensors, we will have the following environmental data for our code to consider:
- Object Position
- Object Orientation
- Movement
- Room Temp
- Object Temperature
- Ambient Temp/Local Weather
- Indoor Humidity
- Atmospheric Pressure
- Away from Home Status
- Sound
- Voice
- Water Leaks
That will definitely be enough to secure and automate our home. In the next blog, we will explore our third and final foundational block to Home Automation - Actuation. After that, in Blog 5, we will build our devices. Then last, in Blog 6, we will bring it all together with our Home Automation Hub.
See ya',
Sean
Top Comments