Saturday, January 13, 2018

Simple MQTT Doorbell Notifier

Welcome to the first project of my blog.  It's a doorbell notifier for my smart home.

I'll start out with some of the tech I'm using.  Home Assistant on a Raspberry Pi 3 (Hass.io).  I have an MQTT server on the Hass.io that I like to use for sensors that I build.  I've been using NodeMCU boards recently to make WiFi projects, but I've also played with the Wemos ESP8266 boards as well.

I recently wanted to start tracking when the doorbell has been rung.  After brainstorming and researching many options, I decided to make a battery operated WiFi sensor that would send MQTT messages to Hass.io.

I started the project by heavily paring down some code from BruhAutomation for his multisensor.  That's a brilliant project and have found mine quite useful.  I used the Arduino IDE to load this onto a NodeMCU board:

/*
  .______   .______    __    __   __    __          ___      __    __  .___________.  ______   .___  ___.      ___   .___________. __    ______   .__   __.
  |   _  \  |   _  \  |  |  |  | |  |  |  |        /   \    |  |  |  | |           | /  __  \  |   \/   |     /   \  |           ||  |  /  __  \  |  \ |  |
  |  |_)  | |  |_)  | |  |  |  | |  |__|  |       /  ^  \   |  |  |  | `---|  |----`|  |  |  | |  \  /  |    /  ^  \ `---|  |----`|  | |  |  |  | |   \|  |
  |   _  <  |      /  |  |  |  | |   __   |      /  /_\  \  |  |  |  |     |  |     |  |  |  | |  |\/|  |   /  /_\  \    |  |     |  | |  |  |  | |  . `  |
  |  |_)  | |  |\  \-.|  `--'  | |  |  |  |     /  _____  \ |  `--'  |     |  |     |  `--'  | |  |  |  |  /  _____  \   |  |     |  | |  `--'  | |  |\   |
  |______/  | _| `.__| \______/  |__|  |__|    /__/     \__\ \______/      |__|      \______/  |__|  |__| /__/     \__\  |__|     |__|  \______/  |__| \__|
  Thanks much to @corbanmailloux for providing a great framework for implementing flash/fade with HomeAssistant https://github.com/corbanmailloux/esp-mqtt-rgb-led
  To use this code you will need the following dependancies: 
  
  - Support for the ESP8266 boards. 
        - You can add it to the board manager by going to File -> Preference and pasting http://arduino.esp8266.com/stable/package_esp8266com_index.json into the Additional Board Managers URL field.
        - Next, download the ESP8266 dependancies by going to Tools -> Board -> Board Manager and searching for ESP8266 and installing it.
  
  - You will also need to download the follow libraries by going to Sketch -> Include Libraries -> Manage Libraries
      - DHT sensor library 
      - Adafruit unified sensor
      - PubSubClient
      - ArduinoJSON
    
  UPDATE 16 MAY 2017 by Knutella - Fixed MQTT disconnects when wifi drops by moving around Reconnect and adding a software reset of MCU
             
  UPDATE 23 MAY 2017 - The MQTT_MAX_PACKET_SIZE parameter may not be setting appropriately do to a bug in the PubSub library. If the MQTT messages are not being transmitted as expected please you may need to change the MQTT_MAX_PACKET_SIZE parameter in "PubSubClient.h" directly.
*/

// MODIFIED BY D SMYTH TO DETECT A DOORBELL ELECTROMAGNET

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

/************ WIFI and MQTT INFORMATION (CHANGE THESE FOR YOUR SETUP) ******************/
#define wifi_ssid "YOUR_SSID" //type your WIFI information inside the quotes
#define wifi_password "YOUR_PASSWORD"
#define mqtt_server "192.168.X.X"
#define mqtt_user "MQTT_USER
#define mqtt_password "MQTT_PASSWORD"
#define mqtt_port 1883

/************* MQTT TOPICS (change these topics as you wish)  **************************/
#define state_topic "home/doorbell/frontdoor"
#define SENSORNAME "doorbell_sensor"
const char* on_cmd = "ON";
const char* off_cmd = "OFF";

/**************************** SENSOR DEFINITIONS *******************************************/

char message_buff[100];

int calibrationTime = 0;

const int BUFFER_SIZE = 300;

#define MQTT_MAX_PACKET_SIZE 512


/******************************** GLOBALS for fade/flash *******************************/
bool stateOn = true;
WiFiClient espClient;
PubSubClient client(espClient);

/********************************** START SETUP*****************************************/
void setup() {
  Serial.begin(115200);
  Serial.println("Starting Node named " + String(SENSORNAME));
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  Serial.println("Ready");
  reconnect();
  sendState();
  delay(1000);
  stateOn = false;
  sendState();
  delay(10);
  ESP.deepSleep(1);
}

/********************************** START SETUP WIFI*****************************************/
void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

/********************************** START SEND STATE*****************************************/
void sendState() {
  StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;

  JsonObject& root = jsonBuffer.createObject();

  root["state"] = (stateOn) ? on_cmd : off_cmd;
  char buffer[root.measureLength() + 1];
  root.printTo(buffer, sizeof(buffer));

  Serial.println(buffer);
  client.publish(state_topic, buffer, true);
}

/********************************** START RECONNECT*****************************************/
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(SENSORNAME, mqtt_user, mqtt_password)) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

/********************************** START MAIN LOOP***************************************/
void loop() {
}

/****reset***/
void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
Serial.print("resetting");
ESP.reset(); 
}

Then I had to add a few lines to the "configuration.yaml" file on Hass.io.

binary_sensor:
  - platform: mqtt
    state_topic: "home/doorbell/frontdoor"
    name: "Doorbell"
    value_template: '{{ value_json.state }}'

This completed the programming for the board.  When the NodeMCU powered up, it sends an "ON" message to the MQTT server and then after a second it sends an "OFF" message.  I connected a simple reed switch between the RST and GND pins on the NodeMCU board to reset the code any time the doorbell rings.

I have some Z-wave sensors that I use and work on battery, so I had some extra 123 batteries around and wanted to use one to power the sensor.  I connected the battery directly to the GND and 3V3 pins and found that it worked great!

Then I measured the current draw and found that the battery had a 30mA drain on it while the ESP8266 was in deep sleep.  :(

A little googling later, I found this blog and followed it to disconnect the voltage regulator and the USB-to-serial adapter using a quick touch of the soldering iron, an exacto knife and a resistor.  I had to play with the resistor value because the board still didn't start correctly with a 1 Mohm resistor.  In the end, I left the deep sleep current around 80 microAmps.  That should be low enough to keep it going for a year or so.

I used my 3D printer to print a holder for the 123 battery and will print another to hold the whole sensor.  I will hang it up next to my doorbell and my home will be that much smarter.

That was fun!

I'm sure I skipped over a lot of details of what to do and such.  If you feel really lost, but want to learn more, I would recommend starting with the BruhAutomation guides.

Good Luck!

No comments:

Post a Comment