// 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":"","Vcc":"","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 #include #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; }