diff --git a/src/fresh.cpp b/src/fresh.cpp index 3d78a43..8ce1e00 100644 --- a/src/fresh.cpp +++ b/src/fresh.cpp @@ -50,9 +50,16 @@ uint32_t getEpochTime() { bool isMessageTimeAcceptable(uint32_t t) { uint32_t localTime = getEpochTime(); if (localTime == 0) { + Serial.println("No epoch time available"); return false; } - return t < localTime + allowedOffset && t > localTime - allowedOffset; + if (t > localTime + allowedOffset) { + return false; + } + if (t < localTime - allowedOffset) { + return false; + } + return true; } void prepareMessageCounterUsage() { @@ -61,23 +68,21 @@ void prepareMessageCounterUsage() { uint32_t getNextMessageCounter() { uint32_t counter = (uint32_t) EEPROM.read(0) << 24; - counter += (uint32_t) EEPROM.read(1) << 16; - counter += (uint32_t) EEPROM.read(2) << 8; - counter += (uint32_t) EEPROM.read(3); + counter += (uint32_t) EEPROM.read(1) << 16; + counter += (uint32_t) EEPROM.read(2) << 8; + counter += (uint32_t) EEPROM.read(3); return counter; } void printMessageCounter() { - Serial.printf("[INFO] Next message number: %d\n", getNextMessageCounter()); + Serial.printf("[INFO] Next message number: %u\n", getNextMessageCounter()); } bool isMessageCounterValid(uint32_t counter) { return counter >= getNextMessageCounter(); } -void didUseMessageCounter(uint32_t counter) { - // Store the next counter, so that resetting starts at 0 - counter += 1; +void setMessageCounter(uint32_t counter) { EEPROM.write(0, (counter >> 24) & 0xFF); EEPROM.write(1, (counter >> 16) & 0xFF); EEPROM.write(2, (counter >> 8) & 0xFF); @@ -86,7 +91,12 @@ void didUseMessageCounter(uint32_t counter) { EEPROM.commit(); } +void didUseMessageCounter(uint32_t counter) { + // Store the next counter, so that resetting starts at 0 + setMessageCounter(counter+1); +} + void resetMessageCounter() { - didUseMessageCounter(0); + setMessageCounter(0); Serial.println("[WARN] Message counter reset"); } diff --git a/src/main.cpp b/src/main.cpp index 743eee4..b17fa10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,7 +48,7 @@ constexpr int32_t timeOffsetDaylightSavings = 3600; // Servo is Emax ES08MA II // The time (in ms) to keep the door button pressed -constexpr uint32_t lockOpeningDuration = 2000; +constexpr uint32_t lockOpeningDuration = 1500; // The timer to use to control the servo constexpr int pwmTimer = 0; @@ -60,7 +60,7 @@ constexpr int servoPin = 14; constexpr int servoFrequency = 50; // The microseconds to set the servo to the pressed and released states -constexpr int servoPressedState = 1600; +constexpr int servoPressedState = 1720;//1600; constexpr int servoReleasedState = 1520; @@ -85,26 +85,48 @@ void setup() { Serial.println("[INFO] Servo configured"); prepareMessageCounterUsage(); + //resetMessageCounter(); printMessageCounter(); - - Serial.printf("[INFO] Connecting to WiFi '%s'\n", wifiSSID); - WiFi.begin(wifiSSID, wifiPassword); - while(WiFi.status() != WL_CONNECTED) { - delay(100); - } - Serial.println("[INFO] WiFi connected"); - configureNTP(timeOffsetToGMT, timeOffsetDaylightSavings, ntpServerUrl); - printLocalTime(); - server.onMessage(handleReceivedMessage); - Serial.printf("[INFO] Opening SSL socket %s%s on port %d\n", serverUrl, serverPath, serverPort); - server.connectSSL(serverAccessKey); } +uint32_t nextWifiReconnect = 0; +bool isReconnecting = false; + void loop() { + uint32_t time = millis(); + server.loop(); servo.loop(); + + // Reconnect to WiFi + if(time > nextWifiReconnect && WiFi.status() != WL_CONNECTED) { + Serial.println("[INFO] Reconnecting WiFi..."); + WiFi.begin(wifiSSID, wifiPassword); + isReconnecting = true; + nextWifiReconnect = time + wifiReconnectInterval; + } + if (isReconnecting && WiFi.status() == WL_CONNECTED) { + isReconnecting = false; + Serial.println("[INFO] WiFi connected, opening socket"); + server.connectSSL(serverAccessKey); + configureNTP(timeOffsetToGMT, timeOffsetDaylightSavings, ntpServerUrl); + printLocalTime(); + } +} + +SesameEvent processMessage(AuthenticatedMessage* message) { + if (!isMessageCounterValid(message->message.id)) { + return SesameEvent::MessageCounterInvalid; + } + if (!isMessageTimeAcceptable(message->message.time)) { + return SesameEvent::MessageTimeMismatch; + } + if (!isAuthenticMessage(message, remoteKey, keySize)) { + return SesameEvent::MessageAuthenticationFailed; + } + return SesameEvent::MessageAccepted; } /** @@ -118,25 +140,21 @@ void loop() { * @return The event to signal to the server. */ SesameEvent handleReceivedMessage(AuthenticatedMessage* message, AuthenticatedMessage* response) { + SesameEvent event = processMessage(message); - if (!isMessageCounterValid(message->message.id)) { - return SesameEvent::MessageCounterInvalid; - } - if (!isMessageTimeAcceptable(message->message.time)) { - return SesameEvent::MessageTimeMismatch; - } - if (!isAuthenticMessage(message, remoteKey, keySize)) { - return SesameEvent::MessageAuthenticationFailed; + // Only open when message is valid + if (event == SesameEvent::MessageAccepted) { + didUseMessageCounter(message->message.id); + // Move servo + servo.pressButton(); + Serial.printf("[Info] Accepted message %d\n", message->message.id); } + // Create response for all cases response->message.time = getEpochTime(); response->message.id = getNextMessageCounter(); if (!authenticateMessage(response, localKey, keySize)) { return SesameEvent::MessageAuthenticationFailed; } - - // Move servo - servo.pressButton(); - Serial.printf("[Info] Accepted message %d\n", message->message.id); - return SesameEvent::MessageAccepted; + return event; } diff --git a/src/server.cpp b/src/server.cpp index cd70dae..6989fe5 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,5 +1,9 @@ #include "server.h" +constexpr int32_t pingInterval = 10000; +constexpr uint32_t pongTimeout = 5000; +uint8_t disconnectTimeoutCount = 3; + ServerConnection::ServerConnection(const char* url, int port, const char* path) : url(url), port(port), path(path) { @@ -12,6 +16,9 @@ void ServerConnection::connect(const char* key, uint32_t reconnectTime) { } void ServerConnection::connectSSL(const char* key, uint32_t reconnectTime) { + if (socketIsConnected) { + return; + } this->key = key; webSocket.beginSSL(url, port, path); registerEventCallback(); @@ -47,6 +54,7 @@ switch(type) { socketIsConnected = true; webSocket.sendTXT(key); Serial.printf("[INFO] Socket connected to url: %s\n", payload); + webSocket.enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount); break; case WStype_TEXT: sendFailureResponse(SesameEvent::TextReceived); @@ -55,6 +63,7 @@ switch(type) { processReceivedBytes(payload, length); break; case WStype_PONG: + break; case WStype_PING: case WStype_ERROR: case WStype_FRAGMENT_TEXT_START: