Wireless Doorbell – Part 1

My new house currently has no doorbell and, whilst I could just buy a normal dumb wireless doorbell or install a wired doorbell, the temptation of making my own flexible system is too great. The majority of the sensors in the house communicate over MQTT, so this seemed the natural protocol to use for this project. Part one will focus on the creation of the bell push and the second part on the chime.

As the bell push will be powered from 2x AAA batteries, maximum power savings will be important. Therefore the ESP8266 will spend almost all of its time in deep sleep. Pressing the button will ground the reset pin and start at the beginning of the sketch. This will cause the ESP8266 to connect to the WiFi using a pre-defined IP address to save time, send an “ON” and battery level message to the MQTT broker, flash an LED for visual feedback for the person pushing the bell, and then go back to sleep. This circuit relies on the fact that the ESP8266 is capable of running down to about 2.2 volts, as a result a voltage regulator can be omitted which in turn avoids the issue of quiescent current which would shorten the battery life. The two capacitors across the power rails are there to handle that current spikes drawn by the ESP8266 when transmitting over WiFi.

Schematic

ESP8266 Arduino Sketch

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

// Configure ADC so ESP.getVcc() can be used
ADC_MODE(ADC_VCC);

// Debugging
#define DEBUG 1 // Set to 1 to output to serial
#define PRINT_DEBUG(STR) { if (DEBUG) Serial.println(STR); }

// Configure Network
const char* ssid = "YOURSSID";     // WiFi SSID
const char* password = "pa55w0rd";  // WiFi password
IPAddress ip(192, 168, 1, 3);       // IP Address - comma separated
IPAddress gateway(192, 168, 1, 1);  // Gateway Address - comma separated
IPAddress subnet(255, 255, 255, 0);   // Subnet Mask - comma separated
IPAddress dns(192, 168, 1, 1);      // DNS server - comma separated

// Configure MQTT
const char* mqtt_server = "192.168.1.2";               // MQTT server IP address
const char* voltagetopic = "HOME/doorbell/voltage";  // Topic to send voltage information
const char* statustopic = "HOME/doorbell/status";    // Topic to send button press status

WiFiClient espClient;
PubSubClient client(espClient);

// Connect to WiFi
void connectWifi(const char* ssid, const char* password) {
  int timeout;

  if (WiFi.status() != WL_CONNECTED) {
    PRINT_DEBUG("Connecting to " + String(ssid));
    WiFi.config(ip, gateway, subnet, dns);
    WiFi.begin(ssid, password);
    for (timeout = 0; (WiFi.status() != WL_CONNECTED) && (timeout < 1000); timeout ++) {
      delay(10);
    }
    if (WiFi.status() != WL_CONNECTED) {
      PRINT_DEBUG("WiFi connection failed");
    } else {
      PRINT_DEBUG("WiFi connected");
    }
  } else PRINT_DEBUG("WiFi already connected");

  PRINT_DEBUG("IP address: ");
  PRINT_DEBUG(WiFi.localIP());

}

// Flash the LED
void flashLED(float frequency, int duration, float duty){
  unsigned int off_interval = (1000.0 / frequency) * (1.0 - duty);
  unsigned int on_interval = (1000.0 / frequency) * (duty);

  while (duration > 0) {
    // LED off
    digitalWrite(0, HIGH);
    delay(off_interval);
    duration -= off_interval;
    
    if (duration > 0) {
      // LED on
      digitalWrite(0, LOW);
      delay(on_interval);
      duration -= on_interval;
    }
  }
  
  // Always Switch Off
  digitalWrite(0, HIGH);
}

void setup() {
  if (DEBUG) Serial.begin(115200);
  pinMode(0, OUTPUT);
  digitalWrite(0, HIGH); // LED off
  PRINT_DEBUG("Reset reason: " + ESP.getResetReason());
  connectWifi(ssid, password);
  client.setServer(mqtt_server, 1883);
}

void loop() {
  //if (WiFi.status() == WL_CONNECTED) digitalWrite(0, LOW); // LED on

  char volt[5];
  double voltage = ESP.getVcc() / 1000.0;
  dtostrf(voltage,5,4, volt);
  
  PRINT_DEBUG("Vcc: " + String(voltage) + "v");

  client.connect("ESP8266Client");
 
  bool v = client.publish(voltagetopic, volt);
  bool s = client.publish(statustopic, "ON");

  if (v && s) flashLED(0, 1000, 0.4);

  PRINT_DEBUG("Sleeping");
  pinMode(0, INPUT_PULLUP); // GPIO 0 back to high impedance mode
  ESP.deepSleep(0, RF_CAL);
}

You may also like...

1 Response

  1. kne says:

    Just added this to my Byron doorbell with a wemos D1 – Working well – Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *