Skip to content

Instantly share code, notes, and snippets.

@cyonhosting
Last active December 11, 2018 17:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cyonhosting/006fe0bedd4920e58f14df9a9beec7e6 to your computer and use it in GitHub Desktop.
Save cyonhosting/006fe0bedd4920e58f14df9a9beec7e6 to your computer and use it in GitHub Desktop.
Make a simple doorbell report its ringing to a slack channel. Timer, ringing-count, delay-warnings and more included. Language: C++
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
/*
WIFI CONFIGURATION
*/
char SSID[] = "<wlan-id>"; // The ID of the wlan network
char pwd[] = "<wlan-pw>"; // The password of the wlan network
/**
* UDP / NTP CONFIGURATION
* see https://github.com/arduino-libraries/NTPClient
*/
WiFiUDP ntpUDP;
// By default 'pool.ntp.org' is used with 60 seconds update interval and no offset
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
/*
* SLACK CONFIGURATION
*/
const String slackHookUrl = "<webhook-url>"; // Slack webhook url. See https://api.slack.com/incoming-webhooks.
const String slackUsername = "Alexander Graham Bell"; // Display name in slack. Use whatever you like.
/*
* APPLICATION LOGIC VARS
*/
bool isRinging = false; // Wether the clock is ringing right now.
bool isWaiting = false; // Wether somebody is still waiting at the door.
int ringingCount = 0; // How many times someone was ringing before the door was opened.
int alertLevel = 0; // The alert-level ranges from 0 to 3.
unsigned long waitingStartTimestamp = 0; // The timestamp when the waiting started
unsigned long elapsedWaitingTime = 0; // The dynamically calculated time we spent waiting
// Digital pin that is connected to the magnetic switch (that registers the opening of the door).
int pushButton = 16;
// Digital pin that indicates the waiting status by activating a LED.
int led = 14;
/**
* Post messages to slack.
*/
bool postMessageToSlack(String msg)
{
const char* host = "hooks.slack.com";
Serial.print("Connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClientSecure client;
const int httpsPort = 443;
if (!client.connect(host, httpsPort)) {
Serial.println("Connection failed :-(");
return false;
}
// We now create a URI for the request
Serial.print("Posting to URL: ");
Serial.println(slackHookUrl);
String postData="payload={\"link_names\": 1, \"username\": \"" + slackUsername + "\", \"text\": \"" + msg + "\"}";
// This will send the request to the server
client.print(String("POST ") + slackHookUrl + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Content-Type: application/x-www-form-urlencoded\r\n" +
"Connection: close" + "\r\n" +
"Content-Length:" + postData.length() + "\r\n" +
"\r\n" + postData);
//Serial.println("Request sent");
String line = client.readStringUntil('\n');
Serial.printf("Response code was: ");
Serial.println(line);
if (line.startsWith("HTTP/1.1 200 OK")) {
return true;
} else {
return false;
}
}
/**
* The setup routine. Runs once at startup.
*/
void setup()
{
Serial.begin(9600);
Serial.println();
// Connect to WIFI.
WiFi.disconnect();
WiFi.mode(WIFI_STA); // Make sure we don't create a wifi hotspot.
WiFi.begin(SSID, pwd);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Connected, IP address: ");
Serial.println(WiFi.localIP());
// Make the pushbutton's pin an input.
pinMode(pushButton, INPUT);
// Declare LED as output
pinMode(led, OUTPUT);
digitalWrite(led, LOW); // Disable the LED at the start.
// Update the current time.
timeClient.begin();
timeClient.update();
postMessageToSlack((String) "[" + timeClient.getFormattedTime() + "] :robot_face: Doorbell-bot initiated.");
}
/**
* Main loop.
*/
void loop()
{
// Calculate elapsed waiting time.
if(true == isWaiting){
elapsedWaitingTime = ((millis() - waitingStartTimestamp) / 1000) + 1; // Get elapsed time in seconds
}
// Read the input on analog pin 0 to get the current value of the bell.
int sensorValue = analogRead(A0);
// Read the button input pin (magnetic switch at the door).
int doorClosed = digitalRead(pushButton);
if(doorClosed != 1 && isWaiting == true){
Serial.println((String) "Door was opened after " + elapsedWaitingTime + " seconds");
postMessageToSlack((String) "[" + timeClient.getFormattedTime() + "] :fonzie: Türe wurde geöffnet nach "
+ elapsedWaitingTime + " Sekunden und " + ringingCount + " x Klingeln.");
// Reset all global variables and start over.
resetAll();
}
// Do we get a ringing? Only report if door is closed.
if(sensorValue > 400 && doorClosed == 1 ){
if(!isRinging){
Serial.println("Ring Ring Ring!");
timeClient.update();
if(++ringingCount == 1){
postMessageToSlack((String) "[" + timeClient.getFormattedTime() + "] :bell: Rrrring rrring.");
}
else if(ringingCount > 1){
postMessageToSlack((String) "[" + timeClient.getFormattedTime() + "] :bell: Ringing for the " + ringingCount + ". time!");
}
// On the first ring start the timer.
if(!isWaiting){
// Start the ringing timer.
waitingStartTimestamp = millis();
}
isRinging = isWaiting = true;
digitalWrite(led, HIGH); // Optical indication that somebody is waiting.
}
} else{
isRinging = false;
}
// Warn delays.
if(true == isWaiting){
warnDelay();
}
delay(100); // Delay in between reads for stability.
}
/**
* Resets all global vars related to the waiting cycle.
*/
void resetAll()
{
digitalWrite(led, LOW);
elapsedWaitingTime = 0;
waitingStartTimestamp = 0;
alertLevel = 0;
ringingCount = 0;
isWaiting = false;
}
/**
* Fire warning messages in the slack channel when certain waiting threshold are surpassed and door remains unopened.
*/
void warnDelay()
{
elapsedWaitingTime = (millis() - waitingStartTimestamp) / 1000; // Get elapsed time in seconds.
if(alertLevel == 0 && elapsedWaitingTime >= 30){
++alertLevel;
Serial.println((String) "Alert level " + alertLevel);
postMessageToSlack((String) "[" + timeClient.getFormattedTime() + "] :rotating_light: 30 s passed ... somebody's waiting!");
}
if(alertLevel == 1 && elapsedWaitingTime >= 60){
++alertLevel;
Serial.println((String) "Alert level " + alertLevel);
postMessageToSlack((String) "[" + timeClient.getFormattedTime() + "] :rotating_light: 1 m passed ... still waiting!");
}
if(alertLevel == 2 && elapsedWaitingTime >= 90){
++alertLevel;
Serial.println((String) "Alert level " + alertLevel);
postMessageToSlack((String) "[" + timeClient.getFormattedTime() + "] :rotating_light: 1:30 m passed ... LAST CALL!");
}
}
@cyonhosting
Copy link
Author

This code can be uploaded onto an arduino-IDE-compatible microcontroller that is attached to a doorbell (a cheap standard 433Mhz doorbell).
In this example we used the 32Bit NodeMCU or ESP8266 (https://de.wikipedia.org/wiki/ESP8266) that we connected over analog input pin A0 to the the doorbells LED wires. Whenever we get a signal, a slack message is posted and a waiting timer initiated. On certain intervals we emit further slack messages if the door is unanswered.
Upon opening the door (which is detected by a magnetic switch that triggers digital input pin 16) we stop the cycle and display an acknowledge message in the slack channel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment