Friday, April 21, 2023

Connecting a 12volt doorbell to an ESP and Domoticz

For an index to all my stories click here

We have an old doorbell. Not the new wireless stuff but an old one working with a 12 volt AC transformer and a hammer that hits a bell. It is lying on the floor, collecting dust, under a closet in a corridor on the first floor in our house (we have a drive-in house with the living room on the first floor).



The bell makes enough sound to warn you when someone is at the door. However sometimes we can not hear it, For example when we are in the garden during summertime. I had the idea to connect it to my Domoticz Home automation system.

Well I could get myself a new fancy wireless doorbell from CoCo (Click on Click off, Klikaanklikuit in Dutch). This poses two problems. The Coco bell works on a power outlet, however the button works on a battery. And I dont like batteries for long term projects. I forget to replace them and they are always empty when you have no spares.

So I started to search the internet on how to attach a 12volt AC signal to a 5 volt DC circuit. And here the quest began.

The common way to transform 12 volt AC to 5 volt DC is to use a rectifying bridge and a power regulator. That is if you have need for a constant power source. But that is not what I needed. I just wanted to detect the signal when the bell button was pressed.



Above is the schematic that shows how the doorbell works. The transformer (on the left side) brings the power outlet down to a 12volt AC current. The button interrupts the power and when the button is pressed the bell wil get its power. The bell itself is mechanical. When it gets power the hammer beats against te bell and that breaks the electrical contact. So the hammer falls down to its original position and gets power again to beat again against te bell. The cycle keeps on going till you release the button.

Only when the button is pressed the bell gets its power. So I have to check the contacts across the bell to know if someone pushes the button.

I did not want the 12Volt be in direct contact with my other electronics. An optocoupler comes to mind. Yet they are made for DC current and not for AC current. Besides that I do not have any opto couplers.

Searching the net and having a conversation with a friend of mine who is excellent with electronics we came up with the following solution:



I took 2 leds and connected them counterwise. Connecting cathode to anode and the other way round. And I attached a current delimiting resistor of 3.3K Normally such a resistor has a far lower value. We are however working with higher voltages. If you decide to build this yourself, make sure you use the 1/4 watt or 1/2 watt resistors. The small 1/8 watt resistors can not handle the higher current it has to reduce.




I put the leds on a breadboard next to eachother and placed an LDR right acros them so the lights would shine full on the LDR. The LDR was at first connected to the analog input of the ESP8266 using a pull-down resistor.

The schematics were made in EasyEDA which really works well for designing schematics and even making PCB. EasyEDA has a large (no huge) library of components and it is quite easy to learn. And it is free to use. They earn their money when you order PCB's from them. There is no breadboard layout so for that I'll stick to Fritzing. You can find EasyEDA here:  https://easyeda.com/

As we are working with AC it means that 25 times a second (we use 50Hz in the Netherlands) alternating one of the leds would be put ON. This alters the LDR's resistance.

Now I had a kind of an AC opto-coupler.

First test was to attach a batterypack to the setup. I used 6 1.5V batteries in series. This gave about 9 volts. And it worked. One of the leds was ON the other OFF. When I switched the battery poles the other way round the other led went ON and the first led went OFF.


int sensorPin = A0;
int sensorValue = 0;

const int buttonPin = 13;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  sensorValue = analogRead(sensorPin);
  Serial.println(sensorValue);
  Serial.println(digitalRead(buttonPin));
  delay (100);
}

I wrote a simple program that would read the analog port off the ESP8266 and display its values on the Serial Monitor. I covered the leds and the LDR with a cloth and applied the 9volts from the batteries again. When the leds were OFF the values on the Ananlog port were high and when the leds  were ON the values dropped. It worked !!!

Then I had an idea. What would happen if I attached the LDR to a digital I/O pin ??? This is an abuse of electronics. But I tried it anyway. And that worked too. Better as expected. When the leds were OFF the digital I/O pin was LOW, and when the leds went ON the pin went HIGH.

