Making my doorbell 'smart'

Hi!

I'm very new to the Arduino world and have very limited background in electronics, so apologies if i'm not using correct terminology or if I'm not clear.

So far i've ran through some of the tutorials without to much issues.
For my first 'real' project I wanted to solve an issue that's annoying me to no end.
My doorbel is a generic wireless unit, and more often than not I don't hear it ring at all (receiver has to be pretty close to the actual button, and my 'office' where I spend most of my time is pretty far).

I thought it'd be pretty easy to hook up an arduino and send some other notification when the doorbell rings.
For this I have hooked up a MKR1000 in parallel (I think) to the speaker, which should trigger a HIGH on a digital IN pin if i'm not mistaken. This actually works pretty well, and pressing the doorbell activates the speaker, and registers on the arduino (which fires of a pushbullet notification and flashes my Hue lights).

The issue i'm having is that the logic is triggered every couple hours even though the doorbell isn't activated. I've measured the current over the arduino ground - digital pin which reads ~0.59V, even when the speaker isn't activated, and ~2.5V when it is.

I'm assuming this is due the difference in ground, the speaker unit is battery powered, and the arduino is hooked up to the mains via a USB adapter?

Could anyone tell me if there's better solutions for what i'm trying to achieve? Basically all i'm trying to accomplish is to detect if the speaker circuit is activated.

And sidequestion, since i'm a noob at the electrical side, am I within the tolerances of the arduino unit? I think I understand the pins can't bear over 3.3V, but is there a limit to the amps as well when the pin is used as an input? - How much of a fire risk have I created?

I don't think it's very relevant, but here's my code:

#include <SPI.h>
#include <WiFi101.h>
#include "arduino_secrets.h"

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

int status = WL_IDLE_STATUS;

char serverName[] = "api.pushingbox.com";
char DEVID1[] = "***************";
const char hueServer[] = "****************";  // Hue hub IP
const char hueUsername[] = "*****************************";  // Hue username
const int hueHubPort = 80;

boolean hueOn1;
boolean hueOn2;

int lightNr1 = 3;
int lightNr2 = 6;

int val = 0;
volatile unsigned long elaps = 0;
String commandR = "{\"on\": true,\"hue\": 0,\"sat\":255,\"bri\":255}";
String commandW = "{\"on\": true,\"hue\": 0,\"sat\":0,\"bri\":255}";
String commandRes1;
String commandRes2;

WiFiClient client;

void setup() {
//  Serial.begin(9600);
  
  pinMode(6, INPUT);
  if (WiFi.status() == WL_NO_SHIELD) {
    while (true);
  }
  while (status != WL_CONNECTED) {
    status = WiFi.begin(ssid, pass);
    delay(10000);
  }
}

void loop() {

  val = digitalRead(6);

  if (elaps == 0 && val == HIGH) {
    elaps = micros();
  }

  if (val == HIGH && elaps >= 1000) {
    digitalWrite(LED_BUILTIN, HIGH);

    pushbullet();

    getHue(lightNr1);
    getHue(lightNr2);

    setHue(lightNr1, commandR);
    setHue(lightNr2, commandR);
    delay(500);
    setHue(lightNr1, commandW);
    setHue(lightNr2, commandW);
    delay(500);
    setHue(lightNr1, commandR);
    setHue(lightNr2, commandR);
    delay(500);
    setHue(lightNr1, commandW);
    setHue(lightNr2, commandW);
    delay(500);
    setHue(lightNr1, commandR);
    setHue(lightNr2, commandR);
    delay(500);
    setHue(lightNr1, commandW);
    setHue(lightNr2, commandW);
    delay(500);
    setHue(lightNr1, commandR);
    setHue(lightNr2, commandR);
    delay(500);
    setHue(lightNr1, commandW);
    setHue(lightNr2, commandW);
    delay(500);
    setHue(lightNr1, commandR);
    setHue(lightNr2, commandR);
    delay(500);
    setHue(lightNr1, commandW);
    setHue(lightNr2, commandW);
    delay(500);

    if (hueOn1) {
      commandRes1 = "{\"on\": true}";
    } else {
      commandRes1 = "{\"on\": false}";
    }

    if (hueOn2) {
      commandRes2 = "{\"on\": true}";
    } else {
      commandRes2 = "{\"on\": false}";
    }
//    Serial.println(commandRes1);
//    Serial.println(commandRes2);
    setHue(lightNr1, commandRes1);
    delay(500);
    setHue(lightNr2, commandRes2);
  }

  if (val == LOW) {
    elaps = 0;
  }
}

void pushbullet() {
  if (client.connect(serverName, 80)) {
    client.print("GET /pushingbox?devid=");
    client.print(DEVID1);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(serverName);
    client.println("User-Agent: Arduino");
    client.println();
    client.stop();
  }
}

void hue() {
  if (client.connect(serverName, 80)) {
    client.print("GET /pushingbox?devid=");
    client.print(DEVID1);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(serverName);
    client.println("User-Agent: Arduino");
    client.println();
    client.stop();
  }
}

