francwalter

Tueroeffner mit NodeMCU (ESP8266)

Jul 7th, 2022
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 19.40 KB | None | 0 0
  1. #include <ESP8266WiFi.h>
  2. #include <WiFiClientSecure.h>
  3. #include <UniversalTelegramBot.h>
  4.  
  5. // Wifi network station credentials
  6. #define WIFI_SSID "accesspoint"
  7. #define WIFI_PASSWORD "wifi-password"
  8. #define BOT_TOKEN "1234567890:ABCDEF-123abcd3141239ajdfafwj93blabla"
  9.  
  10.  
  11. // 2022-04-10: fuer Debug Ausgaben im Serial Monitor (Tools >) debug auf true setzen
  12. bool debug = false;
  13.  
  14. const unsigned long BOT_MTBS = 1000; // mean time between scan messages
  15.  
  16. X509List cert(TELEGRAM_CERTIFICATE_ROOT);
  17. WiFiClientSecure secured_client;
  18. UniversalTelegramBot bot(BOT_TOKEN, secured_client);
  19. unsigned long bot_lasttime; // last time messages' scan has been done
  20.  
  21. // 2022-05-11: LED Ansteuerung deaktiviert, braucht man wohl nicht mehr
  22. // const int ledPin = LED_BUILTIN;
  23. // int ledStatus = 0;
  24.  
  25. // relaisDelay (open_time) kann per Kommando veraendert werden (bis Reboot) aber nicht laenger als relaisMaxDelay ms sein
  26. int relaisDelay = 3000;
  27. int relaisMaxDelay = 10000;
  28.  
  29. // falscher from_name oder chat_id ergibt eine Pause von nagDelay ms fuer das naechste Kommando
  30. int nagDelay = 10000;
  31.  
  32. // Anmerkung: 2022-04-06: von: https://www.smarthome-tricks.de/esp8266/relais-schalten/
  33. // (GPIO 5)
  34. int pinRelais1 = D1;
  35. // 2022-05-12: siehe: https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/
  36. // (GPIO 4)
  37. int pinKlingel = D2;
  38. int relaisStatus = 0;
  39.  
  40. // Anmerkung: 2022-04-09: trusted_chat_ids und temp_trusted_chat_ids
  41. // ToDo: hier ein String-Array fuer dauerhaft erlaubte und temporaer erlaubte chat_id anlegen, die man im laufenden ESP hinzufuegen kann.
  42. String trusted_chat_id1 = "1234567890";
  43. String trusted_chat_id2 = "0987654321";
  44. // mit trusted_chat_ids.length() dann ein loop o.ae. durchlaufen
  45.  
  46. // temp. chat_id default auf Anna gesetzt, zur Laufzeit ueberschreibbar durch Befehl
  47. String temp_trusted_chat_id = "1234567890";
  48. String temp_trusted_from_name = "123beda6725423548245093854f19cd9";
  49.  
  50. // Befehlsbuttons global hier
  51. String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  52.  
  53. // function to check if a string is a valid number (for relaisDelay setting by command)
  54. boolean isNumber(String str)
  55. {
  56.   for(byte i=0;i<str.length();i++)
  57.   {
  58.     if(!isDigit(str.charAt(i))) return false;
  59.   }
  60.   return true;
  61. }
  62.  
  63. void handleNewMessages(int numNewMessages)
  64. {
  65.   if (debug) Serial.print("handleNewMessages ");
  66.   if (debug) Serial.println(numNewMessages);
  67.  
  68.   for (int i = 0; i < numNewMessages; i++)
  69.   {
  70.     String chat_id = bot.messages[i].chat_id;
  71.     String text = bot.messages[i].text;
  72.     String from_name = bot.messages[i].from_name;
  73.     if (from_name == "") from_name = "Guest";    
  74.  
  75.     // die Eigenschaften der Struktur telegramMessage des Objekts UniversalTelegramBot ausgeben
  76.     // von: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot/blob/master/src/UniversalTelegramBot.h
  77.     // debug auf true zum Auslesen
  78.  
  79.     if (debug)
  80.     {
  81.       Serial.print("text: ");
  82.       Serial.println(text);
  83.      
  84.       Serial.print("chat_id: ");
  85.       Serial.println(chat_id);  
  86.  
  87.       String chat_title = bot.messages[i].chat_title;
  88.       Serial.print("chat_title: ");
  89.       Serial.println(chat_title);
  90.      
  91.       String from_id = bot.messages[i].from_id;
  92.       Serial.print("from_id: ");
  93.       Serial.println(from_id);
  94.  
  95.       Serial.print("from_name: ");
  96.       Serial.println(from_name);
  97.  
  98.       String date = bot.messages[i].date;
  99.       Serial.print("date: ");
  100.       Serial.println(date);
  101.  
  102.       String type = bot.messages[i].type;
  103.       Serial.print("type: ");
  104.       Serial.println(type);
  105.  
  106.       String file_caption = bot.messages[i].file_caption;
  107.       Serial.print("file_caption: ");
  108.       Serial.println(file_caption);
  109.  
  110.       String file_path = bot.messages[i].file_path;
  111.       Serial.print("file_path: ");
  112.       Serial.println(file_path);
  113.  
  114.       String file_name = bot.messages[i].file_name;
  115.       Serial.print("file_name: ");
  116.       Serial.println(file_name);
  117.  
  118.       //    Bool hasDocument = bot.messages[i].hasDocument;
  119.       //    Serial.print("hasDocument: ");
  120.       //    Serial.println(String(hasDocument));
  121.  
  122.       int file_size = bot.messages[i].file_size;
  123.       Serial.print("file_size: ");
  124.       Serial.println(String(file_size));
  125.  
  126.       Serial.print("trusted_chat_id1: ");
  127.       Serial.println(trusted_chat_id1);
  128.      
  129.       Serial.print("trusted_chat_id2: ");
  130.       Serial.println(trusted_chat_id2);    
  131.      
  132.       Serial.print("temp_trusted_chat_id: ");
  133.       Serial.println(temp_trusted_chat_id);
  134.      
  135.       Serial.print("temp_trusted_from_name: ");
  136.       Serial.println(temp_trusted_from_name);
  137.     }
  138.  
  139.       /*
  140.      
  141.       die paar fehlen noch:
  142.      
  143.       struct telegramMessage {
  144.       ...
  145.         float longitude;
  146.         float latitude;
  147.         int update_id;
  148.         int message_id;  
  149.  
  150.         int reply_to_message_id;
  151.         String reply_to_text;
  152.         String query_id;
  153.       };
  154.       */
  155.  
  156.   // Anna (1234567890 bzw trusted_chat_id1) oder Berta (0987654321 bzw trusted_chat_id2) oder temp. chat_id (initial Anna) oder tem_trusted_from_name (initial md5(Anna))
  157.     if ((chat_id == trusted_chat_id1) || (chat_id == trusted_chat_id2) || (chat_id == temp_trusted_chat_id) || ((from_name == temp_trusted_from_name) && (from_name != "")))
  158.     {
  159.       if (debug) Serial.print("chat_id OK - Befehlsabfrage...\n");
  160.          
  161.       if ((text == "/info") || (text == "/help"))
  162.       {
  163.         String help = "Hallo " + from_name + ".\n\n";
  164.         help += "/info oder /help: Diesen Text zeigen\n";
  165.         help += "/debug : Die seriellen Ausgaben in der IDE umschalten\n(Standard: aus. Code: sets debug = !debug)\n";
  166.         help += "/open_time:<ms> : Setzt (bis zum nächsten Reboot) die Öffnungszeit in Millisekunden (max. 10000)\n";
  167.         help += "/chat_id:<Chat-ID> : Berechtigt (bis zum nächsten Reboot) zusätzlich diese Chat-ID für Kommandos\n";
  168.         help += "/from_name:<Telegram-Name> : Berechtigt (bis zum nächsten Reboot) zusätzlich diesen Telegram-Namen für Kommandos (leer=nicht erlaubt)\n";
  169.         help += "/open : Tür öffnen für " + String(relaisDelay) + " Millisekunden\n";
  170.         help += "/open1 : Tür eine Sekunden lang öffnen\n";
  171.         help += "/open_in_10 : Tür nach 10 Sekunden öffnen für " + String(relaisDelay) + " Millisekunden\n";
  172.         help += "/open:<ms> : Tür für <ms> Millisekunden öffnen (max 10000)\n";
  173.         // welcome += "chat_id: " + chat_id;
  174.         if (debug) Serial.print("help: \n");
  175.         if (debug) Serial.println(help);
  176.         bot.sendMessage(chat_id, help, "");
  177.       }
  178.    
  179.       if (text == "/open")
  180.       {
  181.         String command = "Tür öffnen für " + String(relaisDelay) + " ms...";      
  182.         bot.sendMessage(chat_id, command, "");      
  183.         digitalWrite(pinRelais1, LOW); // turn the Relais on
  184.         delay(relaisDelay);
  185.         digitalWrite(pinRelais1, HIGH); // turn the Relais off again
  186.         // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
  187.         // bot.sendMessage(chat_id, command, "");      
  188.         // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  189.         bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);
  190.       }
  191.       if (text == "/open1")
  192.       {
  193.         String command = "Tür eine Sekunde öffnen ...";      
  194.         bot.sendMessage(chat_id, command, "");      
  195.         digitalWrite(pinRelais1, LOW); // turn the Relais on
  196.         delay(1000);
  197.         digitalWrite(pinRelais1, HIGH); // turn the Relais off again
  198.         // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
  199.         // bot.sendMessage(chat_id, command, "");      
  200.         // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  201.         bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);
  202.       }
  203.       // ToDo: 2022-04-14: noch fertig stellen und testen:
  204.       if (text.substring(0, 6) == "/open:")
  205.       {
  206.         int length = text.length();
  207.        
  208.  
  209.         String str_open_length = text.substring(6, length);
  210.         if (isNumber(str_open_length))
  211.         {
  212.           int open_length = str_open_length.toInt();
  213.           // nicht kleiner als 100 ms und nicht groesser als 10000 ms
  214.           if (open_length < 100 || open_length > 10000) open_length = relaisDelay;
  215.           String command = "Tür " + String(open_length) + " Millisekunden öffnen ...";
  216.           bot.sendMessage(chat_id, command, "");
  217.           digitalWrite(pinRelais1, LOW); // turn the Relais on
  218.           delay(open_length);
  219.           digitalWrite(pinRelais1, HIGH); // turn the Relais off again
  220.           // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
  221.           // bot.sendMessage(chat_id, command, "");      
  222.           // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  223.           bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);
  224.  
  225.         }
  226.         else
  227.         {
  228.           // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  229.           bot.sendMessageWithReplyKeyboard(chat_id, "/open:<ms> - <ms> muss eine Zahl sein!", "", keyboardJson, true);
  230.         }
  231.  
  232.        
  233.       }
  234.       if (text == "/open_in_10")
  235.       {
  236.         String command = "Tür in 10 Sekunden für " + String(relaisDelay) + " Millisekunden öffnen...";    
  237.         bot.sendMessage(chat_id, command, "");  
  238.         // 10 Sek. warten
  239.         delay(10000);    
  240.         digitalWrite(pinRelais1, LOW); // turn the Relais on
  241.         delay(relaisDelay);
  242.         digitalWrite(pinRelais1, HIGH); // turn the Relais off again
  243.         // command = "Relais was ON for " + String(relaisDelay) + " ms\n\nTo open press: \n/open";      
  244.         // bot.sendMessage(chat_id, command, "");      
  245.         // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  246.         bot.sendMessageWithReplyKeyboard(chat_id, "Für alle Befehle auf /help tippen...", "", keyboardJson, true);
  247.       }
  248.  
  249.       // temporaere chat_id zulassen
  250.                
  251.       if (text.substring(0, 9) == "/chat_id:")
  252.       {
  253.         if (debug) Serial.print("text.substring(0,9): ");
  254.         if (debug) Serial.println(text.substring(0, 9));
  255.         int length = text.length();
  256.         temp_trusted_chat_id = text.substring(9, length);
  257.         if (debug) Serial.print("length: ");
  258.         if (debug) Serial.println(String(length));
  259.         if (debug) Serial.print("temp_trusted_chat_id: ");
  260.         if (debug) Serial.println(temp_trusted_chat_id);
  261.         String command = "Allow commands from chat_id: " + temp_trusted_chat_id;      
  262.         bot.sendMessage(chat_id, command, "");      
  263.       }
  264.       if (text.substring(0, 11) == "/from_name:")
  265.       {
  266.         int length = text.length();
  267.         // wenn leer, also length = 11 dann wird der temp. from_name (temp_trusted_from_name) geleert (initial der md5 von Anna)
  268.         String command = "";
  269.         if (length == 11)
  270.         {
  271.           temp_trusted_from_name = "";
  272.           String command = "from_name geleert, from_name nicht mehr aktiv";
  273.         }
  274.         else
  275.         {
  276.           temp_trusted_from_name = text.substring(11, length);
  277.           String command = "Befehle (bis Reboot) erlauben von Telegram-Name: " + temp_trusted_from_name;          
  278.         }        
  279.         if (debug) Serial.print("length: ");
  280.         if (debug) Serial.println(String(length));
  281.         if (debug) Serial.print("temp_trusted_from_name: ");
  282.         if (debug) Serial.println(temp_trusted_from_name);    
  283.         bot.sendMessage(chat_id, command, "");      
  284.       }    
  285.       if (text.substring(0, 11) == "/open_time:")
  286.       {
  287.         String command = "";
  288.         int length = text.length();
  289.         String temp_open_time = text.substring(11, length);
  290.         if (debug) Serial.print("length: ");
  291.         if (debug) Serial.println(String(length));
  292.         if (debug) Serial.print("temp_open_time: ");
  293.         if (debug) Serial.println(temp_open_time);
  294.         if (isNumber(temp_open_time))
  295.         {
  296.           int tempRelaisDelay = temp_open_time.toInt();
  297.           if (tempRelaisDelay > relaisMaxDelay) relaisDelay = relaisMaxDelay; // max delay
  298.           else if (tempRelaisDelay < 100) relaisDelay = relaisDelay; // unchanged if less 100 ms
  299.           else relaisDelay = tempRelaisDelay;
  300.           command = "open_time now (till next reboot): " + String(relaisDelay);
  301.           if (debug) Serial.print(command);
  302.         }
  303.         else
  304.         {
  305.           command = "open_time must be a number!";
  306.           if (debug) Serial.print("temp_open_time is not a number! command: " + command);
  307.         }
  308.         bot.sendMessage(chat_id, command, "");
  309.       }
  310.       if (text == "/debug")
  311.       {
  312.         debug = !debug;
  313.         if (debug)
  314.         {
  315.           bot.sendMessage(chat_id, "Debug Nachrichten zum Seriellen Monitor aktiviert (debug = true)", "");
  316.           Serial.print("Debug enabled");
  317.         }
  318.         else
  319.         {
  320.           bot.sendMessage(chat_id, "Debug Nachrichten zum Seriellen Monitor deaktiviert (debug = false)", "");
  321.         }
  322.       }
  323.       // Sendet Debug Nachrichten (natuerlich nur an Anna)
  324.       if (debug)
  325.       {
  326.         String debugMessage = "debug:\n";
  327.         debugMessage += "from_name: " + from_name;
  328.         String from_id = bot.messages[i].from_id;
  329.         debugMessage += "\nfrom_id: " + from_id;
  330.         debugMessage += "\nchat_id: " + chat_id;        
  331.         debugMessage += "\ntemp_trusted_from_name: " + temp_trusted_from_name;
  332.         debugMessage += "\ntemp_trusted_chat_id: " + temp_trusted_chat_id;
  333.         debugMessage += "\ntrusted_chat_id1: " + trusted_chat_id1;
  334.         debugMessage += "\ntrusted_chat_id2: " + trusted_chat_id2;
  335.         debugMessage += "\ntext: " + text;
  336.         bot.sendMessage(trusted_chat_id1, debugMessage, "");
  337.       }
  338.     }
  339.     else
  340.     {
  341.       // wrong chat_id or from_name makes delay
  342.       if (debug) Serial.print("from_name: ");
  343.       if (debug) Serial.println(from_name);
  344.       if (debug) Serial.print("chat_id: ");
  345.       if (debug) Serial.println(chat_id);        
  346.       if (debug) Serial.print("wrong chat_id / from_name - delay...");
  347.       if (debug)
  348.       {
  349.         String debugMessage = "debug\nwrong chat_id / from_name - delay\n";
  350.         debugMessage += "from_name: " + from_name;
  351.         String from_id = bot.messages[i].from_id;
  352.         debugMessage += "\nfrom_id: " + from_id;
  353.         debugMessage += "\nchat_id: " + chat_id;        
  354.         debugMessage += "\ntemp_trusted_from_name: " + temp_trusted_from_name;
  355.         debugMessage += "\ntemp_trusted_chat_id: " + temp_trusted_chat_id;
  356.         debugMessage += "\ntrusted_chat_id1: " + trusted_chat_id1;
  357.         debugMessage += "\ntrusted_chat_id2: " + trusted_chat_id2;
  358.         debugMessage += "\text: " + text;
  359.         bot.sendMessage(trusted_chat_id1, debugMessage, "");
  360.       }      
  361.       delay(nagDelay);
  362.     }
  363.   }
  364. }
  365. // 2022-05-12: noch ganz primitiv implementiert, wenn HIGH auf dem D2 Pin (GPIO4)
  366. // ToDo: noch genauer differenzieren an wen geschickt wird, evtl. mit Parameter von klingel()
  367. // evtl. noch fuer Klingel Code die Tuer oeffnen, dann aber die Klingel unterbrechen, also per Relais als weiteren Ausgang
  368. void klingel()
  369. {
  370.   // Nachricht an Anna (hartcodiert, noch)
  371.   bot.sendMessage("1234567890", "Es hat geklingelt!", "");
  372. }
  373. void bot_setup()
  374. {
  375. // 2022-05-12: von SetMyCommands inspiriert, siehe:
  376. // https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot/blob/master/examples/ESP8266/SetMyCommands/SetMyCommands.ino
  377. // die Befehle werden beim Bot selbst hinterlegt, daher kann man sie auch per anderem ESP8266 hochladen und sie wirken auch
  378. // fuer das NodeMCU Tueroeffner, das man gar nicht damit aktualisieren muss.
  379. // Links in der Eingabezeile sieht man dann ein Menue zum Hochklappen mit den Befehlen
  380.   const String commands = F("["
  381.                             "{\"command\":\"/help\",  \"description\":\"Alle Befehle mit Erklärung anzeigen\"},"
  382.                             "{\"command\":\"/debug\",  \"description\":\"Serielle Ausgabe an/aus und Debug an Anna\"},"
  383.                             "{\"command\":\"/open_in_10\",  \"description\":\"Tür in 10s öffnen (3s)\"},"
  384.                             "{\"command\":\"/open1\", \"description\":\"Tür öffnen (1s)\"},"
  385.                             "{\"command\":\"/open\",\"description\":\"Tür öffnen (3s)\"}" // no comma on last command
  386.                             "]");
  387.   bot.setMyCommands(commands);  
  388. }
  389.  
  390. void setup()
  391. {
  392.   // muss auch wenn debug aus ist aktiviert werden, sonst kann man nicht mit /debug umschalten
  393.   Serial.begin(115200);
  394.   Serial.println();
  395.  
  396.   // LED auskommentiert, nicht mehr benoetigt
  397.   // pinMode(ledPin, OUTPUT); // initialize digital ledPin as an output.
  398.   // delay(10);
  399.   // digitalWrite(ledPin, HIGH); // initialize pin as off (active LOW)
  400.   // Anmerkung: 2022-04-06: von: https://www.smarthome-tricks.de/esp8266/relais-schalten/
  401.   pinMode(pinRelais1 , OUTPUT);
  402.   digitalWrite(pinRelais1, HIGH); // initialize pin as off (active LOW)
  403.  
  404.   // 2022-05-12: schon mal den Rohbau fuer die Klingelabfrage:
  405.   pinMode(pinKlingel, INPUT);
  406.  
  407.   // attempt to connect to Wifi network:
  408.   configTime(0, 0, "pool.ntp.org");      // get UTC time via NTP
  409.   secured_client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org
  410.   if (debug) Serial.print("Connecting to Wifi SSID ");
  411.   if (debug) Serial.print(WIFI_SSID);
  412.   WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  413.   while (WiFi.status() != WL_CONNECTED)
  414.   {
  415.     if (debug) Serial.print(".");
  416.     delay(500);
  417.   }
  418.   if (debug) Serial.print("\nWiFi connected. IP address: ");
  419.   if (debug) Serial.println(WiFi.localIP());
  420.  
  421.   // Check NTP/Time, usually it is instantaneous and you can delete the code below.
  422.   if (debug) Serial.print("Retrieving time: ");
  423.   time_t now = time(nullptr);
  424.   while (now < 24 * 3600)
  425.   {
  426.     if (debug) Serial.print(".");
  427.     delay(100);
  428.     now = time(nullptr);
  429.   }
  430.   if (debug) Serial.println(now);
  431.  
  432.   // String keyboardJson = "[[\"/help\", \"/open\"],[\"/open_in_10\", \"/open1\"]]";
  433.   bot.sendMessageWithReplyKeyboard(trusted_chat_id1, "NodeMCU: tueroeffner.ino Start...", "", keyboardJson, true);
  434.    
  435. //  String startup = "NodeMCU: tueroeffner.ino - Startup\n\nFor info press:\n/info\n\nTo open press:\n/open";
  436. //  bot.sendMessage("1234567890", startup, "");
  437.   bot_setup();
  438. }
  439.  
  440. void loop()
  441. {
  442.   // millis ist die Zeit in ms seit dem letzten Reboot. bot_lasttime wird unten auf millis gesetzt und sobald millis() eine Sekunde (BOT_MTBS) weiter ist, wird das if betreten
  443.   if (millis() - bot_lasttime > BOT_MTBS)
  444.   {
  445.     int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
  446.  
  447.     while (numNewMessages)
  448.     {
  449.       if (debug) Serial.println("got response");
  450.       handleNewMessages(numNewMessages);
  451.       numNewMessages = bot.getUpdates(bot.last_message_received + 1);
  452.     }
  453.  
  454.     bot_lasttime = millis();
  455.   }
  456.   else
  457.   {
  458.     // 2022-05-12: den Eingang pruefen, wenn auf Masse, dann Funktion klingel() aufrufen
  459.     // ToDo: genauer die Bedingung pruefen und auf dem Board ueber einen Widerstand gg Plus oder Masse eindeutig setzen
  460.     /*
  461.    das funktioniert noch nicht so, muss noch ein Widerstand rein, dass der Eingang auch def. ist, daher erst mal raus
  462.     if (digitalRead(pinKlingel) == LOW)
  463.     {
  464.       klingel();
  465.     }
  466.     */
  467.   }
  468.  
  469. }
Add Comment
Please, Sign In to add comment