123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- // Postkastl_MQTT v5
- // Author: Flo Kra
- // Desc: nach dem Start wird zunächst GPIO0 als output definiert und auf high gesetzt (Selbsthalteschaltung, dieser Pin ist mit CH_PD verbunden)
- // danach wird GPIO3 abgefragt - wenn high ist der Türkontakt und nicht der Klappenkontakt aktiv (event="emptied", da der Postkasten ja gerade entleert wird,
- // ansonsten event="new_post".
- // dann wird eine WIFI Verbindung aufgebaut, eine Message mit ein paar Daten als JSON string an einen MQTT broker gesendet und nach einer Wartezeit das Modul wieder
- // abgeschaltet
- // MQTT payload: {"event":"<event>","Vcc":"<vcc>","Batt":"<batt>"}
- // event = "new_post" -> Klappe wurde geöffnet, vermutlich ist neue Post da!
- // "emptied" -> Postkasten wurde entleert (wenn die Tür und nicht die Klappe geöffnet ist)
- // Vcc = -> Vcc in mV (sollte zwischen 2400 - 3500 liegen)
- // Batt = normalerweise "OK", "LOW" wenn Vcc unter definiertem Wert ist
- #include <ESP8266WiFi.h>
- #include <PubSubClient.h>
- #define SerialDebug false
- const char* ssid = ""; // WiFi SSID
- const char* password = "!"; // WiFi PWD
- const char* server = ""; // gateway server IP
- const int port = 1883;
- const char* mqtt_user = "";
- const char* mqtt_pwd = "";
- const char* topic = "Postkasten";
- const int BattLowValue = 2600; // mV @ ADC (always some 10 mV less than external supply voltage!)
- const int powerdownAfter = 20; // sec
- // NO CONFIG BELOW!
- byte holdPin = 0; // GPIO 0 ist via Diode mit CH_PD verbunden, muss high gehalten werden bis das Programm fertig ist, dann wird auf low geschaltet und dadurch das Modul abgeschaltet
- byte inputPin = 3; // GPIO 3 ist Input, wenn high bedeutet das, dass die Postkastentür und nicht die Klappe geöffnet wurde
- bool event_is_emptying = false;
- ADC_MODE(ADC_VCC);
- int Vcc;
- byte BattLow;
- WiFiClient wifiClient;
- PubSubClient client(server, port, callback, wifiClient);
- void setup() {
- pinMode(holdPin, OUTPUT); // GPIO 0 ist output
- digitalWrite(holdPin, HIGH); // setze GPIO 0 auf high, dadurch wird CH_PD high gehalten auch wenn der Kontakt nicht mehr betätigt ist
- #if SerialDebug
- // Serial TX only!! GPIO3 = RX wird als Input gebraucht
- Serial.begin(9600, SERIAL_8N1, SERIAL_TX_ONLY, 1); // void begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin);
- #endif
- // wenn GPIO3 / RX jetzt HIGH ist, dann ist der Kontakt der Postkastentür betätigt, also wird der Postkasten gerade entleert
- pinMode(inputPin, INPUT); // GPIO 3 = RX = input
- delay(100);
- if ( digitalRead(inputPin) == HIGH ) event_is_emptying = true;
- #if SerialDebug
- delay(1000);
- Serial.print("begin...\n");
- Serial.print("inputPin/event_is_emptying=");
- Serial.print(digitalRead(inputPin));
- Serial.print("\n");
- #endif
- #if SerialDebug
- Serial.print("connecting WiFi");
- #endif
- WiFi.begin(ssid, password);
- uint8_t wifiRetryCounter = 0;
- while (WiFi.status() != WL_CONNECTED) { // loop until WiFi connected
- delay(500);
- #if SerialDebug
- Serial.print(".");
- #endif
- wifiRetryCounter++;
- if (wifiRetryCounter >= 60) {
- #if SerialDebug
- Serial.println();
- #endif
- break;
- }
- }
- if (WiFi.status() == WL_CONNECTED) {
- #if SerialDebug
- Serial.println("WiFi connected");
- Serial.println("IP: ");
- Serial.println(WiFi.localIP());
- #endif
- }
- else {
- #if SerialDebug
- Serial.println("ERROR: could not connect WiFi. Powering down now.");
- #endif
- ESP.deepSleep(0);
- }
- // Generate client name based on MAC address and last 8 bits of microsecond counter
- String clientName;
- clientName += "esp8266-";
- uint8_t mac[6];
- WiFi.macAddress(mac);
- clientName += macToStr(mac);
- clientName += "-";
- clientName += String(micros() & 0xff, 16);
- Vcc = ESP.getVcc();
- #if SerialDebug
- Serial.print("Connecting to ");
- Serial.print(server);
- Serial.print(" as ");
- Serial.println(clientName);
- Serial.print("Vcc=");
- Serial.print(Vcc);
- Serial.print("\n");
- Serial.print("Batt=");
- if ( Vcc <= BattLowValue ) Serial.print("LOW");
- else Serial.print("OK");
- Serial.print("\n");
- #endif
- //if (client.connect((char*) clientName.c_str())) {
- //if (client.connect("ESP-Post-5", "espclient", "1Weinum9")) {
- if (client.connect((char*) clientName.c_str(), mqtt_user, mqtt_pwd)) {
- #if SerialDebug
- Serial.println("Connected to MQTT broker");
- Serial.print("Topic: ");
- Serial.println(topic);
- #endif
- client.loop();
- String payload = "{\"event\":\"";
- if ( !event_is_emptying ) payload += "new_post";
- else payload += "emptied";
- payload += "\",\"Vcc\":\"";
- payload += Vcc;
- payload += "\",\"Batt\":";
- if ( Vcc <= BattLowValue ) payload += "\"LOW\"";
- else payload += "\"OK\"";
- payload += "}";
- #if SerialDebug
- Serial.print("Sending payload: ");
- Serial.println(payload);
- #endif
- client.loop();
- if (client.publish(topic, (char*) payload.c_str())) {
- client.loop();
- #if SerialDebug
- Serial.println("Publish ok");
- #endif
- }
- else {
- client.loop();
- #if SerialDebug
- Serial.println("Publish failed");
- #endif
- }
- client.loop();
- client.disconnect();
- }
- else {
- #if SerialDebug
- Serial.println("MQTT connect failed");
- //Serial.println("Will reset and try again...");
- #endif
- //abort(); // reboot ESP
- }
- #if SerialDebug
- Serial.print("sent, stopping WIFI...\n");
- #endif
- WiFi.disconnect();
- WiFi.mode(WIFI_OFF);
- WiFi.forceSleepBegin();
- #if SerialDebug
- Serial.print("WIFI deactivated\n");
- #endif
- // powerdownAfter Sekunden warten bevor PowerDown erfolgt, um doppelausloesung zu vermeiden falls waehrenddessen der Kontakt nochmal betaetigt wird (GPIO2 = HIGH) den Counter reseten
- for (int i = 0; i <= powerdownAfter; i++) {
- delay(1000);
- }
- // power down now
- #if SerialDebug
- Serial.print("power down now\n");
- #endif
- //digitalWrite(holdPin, LOW); // setze GPIO 0 auf low. dadurch wird CH_PD low und der ESP abgeschaltet (den Ast auf dem wir sitzen absägen ;-) )
- // nur deepSleep einschalten - müsste auch den GPIO 0 automatisch abschalten ..?
- ESP.deepSleep(0);
- // // ab hier nichts mehr tun, nur mehr auf bessere zeiten warten! (wenn wir hier gelandet sind ist eh etwas schief gelaufen!)
- // delay(5000);
- //#if SerialDebug
- // Serial.print("PWRDOWN failed, check circuit on CH_PD\n");
- //#endif
- // // deep sleep auslösen, da wir nun nichts mehr zu tun haben. falls das powerdown via GPIO0->CH_PD nicht funktioniert sparen wir so zumindest energie
- // // wieder hochkommen wird zumindest der ESP-01 nie, da hierfür eine Verbindung von GPIO-16 zu RES nötig wäre
- // ESP.deepSleep(0); // 300 sec
- } // END Setup
- void loop() {
- } // END loop
- void callback(char* topic, byte* payload, unsigned int length) {
- // handle message arrived
- }
- String macToStr(const uint8_t* mac)
- {
- String result;
- for (int i = 0; i < 6; ++i) {
- result += String(mac[i], 16);
- if (i < 5)
- result += ':';
- }
- return result;
- }
|