boolean setHue(int lightNum, String command)
{
  if (client.connect(hueServer, hueHubPort))
  {
    client.print("PUT /api/");
    client.print(hueUsername);
    client.print("/lights/");
    client.print(lightNum);  // hueLight zero based, add 1
    client.println("/state HTTP/1.1");
    client.println("keep-alive");
    client.print("Host: ");
    client.println(hueServer);
    client.print("Content-Length: ");
    client.println(command.length());
    client.println("Content-Type: text/plain;charset=UTF-8");
    client.println();  // blank line before body
    client.println(command);  // Hue command
    client.stop();
  }
}

boolean getHue(int lightNum)
{
  if (client.connect(hueServer, hueHubPort))
  {
    client.print("GET /api/");
    client.print(hueUsername);
    client.print("/lights/");
    client.print(lightNum);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(hueServer);
    client.println("Content-type: application/json");
    client.println("keep-alive");
    client.println();
    while (client.connected())
    {
      if (client.available())
      {
        client.findUntil(const_cast<char*>("\"on\":"), const_cast<char*>("bri"));
        String onState = client.readStringUntil(',');
//        Serial.println(lightNum);
//        Serial.println(onState);
        if (lightNum == lightNr1){
          hueOn1 = (onState == "true");  // if light is on, set variable to true
        }else{
          hueOn2 = (onState == "true");  // if light is on, set variable to true
        }
        break;  // not capturing other light attributes yet
      }
    }
    client.stop();
  }
}

Some Arduinos are limited to 3.3V, most 5V. Your 2.5V level is borderline for a reliable read as high signal.

When a pin is set to INPUT it doesn't take any current to speak of.

wvmarle:
Some Arduinos are limited to 3.3V, most 5V. Your 2.5V level is borderline for a reliable read as high signal.

When a pin is set to INPUT it doesn't take any current to speak of.

Thanks for the reply! I've read the datsaheet of the MKR1000, and it explicitly mentions it is 3.3V, so I'm assuming I need to stay under that.
Can I interpret your comment regarding the current as I don't need to take the current of the speakercircuit into account if the Arduino pin is used as an input?

I've verified that 2.5V on the digital IN is reliable to register as HIGH, it's the ~.5V that's always there i'm worried about (which I also think might be the source of the false triggers?)

I408:
Thanks for the reply! I've read the datsaheet of the MKR1000, and it explicitly mentions it is 3.3V, so I'm assuming I need to stay under that.

Indeed - well, 3.8V is the real limit (Vcc + 0.5V). Actually you can even go higher if you add a large enough current limiting resistor, so you never get more than 0.5 mA running through the clamping diode.

Can I interpret your comment regarding the current as I don't need to take the current of the speakercircuit into account if the Arduino pin is used as an input?

Indeed. Voltage matters here. Current not.

I've verified that 2.5V on the digital IN is reliable to register as HIGH, it's the ~.5V that's always there i'm worried about (which I also think might be the source of the false triggers?)

Check the data sheet for the actual values for low and high. Typically a guaranteed high is >0.6 * Vcc, low <0.2 * Vcc. So your 0.5-0.6V is OK - as long as that's the actual peak value. You mention speakers which usually implies AC or at the very least waveforms. A higher peak may go completely unnoticed by your multimeter (which averages), but not by the Arduino (the pins of which can react really fast).

What you can try is adding a low pass filter. ~10k resistor between the signal line and the pin, and a 1-10µF cap between pin and GND (mind polarity if you use electrolytics). That should nicely take care of such peaks, without affecting the speaker circuit it's attached to.

Hi 1408,

Cool project, could you maybe show us a picture or wiring diagram so we can have a better understanding of what you are doing. Also what type of arduino are you using?

Like you said, the ground could very well be an issue. Try connecting the ground of the speaker to a ground pin on the arduino, this way there will be a shared ground for the whole system.

Also if there are any voltage spikes on the input (due to interference or whatever) you could try and take an average over a few measurements. So only if the input is HIGH for a few ms will it trigger the lights.

Hope that helps.

@wvmarle,

Thank you for the education! :slight_smile:

I haven't found much more in regards to a data sheet than what is listed on the Arduino store page. So as to what registers as a HIGH, it's a guess for me. Assuming >0.6V as you mentioned, the baseline is pretty close to that which seems like the probable cause for the false triggers.

wvmarle:
What you can try is adding a low pass filter. ~10k resistor between the signal line and the pin, and a 1-10µF cap between pin and GND (mind polarity if you use electrolytics). That should nicely take care of such peaks, without affecting the speaker circuit it's attached to.

I'll try this and report back. I had a feeling i'd need something like this, but no technical skills to translate that to actual components, so thanks! I've tried averaging it out in the code by requiring the pin to be HIGH for 1000ms:

