Description:
This is the research project to understand the home automation system which I would like to develop when I'm building my own house in the future. Burglary is a common threat while living in South Auckland. My wife's mountain bike was stolen from the garage in our first year living in the South Auckland. Even though we have moved to different house and living in better neighbourhood now, always worried and paranoid about the garage door. So this project developed to monitor the garage door and alert if the door is open.
Some of the terminology used in this post:
Home Assistant - Home Assistant is an open-source home automation platform running on Python 3. Track and control all devices at home and automate control. Many components are supported well by Home assistant community (Wemo, Amazon Echo, Google Home, Google Assistant, Zigbee, MQTT, IFTT, etc..)
ESP8266 NodeMcu v3 wifi module development control board, accepts Arduino.
AWS - Amazon Web Service - various development tools, products and services are offered. First year subscription is free.
Hardware Components:
- ESP8266 NodeMcu v3 wifi module development control board ( ~ $4 from Aliexpress)
- Magnetic Reed Switch MC-38 (~$2 from Aliexpress)
- Enclosure box (~$2 from Aliexpress)
- Female to Female Jumper Wire
- USB Charger Cable (Recycled from house)
- Power Bank (Recycled from the house) - identified that it only survives for two days. better to use the plug point if you have one near the door. in my case i do not have one.
Building the door sensor
Below steps describes the step by step procedure for building the door sensor. This is completely inspired by Simpleiothings.com (check out he has some pretty cool stuff)
- Create an opening in the rear of the enclosure for the micro-usb power cable and in the front of the enclosure for the jumper wires.
- Take two jumper wires, at the end of each wire is a plastic housing covering some metal. Remove the plastic housing using a needle or safety pin, and find a small tab in the plastic housing. Lifted up on the plastic tab. Once lifted up, smoothly removed the wire from the plastic housing. This is for one side only.
- Take MC-38 sensor, exposed wires and connected female jumper wires to these exposed sensor wires by crimping (compress with pliers to create a firm connection), use tape to insulate the exposed wires. plug the other end of the jumper wire into D5 and GND on the development board.
- Connect the micro-usb cable for powering up the bo
Software
Note: Below software components was developed using macOS.
Pre-requisties
Following software should be installed:
- Python latest version
- Home assistant
- Arduino IDE (Install and include ESP8266 and Pubsubclient libraries)
- 340G driver
MQTT Broker
First step is to get MQTT and Home Assistant working is to choose a broker. Home Assistant contains an embedded MQTT broker called HBMQTT. but Home assistant issued an warning that there is an memory leak issue. So I have decided to use mosquitto platform until this issue has been fixed.
For better security, create your own MQTT broker. This can be done using amazon web services - EC2 Instance, helps to run Linux based Virtual Machine and host MQTT broker on the same. EC2 instance uses key pair to securely access Linux instance using SSH. AWS stores the public part of the key pair which is just like a house lock, download and use the private part of the key pair which is just like a house key. Step by step procedure for creating own MQTT broker is explained in the medium post here
To use the MQTT broker, Linux need to be running in the machine. use the following code in terminal window (MacOS)
xxxxxxMBP3:~ foldername$ ssh -i ~/.ssh/MyKeyPair.pem username@aa.bb.cc.dd (ip address).
Sensor specific software with Arduino
Originally code was developed for monitoring the status of the garage door as well as operating it. At the moment this post only covers the status of the garage door, Just ignore the nuisance for relay if there is any.
/*
Garage Door
ESP8266-based MQTT Garage Door Sensor
*/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SoftwareSerial.h>
SoftwareSerial ESPserial(11, 12);
// Mapping NodeMCU Ports to Arduino GPIO Pins
// Allows use of NodeMCU Port nomenclature in config.h
#define D0 16
#define D1 5
#define D2 4
#define D3 0
#define D4 2
#define D5 14
#define D6 12
#define D7 13
#define D8 15
const char* ssid = "your wifi ssid";
const char* password = "your wifi password";
const boolean static_ip = true of false;
IPAddress ip(ip address);
IPAddress gateway(gateway);
IPAddress subnet(subnet);
const char* mqtt_broker = "your mqtt broker (i.e ip address)";
const char* mqtt_clientId = "Garage_Door";
const char* mqtt_username = "mqtt username";
const char* mqtt_password = "mqtt password";
const char* garagedoor_alias = "Garage Door";
const char* mqtt_garagedoor_status_topic = "garage/door/status";
const int garagedoor_statusPin = D5;
const char* garagedoor_statusSwitchLogic = "NO or NC"
int garagedoor_lastStatusValue = 2;
unsigned long garagedoor_lastSwitchTime = 0;
int debounceTime = 2000;
String availabilityBase = "Garage_Door";
String availabilitySuffix = "/availability";
String availabilityTopicStr = availabilityBase + availabilitySuffix;
const char* availabilityTopic = availabilityTopicStr.c_str();
const char* birthMessage = "online";
const char* lwtMessage = "offline";
WiFiClient espClient;
PubSubClient client(espClient);
// Wifi setup function
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.print(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (static_ip) {
WiFi.config(ip, gateway, subnet);
}
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print(" WiFi connected - IP address: ");
Serial.println(WiFi.localIP());
}
// Callback when MQTT message is received;
passing topic and payload as parameters
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
String topicToProcess = topic;
payload[length] = '\0';
String payloadToProcess = (char*)payload;
triggerDoorAction(topicToProcess, payloadToProcess);
}
// Functions that check door status and publish an update when called
void publish_garagedoor_status() {
if (digitalRead(garagedoor_statusPin) == LOW) {
if (garagedoor_statusSwitchLogic == "NO") {
Serial.print(garagedoor_alias);
Serial.print(" closed! Publishing to ");
Serial.print(mqtt_garagedoor_status_topic);
Serial.println("...");
client.publish(mqtt_garagedoor_status_topic, "closed", true);
}
else if (garagedoor_statusSwitchLogic == "NC") {
Serial.print(garagedoor_alias);
Serial.print(" open! Publishing to ");
Serial.print(mqtt_garagedoor_status_topic);
Serial.println("...");
client.publish(mqtt_garagedoor_status_topic, "open", true);
}
else {
Serial.println("Error! Specify only either NO or NC! Not publishing...");
}
}
else {
if (garagedoor_statusSwitchLogic == "NO") {
Serial.print(garagedoor_alias);
Serial.print(" open! Publishing to ");
Serial.print(mqtt_garagedoor_status_topic);
Serial.println("...");
client.publish(mqtt_garagedoor_status_topic, "open", true);
}
else if (garagedoor_statusSwitchLogic == "NC") {
Serial.print(garagedoor_alias);
Serial.print(" closed! Publishing to ");
Serial.print(mqtt_garagedoor_status_topic);
Serial.println("...");
client.publish(mqtt_garagedoor_status_topic, "closed", true);
}
else {
Serial.println("Error! Specify only either NO or NC! Not publishing...");
}
}
}
// Functions that run in loop() to check each loop if garage door status (open/closed) has changed and call publish_garagedoor_status() to publish any change if so
void check_garagedoor_status() {
int currentStatusValue = digitalRead(garagedoor_statusPin);
if (currentStatusValue != garagedoor_lastStatusValue) {
unsigned int currentTime = millis();
if (currentTime - garagedoor_lastSwitchTime >= debounceTime) {
publish_garagedoor_status();
garagedoor_lastStatusValue = currentStatusValue;
garagedoor_lastSwitchTime = currentTime;
}
}
}
// Function that publishes birthMessage
void publish_birth_message() {
// Publish the birthMessage
Serial.print("Publishing birth message \"");
Serial.print(birthMessage);
Serial.print("\" to ");
Serial.print(availabilityTopic);
Serial.println("...");
client.publish(availabilityTopic, birthMessage, true);
}
// Function that runs in loop() to connect/reconnect to the MQTT broker, and publish the current door statuses on connect
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(mqtt_clientId, mqtt_username, mqtt_password, availabilityTopic, 0, true, lwtMessage)) {
Serial.println("Connected!");
// Publish the birth message on connect/reconnect
publish_birth_message();
}
else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
// Set input pin to use internal pullup resistor
pinMode(garagedoor_statusPin, INPUT_PULLUP);
// Update variable with current door state
garagedoor_lastStatusValue = digitalRead(garagedoor_statusPin);
// Setup serial output, connect to wifi, connect to MQTT broker, set MQTT message callback
Serial.begin(9600);
ESPserial.begin(115200);
ESPserial.println("AT+IPR=9600");
delay(1000);
// Start the software serial for communication with the ESP8266
ESPserial.begin(9600);
Serial.println("Ready");
ESPserial.println("AT+GMR");
setup_wifi();
client.setServer(mqtt_broker, 1883);
client.setCallback(callback);
}
void loop() {
// Connect/reconnect to the MQTT broker and listen for messages
if (!client.connected()) {
reconnect();
}
client.loop();
// Check door open/closed status each loop and publish changes
check_garagedoor_status();
}
[/code]
Flash and upload the sketch into the controller
- While pressing reset button, press the flash button in the ESP8266 board.
- then release the reset button.
- press upload the sketch under Sketch menu (Sketch>Upload)
Once sketch uploaded into the controller, select serial monitor under Tools menu for testing and press the reset button to listen to the controller.
Home-assistant
Setting up the home assistant is not covered in this post, refer to the website for installation and initial configuration.
Find .Homeassistant (hidden folder) in your user directory, open configuration .yaml file. set up your home location, latitude, longitude, elevation, unit system, time zone as follows
code :
homeassistant:
# Name of the location where Home Assistant is running
name: Home
# Location required to calculate the time the sun rises and sets
latitude: xx.xx
longitude: yy.yy
# Impacts weather/sunrise data (altitude above sea level in meters)
elevation: zz
# metric for Metric, imperial for Imperial
unit_system: metric
# Pick yours from here: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
time_zone: Pacific/Auckland
# Customization file
customize: !include customize.yaml
There are some default options which you can either use it or un use it with # in front of the code line. i will just directly jump into the related code for this post. To configure MQTT, enter the code as follows in configuration,yaml:
# MQTT
mqtt:
broker: aa.bb.cc.dd (ip address)
port: 1883
client_id: Garage_door
username: username
password: password
Configuration for sensor status using mqtt cover as follows. To know more about this click here.
cover:
- platform: mqtt
name: "Garage_Door"
state_topic: "garage/door/status"
availability_topic: "Garage_door/availability"
qos: 0
payload_open: "OPEN"
payload_close: "CLOSE"
payload_available: "online"
payload_not_available: "offline"
Notifications - I have used pushbullet service as notification service. i have tried using AWS SNS service. They worked pretty good as well. there are various options for notifications, click here to know more about them. Configuration for pushbullet notification as follows:
notify:
platform: pushbullet
api_key: "your API key"
name: GarageDoorpushbullet
for AWS:
notify:
platform: aws_sns
aws_access_key_id: aws access key
aws_secret_access_key: aws secret key
region_name: region
So all the components are configured now. next step is to automate using the parameters.
open animations.yaml and enter the below code
- id: garage_door_status
alias: "Notify when garage door is open"
trigger:
- platform: state
entity_id: cover.Garage_Door
to: open
action:
- service: notify.GarageDoorpushbullet
data_template:
message: "Garage Door is Open"
Testing
- Install the hardware components to the location
- Run the software
- MQTT broker linux virtual machine
- Home assistant in a separate terminal window
then type http://localhost:8123 in you browser to access the home assistant frontend.
See below video for the complete operation of system.
Inspired by : Matthieu Bila, Home Assistant and SimpleIOthings
Comments
Post a Comment