diff --git a/README.md b/README.md index 7e6c0fc..51d10ac 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,3 @@ Developed with the Arduino IDE, the script relies on the following third-party l * https://arduinojson.org/ v6 6.13.0 * https://github.com/tzapu/WiFiManager 0.15.0-beta -* https://github.com/krzychb/EspSaveCrash 1.0.2 diff --git a/main.ino b/presence-button.ino similarity index 62% rename from main.ino rename to presence-button.ino index 77d9a4a..58c5b44 100644 --- a/main.ino +++ b/presence-button.ino @@ -1,4 +1,3 @@ - #include //this needs to be first, or it all crashes and burns... #include //https://github.com/esp8266/Arduino //needed for library @@ -9,19 +8,19 @@ #include //https://github.com/bblanchon/ArduinoJson #include // https://tttapa.github.io/ESP8266/Chap08%20-%20mDNS.html -#include +#include //for LED status #include -Ticker ticker; +Ticker ledTicker; -const byte RELAY_PIN = 12; -const byte LED_PIN = 13; // 13 for Sonoff S20, 2 for NodeMCU/ESP12 internal LED +const byte RELAY_PIN = D2; // SHOULD BE 12 for Sonoff S20 +const byte LED_PIN = LED_BUILTIN; // 13 for Sonoff S20, 2 for NodeMCU/ESP12 internal LED const byte BUTTON_PIN = 0; bool fuzIsOpen = false; -void tick() { +void blinkLED() { //toggle state bool state = digitalRead(LED_PIN); // get the current state of LED_PIN pin digitalWrite(LED_PIN, !state); // set pin to the opposite state @@ -34,15 +33,14 @@ void configModeCallback (WiFiManager *myWiFiManager) { //if you used auto generated SSID, print it Serial.println(myWiFiManager->getConfigPortalSSID()); //entered config mode, make led toggle faster - ticker.attach(0.2, tick); + ledTicker.attach(0.5, blinkLED); } //define your default values here, if there are different values in config.json, they are overwritten. String matrixUsername; String matrixPassword; -String matrixRoom = "!ppCFWxNWJeGbyoNZVw:matrix.fuz.re"; // #entropy:matrix.fuz.re -String matrixMessage = "Test"; +String notifiedEndpoint = "https://presence-button-staging.glitch.me/status?fuzisopen="; // #entropy:matrix.fuz.re //flag for saving data bool shouldSaveConfig = false; @@ -56,89 +54,8 @@ void saveConfigCallback () { WiFiManager wifiManager; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include // for https://github.com/matt-williams/matrix-esp8266/blob/master/matrix-esp8266.ino -HTTPClient http; -String accessToken; -String lastMessageToken; - -String createLoginBody(String user, String password) { - String buffer; - StaticJsonDocument<1000> jsonBuffer; - //JsonObject& root = jsonBuffer.createObject(); - jsonBuffer["type"] = "m.login.password"; - jsonBuffer["user"] = user; - jsonBuffer["password"] = password; - jsonBuffer["identifier"]["type"] = "m.id.user"; - jsonBuffer["identifier"]["user"] = user; - serializeJson(jsonBuffer, buffer); - return buffer; -} - -String createMessageBody(String message) { - String buffer; - StaticJsonDocument<1000> jsonBuffer; - jsonBuffer["msgtype"] = "m.text"; - jsonBuffer["body"] = message; - serializeJson(jsonBuffer, buffer); - return buffer; -} - -bool login(String user, String password) { - bool success = false; - - String buffer; - buffer = createLoginBody(user.substring(0, user.indexOf(":")), password); - - String url = "http://corsanywhere.glitch.me/https://" + user.substring(user.indexOf(":") + 1) + "/_matrix/client/r0/login"; - // Serial.printf("POST %s\n", url.c_str()); - - http.begin(url); - http.addHeader("Content-Type", "application/json"); - int rc = http.POST(buffer); - Serial.printf("buffer %s\n", buffer.c_str()); - if (rc > 0) { - Serial.printf("Login return code %d\n", rc); - if (rc == HTTP_CODE_OK) { - String body = http.getString(); - StaticJsonDocument<1000> jsonBuffer; - deserializeJson(jsonBuffer, body); - String myAccessToken = jsonBuffer["access_token"]; - accessToken = String(myAccessToken.c_str()); - Serial.println(accessToken); - success = true; - } - } else { - Serial.printf("Error: %s\n", http.errorToString(rc).c_str()); - } - - return success; -} - -bool sendMessage(String roomId, String message) { - bool success = false; - - String buffer; - buffer = createMessageBody(message); - - String url = "http://corsanywhere.glitch.me/https://" + roomId.substring(roomId.indexOf(":") + 1) + "/_matrix/client/r0/rooms/" + roomId + "/send/m.room.message/" + String(millis()) + "?access_token=" + accessToken + "&limit=1"; - Serial.printf("PUT %s\n", url.c_str()); - - http.begin(url); - int rc = http.sendRequest("PUT", buffer); - if (rc > 0) { - // Serial.printf("%d\n", rc); - if (rc == HTTP_CODE_OK) { - success = true; - } - } else { - Serial.printf("Error: %s\n", http.errorToString(rc).c_str()); - } - return success; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ESP8266WebServer httpServer(80); // webserver on port 80 https://github.com/esp8266/Arduino/blob/14262af0d19a9a3b992d5aa310a684d47b6fb876/libraries/ESP8266WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino void handleRoot() { String html = @@ -171,7 +88,7 @@ void handleAdmin() { httpServer.sendHeader("Location", httpServer.uri(), true); httpServer.send(302, "text/plain", ""); delay(500); - ESP.reset(); + ESP.restart(); return; } } @@ -186,21 +103,17 @@ void handleAdmin() { matrixPassword = httpServer.arg(i); continue; } - if (httpServer.argName(i) == "matrixRoom") { - matrixRoom = httpServer.arg(i); - continue; - } - if (httpServer.argName(i) == "matrixMessage") { - matrixMessage = httpServer.arg(i); + if (httpServer.argName(i) == "notifiedEndpoint") { + notifiedEndpoint = httpServer.arg(i); continue; } } Serial.println(F("saving config")); - StaticJsonDocument<800> jsonBuffer; + const size_t capacity = JSON_OBJECT_SIZE(3) + 440; // https://arduinojson.org/v6/assistant/ + DynamicJsonDocument jsonBuffer(capacity); jsonBuffer["matrixUsername"] = matrixUsername; jsonBuffer["matrixPassword"] = matrixPassword; - jsonBuffer["matrixRoom"] = matrixRoom; - jsonBuffer["matrixMessage"] = matrixMessage; + jsonBuffer["notifiedEndpoint"] = notifiedEndpoint; File configFile = SPIFFS.open("/config.json", "w"); if (!configFile) { @@ -226,8 +139,7 @@ void handleAdmin() { "
" + "
" + "
" + - "
" + - "
" + + "
" + "
" ""; httpServer.send(200, "text/html", html); @@ -236,39 +148,21 @@ void handleNotFound() { httpServer.send(404, "text/plain", httpServer.uri() + " not found"); } -void morseSOSLED() { // ... ___ ... - for (int i = 0; i < 3; i++) { - digitalWrite(LED_PIN, LOW); // lit up - delay(100); - digitalWrite(LED_PIN, HIGH); // lit down - delay(100); - } - delay(50); - for (int i = 0; i < 3; i++) { - digitalWrite(LED_PIN, LOW); // lit up - delay(300); - digitalWrite(LED_PIN, HIGH); // lit down - delay(100); - } - delay(50); - for (int i = 0; i < 3; i++) { - digitalWrite(LED_PIN, LOW); // lit up - delay(100); - digitalWrite(LED_PIN, HIGH); // lit down - delay(100); - } - delay(500); -} - BearSSL::WiFiClientSecure secureClient; -HTTPClient http2; -// http2.setReuse(true); -void notifyFuzIsOpen() { - http2.begin(secureClient, "https://presence-button.glitch.me/status?fuzisopen=" + String(fuzIsOpen)); - http2.setAuthorization(matrixUsername.c_str(), matrixPassword.c_str()); - int httpCode = http2.GET(); - Serial.println("GET status return code: " + String(httpCode)); - http2.end(); +HTTPClient http; +void notifyFuzIsOpen(bool fuzIsOpen) { + http.begin(secureClient, notifiedEndpoint + String(fuzIsOpen)); + http.setAuthorization(matrixUsername.c_str(), matrixPassword.c_str()); + int httpCode = http.GET(); + Serial.println("notifyFuzIsOpen body: " + http.getString()); + Serial.println("notifyFuzIsOpen return code: " + String(httpCode)); + http.end(); + if (httpCode != 200) { // something is wrong, bad network or misconfigured credentials + ledTicker.attach(0.1, blinkLED); + } else { + ledTicker.detach(); + digitalWrite(LED_PIN, LOW); // ensure the LED is lit + } } bool loggedInMatrix = false; @@ -283,8 +177,8 @@ void setup() { //set button pin as input pinMode(BUTTON_PIN, INPUT); - // start ticker with 0.5 because we start in AP mode and try to connect - ticker.attach(0.6, tick); + // start ledTicker with 1 because we start in AP mode and try to connect + ledTicker.attach(1.1, blinkLED); Serial.println(F("mounting FS...")); @@ -301,7 +195,8 @@ void setup() { std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); - StaticJsonDocument<800> jsonBuffer; + const size_t capacity = JSON_OBJECT_SIZE(3) + 440; // https://arduinojson.org/v6/assistant/ + DynamicJsonDocument jsonBuffer(capacity); auto error = deserializeJson(jsonBuffer, buf.get()); if (error) { Serial.print(F("deserializeJson() failed with code ")); @@ -317,10 +212,8 @@ void setup() { matrixUsername = m0; String m1 = jsonBuffer["matrixPassword"]; matrixPassword = m1; - String m2 = jsonBuffer["matrixRoom"]; - matrixRoom = m2; - String m3 = jsonBuffer["matrixMessage"]; - matrixMessage = m3; + String m2 = jsonBuffer["notifiedEndpoint"]; + notifiedEndpoint = m2; } configFile.close(); } @@ -337,8 +230,7 @@ void setup() { // id/name placeholder/prompt default length WiFiManagerParameter customMatrixUsername("Matrix username", "Matrix username", matrixUsername.c_str(), 50); WiFiManagerParameter customMatrixPassword("Matrix password", "Matrix password", matrixPassword.c_str(), 50); - WiFiManagerParameter customMatrixRoom("Matrix room", "Matrix room", matrixRoom.c_str(), 200); - WiFiManagerParameter customMatrixMessage("Matrix message", "Matrix message", matrixMessage.c_str(), 500); + WiFiManagerParameter customNotifiedEndpoint("Notified endpoint", "Notified endpoint", notifiedEndpoint.c_str(), 200); //WiFiManager //Local intialization. Once its business is done, there is no need to keep it around @@ -358,8 +250,7 @@ void setup() { //add all your parameters here wifiManager.addParameter(&customMatrixUsername); wifiManager.addParameter(&customMatrixPassword); - wifiManager.addParameter(&customMatrixRoom); - wifiManager.addParameter(&customMatrixMessage); + wifiManager.addParameter(&customNotifiedEndpoint); //reset settings - for testing //wifiManager.resetSettings(); @@ -377,30 +268,29 @@ void setup() { Serial.println(F("failed to connect and hit timeout")); delay(3000); //reset and try again, or maybe put it to deep sleep - ESP.reset(); + ESP.restart(); delay(5000); } //if you get here you have connected to the WiFi Serial.println(F("connected...yeey :)")); - ticker.detach(); + ledTicker.detach(); //keep LED on digitalWrite(LED_PIN, LOW); //read updated parameters matrixUsername = customMatrixUsername.getValue(); matrixPassword = customMatrixPassword.getValue(); - matrixRoom = customMatrixRoom.getValue(); - matrixMessage = customMatrixMessage.getValue(); + notifiedEndpoint = customNotifiedEndpoint.getValue(); //save the custom parameters to FS if (shouldSaveConfig) { Serial.println(F("saving config")); - StaticJsonDocument<800> jsonBuffer; + const size_t capacity = JSON_OBJECT_SIZE(3) + 440; // https://arduinojson.org/v6/assistant/ + DynamicJsonDocument jsonBuffer(capacity); jsonBuffer["matrixUsername"] = matrixUsername; jsonBuffer["matrixPassword"] = matrixPassword; - jsonBuffer["matrixRoom"] = matrixRoom; - jsonBuffer["matrixMessage"] = matrixMessage; + jsonBuffer["notifiedEndpoint"] = notifiedEndpoint; File configFile = SPIFFS.open("/config.json", "w"); if (!configFile) { @@ -418,16 +308,6 @@ void setup() { Serial.println(WiFi.localIP()); Serial.println(WiFi.SSID()); - http.setReuse(true); - loggedInMatrix = login(matrixUsername, matrixPassword); - if (loggedInMatrix) { - Serial.println("Sucessfully athenticated"); - //keep LED on - digitalWrite(LED_PIN, LOW); - //light up rotating light - digitalWrite(RELAY_PIN, HIGH); - } - httpServer.on("/", handleRoot); httpServer.on("/admin", handleAdmin); httpServer.onNotFound(handleNotFound); @@ -446,7 +326,7 @@ void setup() { bool buttonState = HIGH; bool previousButtonState = HIGH; long previousMillis = 0; -const long getMatrixMessagesInterval = 5000; +const long notifyInterval = 5000; unsigned long pressedTime = millis(); void loop() { MDNS.update(); @@ -459,32 +339,30 @@ void loop() { pressedTime = millis(); } if (buttonState == LOW && previousButtonState == LOW && (millis() - pressedTime) > 5000) { + Serial.println("Button STILL pressed (longpress handling)"); wifiManager.resetSettings(); SPIFFS.format(); delay(500); - ESP.reset(); + ESP.restart(); } - unsigned long currentMillis = millis(); - if (currentMillis - previousMillis > getMatrixMessagesInterval) { + if (currentMillis - previousMillis > notifyInterval) { previousMillis = currentMillis; - notifyFuzIsOpen(); + notifyFuzIsOpen(fuzIsOpen); } - if (!loggedInMatrix) { // send SOS in morse - morseSOSLED(); - loggedInMatrix = login(matrixUsername, matrixPassword); - return; + if (!fuzIsOpen) { + digitalWrite(RELAY_PIN, HIGH); } bool relayState = digitalRead(RELAY_PIN); - if (buttonState == LOW && previousButtonState == HIGH && relayState == HIGH && sendMessage(matrixRoom, matrixMessage)) { // button just pressed while light is up + if (buttonState == LOW && previousButtonState == HIGH /* && relayState == HIGH*/) { // button just pressed while light is up delay(100); Serial.println("Button pressed"); digitalWrite(RELAY_PIN, LOW); fuzIsOpen = true; + notifyFuzIsOpen(fuzIsOpen); } - digitalWrite(LED_PIN, LOW); // ensure the LED is lit previousButtonState = buttonState; }