if (elaps == 0 && val == HIGH) {
    elaps = micros();
  }

  if (val == HIGH && elaps >= 1000) {
    digitalWrite(LED_BUILTIN, HIGH);
....

@teunman,

Thank you for the compliment, I'm very excited to get it working reliably :slight_smile:

I'm using the MKR1000 (because it has built-in wifi).

I have hooked up the positive of the pot (i think) which regulates the speaker volume to the digital pin on the arduino, and the negative of said pot to the ground. There is still .5V across pin and ground even when the speaker is silent.

In my previous reply i've quoted the part where I implemented your suggestion (before this post was made) of sampling the pin and only triggering when it has been HIGH for 1000ms. Great minds think alike!

Here's a picture of my project

I408:
Assuming >0.6V as you mentioned,

No, I mentioned 0.6 * Vcc.

In your case Vcc = 3.3V, so a high would be >1.98V. Values vary a bit per processor, that's why I said, check the data sheet for details.

For a regular 5V Arduino I recall it's about 2.7-2.8V. So a bit less than 0.6*Vcc.

Above that value, it's a high. Below 0.2 * Vcc (so 0.6-0.7V) it's a guaranteed low.

In between... not defined, but as this are Schmitt triggers it should stay low until the voltage reaches a high enough value to change to high which is somewhere below the guaranteed limit, and when the voltage goes down, it stays high until the voltage drops low enough, which is somewhere above the guaranteed limit.

I408:
In my previous reply i've quoted the part where I implemented your suggestion (before this post was made) of sampling the pin and only triggering when it has been HIGH for 1000ms. Great minds think alike!

Well done!
That's actually a software version of a low pass filter to remove short peaks, does the job as well.

hi 1408,

No problem :slight_smile:

Let us know if filtering the signal for a bit does the trick.

If not you could maybe try using one of the analog ports to read the voltage (which would allow you to specify at what voltage the event triggers).

I found out what the issue was!

First off, thanks again for all your help!

So, I have a mobile airconditioning unit which has been running while I was working on this project. It just blows air when the set temperature is reached, and activates the actual airconditioning part when the room gets to hot. I was changing the settings on the unit to cool down the room a bit more, and turns out, whenever the airconditioning starts/stops, it triggers the logic on the Arduino!

So to verify this, I moved my doorbell receiver to the bathroom (seperate breaker), and guess what, no more false triggers!

I'm assuming the surge from the aircon turning on/off somehow travels throughout my house and messes with the arduino from the plug? Is this normal? And more importantly, is there anything I can do to stop this from happening when both devices are on the same breaker?

A/Cs use powerful compressors, switching them may cause a peak due to the induction (my monitor often flickers when my A/C switches - same problem).

Actually it can be two things.

  1. a pulse on the power lines, that travels into your door bell and onto the ring line. That's how my monitor gets affected.
  2. more likely for you is EMI: the (long) line from your bell to the speaker and the Arduino are antennas, picking up the power line pulse, momentarily spiking the voltage on your input pin and your software thinks someone pressed the bell.

These things are quite normal indeed, and a common cause of problems. Domestic AC supply is notoriously noisy. Fluorescent lights are a major source of noise as well. That's why you see all those filtering and decoupling capacitors on PCBs, including on your Arduino. They're in place to keep the voltage stable and noise out. If that's not enough, add an inductor in your Arduino's power supply.

That's also why I suggested the RC circuit on your input pin. Also to keep that voltage stable. Short peaks are absorbed by the capacitor, only relative slow changes (in the order of 0.1 seconds for 10kΩ and 10µF) make it to the input.

@wvmarle,

That's interesting!

In my particular case the doorbell is wireless, both the sender (button) and receiver (chime) are battery powered. I would have to conclude the Arduino is still somehow the part of my project that is influenced by the surge. I guess I'll just have to find a suitable contact..

Thanks again for sharing your wisdom!

That doesn't completely exclude EMI.

The pulse from switching a motor (washing machine, fridge) can be heard on battery powered radios, especially the old AM ones. Same for sparks from light switches. Good chance that a cheap doorbell doesn't have good filters, picks up the pulse, and produces a signal too weak/short for the speaker to produce something audible, but long/strong enough for your Arduino to react.

Your bell reacts to a stray signal on the pin, not a reset of the Arduino. The first is usually caused by interference/noise, the second most commonly a power supply issue. The way to make sure is disconnect the door bell from the Arduino, and see what happens when your A/C switches.

Thanks for sticking with it, I think it's an interesting issue to troubleshoot :slight_smile:

You are 100% right about FL, I have one of those on the same circuit in the bathroom that's currently feeding the Arduino, and wouldn't you know it, turning on the light triggers the Arduino in the same way the A/C does!

I'll have to break out the soldering iron to figure out if it's the arduino resetting, or the speaker firing a signal as you said, thank you for the suggestion.

Okay, a solution has been found!

For anyone that may happen upon it in the future:

As wvmarle said, I'm assuming something (maybe the speaker?) picked up the pulse generated by FL and A/C, triggering a HIGH on the Arduino.

Since there was no data sheet of the cheap doorbell available, I was guessing about grounds etc, which I decided would be a pole on the volume pot. My guess is this part of the circuit was affected by the pulse.

Issue was solved by grounding to the battery terminal instead, which works fine! No more false positives triggered by lights or A/C.

Interesting! Didn't see that coming, so the interference was at least in part in the ground line even.