Why would I do that ?
I could simply test for the analog values which would be good practice.
However if I could switch a digital pin this way I could trigger an interrupt and did not have to poll the IO pin all the time.

Breadboard setup

To make things clear I give you the breadboard setup.


I bend the leads of the leds and the LDR in such a way that the leds would shine direct on the LDR. I connected the VCC and GND to the 3.3V pins on the ESP8266 and the LDR signal line was attached to pin D0 (16).

At the led side the risistors were atached parallel to the bell. So there would flow currect only when the button was pushed.

Permanent setup

I wanted a permanent setup. So I put everything on a stripboard.



Above you can see how the stripboard is build. I put a header on the led side so I could use dupont wires to connect the board to the ESP8266.
For the ESP8266 (a Wemos D1 mini) I usede a second piece of stripboard and soldered some headers next to the ESP8266 similar like I did in this story:
http://lucstechblog.blogspot.com/2015/09/nodemcu-breadboard-aid.html

Then I connected the two breadboards with dupont wires.

The idea behind this is that I am using this as a base for a part of my home automation. So as more functionality will be added I might switch to an ESP32 in the future. One of the things that can be implemented direct is the geofencing technique I described in this story: http://lucstechblog.blogspot.com/2020/01/geofencing-for-domoticz-with-esp8266.html

Domoticz

The hardware works. The first thing to do now is to setup a new switch in Domoticz. The complete procedure on how to do that can be found in this story: xxxxxxxxxxxxxxxxxxxxxx
I am going to give you the step by step version here:

- click on the settings menu on the right-side tab in Domoticz
- choose hardware in the settings menu
- add a new virtual switch
- call it virtual doorbell
- as usual the type of the switch is dummy
- when finished click on Make virtual sensors
- choose switch
- give the switch the name Doorbell and as type switch
- now again use the settings menu
- choose devices
- choose active devices
- write down the IDX (index) of the virtual doorbell switch
- now move over to the switches tab
- you can see the last created switch at the bottom being the doorbell
- press the adapt button and alter the icon in a switch


There is now a new switch in the switches section of Domoticz.

The ESP8266 Program

As usual I give you first the complete program and then I will discuss some details.

// ESP8266 program to test a digital pin
// and when that pin is HIGH send a signal to 
// Domoticz. 
// Part of the Domoticz Doorbell project

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

// WiFi settings
#define wifi_ssid "XXXXXXXXXXXXXX"
#define wifi_password "YYYYYYYYYYYYY"

// HTTP Domoticz settings
const char* host = "192.168.1.66";
const int   port = 8080;

HTTPClient http;

int toggle = 0;
int sensorValue = 0;
const int buttonPin = 16;  // D0

void setup() 
  {
  Serial.begin(115200);
  setup_wifi();           
  }

void switchonoff()
  {
    // Here is the Json format that Domoticz expects
    // /json.htm?type=command&param=switchlight&idx=99&switchcmd=On
    String url = "/json.htm?type=command&param=switchlight&idx=";
    url += String(8539);
    url += "&switchcmd=On";
    sendToDomoticz(url);
  }  

void loop() 
  {
  sensorValue = digitalRead(buttonPin);
  Serial.println(digitalRead(buttonPin));
  if (sensorValue == 1)
    {
    switchonoff();
    delay (2000);
    }
  delay(10);
  }

//Connect to wifi
void setup_wifi() 
  {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.begin(wifi_ssid, wifi_password);

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

  Serial.println("");
  Serial.println("WiFi connection Established");
  Serial.print("IP Adress : ");
  Serial.print(WiFi.localIP());
  }


void sendToDomoticz(String url){
  Serial.print("Connecting to ");
  Serial.println(host);
  Serial.print("Requesting URL: ");
  Serial.println(url);
  http.begin(host,port,url);
  int httpCode = http.GET();
    if (httpCode) 
      {
      if (httpCode == 200) 
        {
        String payload = http.getString();
        Serial.println("Domoticz response "); 
        Serial.println(payload);
        }
      }
  Serial.println("closing connection");
  http.end();
}

