Last active
December 11, 2018 17:06
-
-
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++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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!"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.