Use local UDP messages instead of web server

This commit is contained in:
Christoph Hagen 2024-04-20 17:47:44 +02:00
parent 4a88d1a380
commit 1504ce6b0c
5 changed files with 70 additions and 40 deletions

View File

@ -28,4 +28,6 @@ struct EthernetConfiguration {
// The IP address of the DNS server, if DHCP fails // The IP address of the DNS server, if DHCP fails
uint8_t manualDnsAddress[4]; uint8_t manualDnsAddress[4];
// The port for the incoming UDP connection
uint16_t udpPort;
}; };

View File

@ -3,14 +3,13 @@
#include "server.h" #include "server.h"
#include "servo.h" #include "servo.h"
#include "message.h" #include "message.h"
#include <ESPAsyncWebServer.h>
#include "configurations/EthernetConfiguration.h" #include "configurations/EthernetConfiguration.h"
#include "configurations/KeyConfiguration.h" #include "configurations/KeyConfiguration.h"
class SesameController: public ServerConnectionCallbacks { class SesameController: public ServerConnectionCallbacks {
public: public:
SesameController(uint16_t localWebServerPort); SesameController();
void configure(ServoConfiguration servoConfig, ServerConfiguration serverConfig, EthernetConfiguration ethernetConfig, KeyConfiguration keyConfig); void configure(ServoConfiguration servoConfig, ServerConfiguration serverConfig, EthernetConfiguration ethernetConfig, KeyConfiguration keyConfig);
@ -22,7 +21,16 @@ private:
ServerConnection server; ServerConnection server;
ServoController servo; ServoController servo;
AsyncWebServer localWebServer;
// UDP
// buffers for receiving and sending data
char udpReceiveBuffer[SIGNED_MESSAGE_SIZE]; // buffer to hold incoming packet
// An EthernetUDP instance to send and receive packets over UDP
EthernetUDP Udp;
EthernetConfiguration ethernetConfig; EthernetConfiguration ethernetConfig;
bool ethernetIsConfigured = false; bool ethernetIsConfigured = false;
@ -52,7 +60,7 @@ private:
// MARK: Local client callbacks // MARK: Local client callbacks
void handleLocalMessage(AsyncWebServerRequest *request); void checkLocalMessage();
// MARK: Socket Callbacks // MARK: Socket Callbacks
@ -76,7 +84,7 @@ private:
* *
* Note: Prepares the response in the outgoing message buffer. * Note: Prepares the response in the outgoing message buffer.
*/ */
void processMessage(SignedMessage* message); void processMessage(SignedMessage* message, bool shouldPerformUnlock);
/** /**
* @brief Checks that the message is valid and prepares a challenge. * @brief Checks that the message is valid and prepares a challenge.
@ -105,7 +113,7 @@ private:
* *
* Note: Prepares the response in the outgoing message buffer. * Note: Prepares the response in the outgoing message buffer.
*/ */
void completeUnlockRequest(Message* message); void completeUnlockRequest(Message* message, bool shouldPerformUnlock);
// MARK: Responses // MARK: Responses
@ -117,12 +125,18 @@ private:
*/ */
void prepareResponseBuffer(MessageResult event, Message* message = NULL); void prepareResponseBuffer(MessageResult event, Message* message = NULL);
/**
* @brief Read a message from the UDP port
*
*/
bool readLocalMessage();
/** /**
* @brief Send the prepared outgoing message to a locally connected client * @brief Send the prepared outgoing message to a locally connected client
* *
* @param request The original request of the client * @param request The original request of the client
*/ */
void sendPreparedLocalResponse(AsyncWebServerRequest *request); void sendPreparedLocalResponse();
/** /**
* @brief Send the prepared outgoing message to the server * @brief Send the prepared outgoing message to the server
@ -131,5 +145,5 @@ private:
// MARK: Helper // MARK: Helper
bool convertHexMessageToBinary(const char* str); bool convertHexMessageToBinary(const char* str);
}; };

View File

@ -13,9 +13,7 @@ platform = espressif32
board = az-delivery-devkit-v4 board = az-delivery-devkit-v4
framework = arduino framework = arduino
lib_deps = lib_deps =
; links2004/WebSockets@^2.4.0
madhephaestus/ESP32Servo@^1.1.0 madhephaestus/ESP32Servo@^1.1.0
ottowinter/ESPAsyncWebServer-esphome@^3.0.0
arduino-libraries/Ethernet@^2.0.2 arduino-libraries/Ethernet@^2.0.2
https://github.com/christophhagen/arduinoWebSockets#master https://github.com/christophhagen/arduinoWebSockets#master
rweather/Crypto@^0.4.0 rweather/Crypto@^0.4.0

View File

@ -5,7 +5,7 @@
#include <SPI.h> #include <SPI.h>
#include <Ethernet.h> #include <Ethernet.h>
SesameController::SesameController(uint16_t localWebServerPort) : localWebServer(localWebServerPort) { SesameController::SesameController() {
} }
@ -51,41 +51,54 @@ void SesameController::configure(ServoConfiguration servoConfig, ServerConfigura
// Direct messages and errors over the websocket to the controller // Direct messages and errors over the websocket to the controller
server.configure(serverConfig, this); server.configure(serverConfig, this);
Serial.println("[INFO] Server connection configured"); Serial.println("[INFO] Server connection configured");
// Direct messages from the local web server to the controller
localWebServer.on("/message", HTTP_POST, [this] (AsyncWebServerRequest *request) {
this->handleLocalMessage(request);
this->sendPreparedLocalResponse(request);
});
Serial.println("[INFO] Local web server configured"); Udp.begin(ethernetConfig.udpPort);
Serial.println("[INFO] Local UDP connection configured");
} }
void SesameController::loop(uint32_t millis) { void SesameController::loop(uint32_t millis) {
currentTime = millis; currentTime = millis;
server.loop(millis); //server.loop(millis);
checkLocalMessage();
} }
// MARK: Local // MARK: Local
void SesameController::handleLocalMessage(AsyncWebServerRequest *request) { void SesameController::checkLocalMessage() {
if (!request->hasParam(messageUrlParameter)) { if (readLocalMessage()) {
Serial.println("Missing url parameter"); sendPreparedLocalResponse();
prepareResponseBuffer(MessageResult::InvalidUrlParameter);
return;
} }
String encoded = request->getParam(messageUrlParameter)->value();
if (!convertHexMessageToBinary(encoded.c_str())) {
Serial.println("Invalid hex encoding");
prepareResponseBuffer(MessageResult::InvalidMessageSizeFromRemote);
return;
}
processMessage(&receivedLocalMessage);
} }
void SesameController::sendPreparedLocalResponse(AsyncWebServerRequest *request) { bool SesameController::readLocalMessage() {
request->send_P(200, "application/octet-stream", (uint8_t*) &outgoingMessage, SIGNED_MESSAGE_SIZE); // if there's data available, read a packet
Serial.printf("[INFO] Local response %u,%u\n", outgoingMessage.message.messageType, outgoingMessage.message.result); int packetSize = Udp.parsePacket();
if (packetSize == 0) {
return false;
}
if (packetSize != SIGNED_MESSAGE_SIZE) {
Serial.print("Received packet of invalid size ");
Serial.println(packetSize);
prepareResponseBuffer(MessageResult::InvalidMessageSizeFromRemote);
return true;
}
int bytesRead = Udp.read((uint8_t*) &receivedLocalMessage, SIGNED_MESSAGE_SIZE);
if (bytesRead != SIGNED_MESSAGE_SIZE) {
Serial.println("Failed to read full local message");
prepareResponseBuffer(MessageResult::InvalidMessageSizeFromRemote);
return true;
}
Serial.println("Received local message");
processMessage(&receivedLocalMessage, true);
return true;
}
void SesameController::sendPreparedLocalResponse() {
// send a reply to the IP address and port that sent us the packet we received
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write((uint8_t*) &outgoingMessage, SIGNED_MESSAGE_SIZE);
Udp.endPacket();
} }
// MARK: Server // MARK: Server
@ -101,7 +114,7 @@ void SesameController::handleServerMessage(uint8_t* payload, size_t length) {
sendServerError(MessageResult::InvalidMessageSizeFromRemote); sendServerError(MessageResult::InvalidMessageSizeFromRemote);
return; return;
} }
processMessage((SignedMessage*) payload); processMessage((SignedMessage*) payload, true);
sendPreparedResponseToServer(); sendPreparedResponseToServer();
} }
@ -112,7 +125,7 @@ void SesameController::sendPreparedResponseToServer() {
// MARK: Message handling // MARK: Message handling
void SesameController::processMessage(SignedMessage* message) { void SesameController::processMessage(SignedMessage* message, bool shouldPerformUnlock) {
// Result must be empty // Result must be empty
if (message->message.result != MessageResult::MessageAccepted) { if (message->message.result != MessageResult::MessageAccepted) {
prepareResponseBuffer(MessageResult::InvalidMessageResultFromRemote); prepareResponseBuffer(MessageResult::InvalidMessageResultFromRemote);
@ -127,7 +140,7 @@ void SesameController::processMessage(SignedMessage* message) {
checkAndPrepareChallenge(&message->message); checkAndPrepareChallenge(&message->message);
return; return;
case MessageType::request: case MessageType::request:
completeUnlockRequest(&message->message); completeUnlockRequest(&message->message, shouldPerformUnlock);
return; return;
default: default:
prepareResponseBuffer(MessageResult::InvalidMessageTypeFromRemote); prepareResponseBuffer(MessageResult::InvalidMessageTypeFromRemote);
@ -158,7 +171,7 @@ void SesameController::prepareChallenge(Message* message) {
prepareResponseBuffer(MessageResult::MessageAccepted, message); prepareResponseBuffer(MessageResult::MessageAccepted, message);
} }
void SesameController::completeUnlockRequest(Message* message) { void SesameController::completeUnlockRequest(Message* message, bool shouldPerformUnlock) {
// Client and server challenge must match // Client and server challenge must match
if (message->clientChallenge != currentClientChallenge) { if (message->clientChallenge != currentClientChallenge) {
prepareResponseBuffer(MessageResult::InvalidClientChallengeFromRemote, message); prepareResponseBuffer(MessageResult::InvalidClientChallengeFromRemote, message);
@ -180,7 +193,9 @@ void SesameController::completeUnlockRequest(Message* message) {
clearCurrentChallenge(); clearCurrentChallenge();
// Move servo // Move servo
servo.pressButton(); if (shouldPerformUnlock) {
servo.pressButton();
}
prepareResponseBuffer(MessageResult::MessageAccepted, message); prepareResponseBuffer(MessageResult::MessageAccepted, message);
Serial.println("[INFO] Accepted message"); Serial.println("[INFO] Accepted message");
} }

View File

@ -22,7 +22,7 @@
#include "controller.h" #include "controller.h"
#include "config.h" #include "config.h"
SesameController controller(localPort); SesameController controller{};
void setup() { void setup() {
Serial.begin(serialBaudRate); Serial.begin(serialBaudRate);
@ -59,6 +59,7 @@ void setup() {
.dhcpLeaseResponseTimeoutMs = dhcpLeaseResponseTimeoutMs, .dhcpLeaseResponseTimeoutMs = dhcpLeaseResponseTimeoutMs,
.manualIp = manualIpAddress, .manualIp = manualIpAddress,
.manualDnsAddress = manualDnsServerAddress, .manualDnsAddress = manualDnsServerAddress,
.udpPort = localUdpPort,
}; };
KeyConfiguration keyConfig { KeyConfiguration keyConfig {