I will discuss some of the details here.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

These lines load the necessary libraries into the program.

// WiFi settings
#define wifi_ssid "XXXXXXXXXXXXXX"
#define wifi_password "YYYYYYYYYYYYY"

Put your own router credentials in here so the ESP8266 can contact the router to send data over wifi.

// HTTP Domoticz settings
const char* host = "192.168.1.66";
const int   port = 8080;

This is the IP number and the port number of my Domoticz system. Put in your own numbers.

HTTPClient http;

The webserver instance is initiated.

int toggle = 0;
int sensorValue = 0;
const int buttonPin = 16;  // D0

Some help variables are declared and the pin to which the doorbell circuit is attached is defined.

void switchonoff()
  {
    // Here is the Json format that Domoticz expects
    // /json.htm?type=command&param=switchlight&idx=99&switchcmd=On
    String url = "/json.htm?type=command&param=switchlight&idx=";
    url += String(8539);
    url += "&switchcmd=On";
    sendToDomoticz(url);
  } 

This routine is called form within the loop when the doorbell is ringing.
A string called url is filled with the JSON code that is needed to put the switch in Domoticz ON. By putting this part of the program in its own subroutine it will be possible, when expanding the program, to call the procedure with parameters that represent different IDX numbers and commands like ON and OFF.

void loop() 
  {
  sensorValue = digitalRead(buttonPin);
  Serial.println(digitalRead(buttonPin));
  if (sensorValue == 1)
    {
    switchonoff();
    delay (2000);
    }
  delay(10);
  }

The loop() is where the tests wether the bell has ringed is performed.
The buttonPin is read into the sensorValue variable. the value is for checking printed to the Serial Monitor.
Then a test if made to determine wether the doorbeel has been pushed. If that is the case D0 will be high and the switchonoff routine is called.

You often see that the Wifi Connection is established in the setup() routine.
It is however more comprehensible if the connection is made in its own subroutine and that is done in the setup_wifi() routine.
The routine will print dots into the Serial Monitor until a connection is made with your router. Then the IP adress of the ESP8266 is printed.

void sendToDomoticz(String url){
  Serial.print("Connecting to ");
  Serial.println(host);
  Serial.print("Requesting URL: ");
  Serial.println(url);
  http.begin(host,port,url);
  int httpCode = http.GET();
    if (httpCode) 
      {
      if (httpCode == 200) 
        {
        String payload = http.getString();
        Serial.println("Domoticz response "); 
        Serial.println(payload);
        }
      }
  Serial.println("closing connection");
  http.end();
}

This is the routine that sends the command to set the switch ON to Domoticz.
First the Serial Monitor displays that a connection with Domoticz will be made and that the string URL will se send.

The http.begin command fires the connection with Domoticz with the IP number, Port number and the variable url which contains the JSON code for setting the switch on.

Then a variable httpCode is filled with the return of the http.GET() comand.
This makes sure we get an OK signal (code 200) back from Domoticz so we know everything went well.

Next the connection with Domoticz is closed.

Modifications, upgrades and expansion

This code works flawlessly. It is however better practice to alter the program in a way that an interrupt is fired when the Doorbell button is pushed. Then we do not need an infinite loop in the software that tests the IO PIN constantly.
An interrupt is a shorter and cleaner method.

A first upgrade would be to combine this code with the Geofencing code I shown in this story: http://lucstechblog.blogspot.com/2020/01/geofencing-for-domoticz-with-esp8266.html That way we would only need 1 ESP8266 for multiple purposes.

When the doorbell is rang the button in Domoticz changes its state in ON. As I have the Domoticz app on my Phone I can see the state of the bell changing. You can also send a command to IFTTT and that can send a notification to our phone. Or send a message to Telegram so you will get a notification on your phone. That way we will know when someone is at the door wherever in the world we are, be it just sitting in the garden.

What rests is designing a box in Tinkercad and printing the enclosure with my 3D printer.

That's it for now
have fun

Luc Volders