Finish socket operations

This commit is contained in:
Christoph Hagen 2023-12-05 21:31:11 +01:00
parent 9b49c3565d
commit 4c23565b9c
6 changed files with 121 additions and 55 deletions

View File

@ -31,9 +31,6 @@ struct EthernetConfiguration {
// The IP address of the DNS server, if DHCP fails
uint8_t manualDnsAddress[4];
uint32_t socketHeartbeatIntervalMs;
uint32_t socketHeartbeatTimeoutMs;
uint8_t socketHeartbeatFailureReconnectCount;
};
struct KeyConfiguration {
@ -88,23 +85,11 @@ private:
currentChallengeExpiry = 0;
}
/**
* @brief Send an error Response over the web socket.
*
* @param result The error result to send
* @param discardMessage Indicate if the stored message should be cleared.
*
* Note: Only clear the message if no other operation is in progress.
*/
void sendErrorResponseToServer(MessageResult result, bool discardMessage = true);
void ensureWebSocketConnection();
// MARK: Local client callbacks
void handleLocalMessage(AsyncWebServerRequest *request);
bool convertHexMessageToBinary(const char* str);
void handleServerMessage(uint8_t* payload, size_t length);
// MARK: Socket Callbacks
/**
* @brief Callback to send an error back to the server via the web socket.
@ -115,13 +100,60 @@ private:
*/
void sendServerError(MessageResult event);
void processMessage(SignedMessage* message);
MessageResult verifyAndProcessReceivedMessage(SignedMessage* message);
void handleServerMessage(uint8_t* payload, size_t length);
// MARK: Message processing
/**
* @brief Process a received message (local or socket).
*
* @param message The message to process.
*
* Note: Prepares the response in the outgoing message buffer.
*/
void processMessage(SignedMessage* message);
/**
* @brief Prepare a server challenge for a local or socket message.
*
* @param message The message to respond to
*
* Note: Prepares the response in the outgoing message buffer.
*/
void prepareChallenge(Message* message);
/**
* @brief Complete an unlock request for a local or socket message.
*
* @param message The message to respond to
*
* Note: Prepares the response in the outgoing message buffer.
*/
void completeUnlockRequest(Message* message);
// MARK: Responses
/**
* @brief Prepare the outgoing message buffer for both socket and local responses.
*
* @param event The resulting state to transmit
* @param message An optional message to echo
*/
void prepareResponseBuffer(MessageResult event, Message* message = NULL);
/**
* @brief Send the prepared outgoing message to a locally connected client
*
* @param request The original request of the client
*/
void sendPreparedLocalResponse(AsyncWebServerRequest *request);
/**
* @brief Send the prepared outgoing message to the server
*/
void sendPreparedResponseToServer();
void prepareChallenge(Message* message);
void completeUnlockRequest(Message* message);
// MARK: Helper
bool convertHexMessageToBinary(const char* str);
};

View File

@ -28,6 +28,10 @@ struct ServerConfiguration {
uint32_t reconnectTime;
uint32_t socketHeartbeatIntervalMs;
uint32_t socketHeartbeatTimeoutMs;
uint8_t socketHeartbeatFailureReconnectCount;
};
class ServerConnectionCallbacks {
@ -51,11 +55,13 @@ public:
*/
void configure(ServerConfiguration configuration, ServerConnectionCallbacks* callbacks);
void connect();
void disconnect();
void loop();
/**
* @brief Call this function regularly to handle socket operations.
*
* Connecting and disconnecting is done automatically.
*
*/
void loop(uint32_t millis);
/**
* @brief Send a response message over the socket
@ -65,11 +71,24 @@ public:
*/
void sendResponse(uint8_t* buffer, uint16_t length);
bool isSocketConnected() {
private:
uint32_t currentTime;
bool socketIsConnected() {
return webSocket.isConnected();
}
private:
void connect();
void disconnect();
bool shouldReconnect = true;
uint32_t nextReconnectAttemptMs = 0;
void didDisconnect();
void didConnect();
ServerConfiguration configuration;

View File

@ -20,3 +20,4 @@ lib_deps =
https://github.com/christophhagen/arduinoWebSockets#master
monitor_speed = 115200
build_flags= -D WEBSOCKETS_NETWORK_TYPE=NETWORK_W5100

View File

@ -62,10 +62,8 @@ void SesameController::configure(ServoConfiguration servoConfig, ServerConfigura
void SesameController::loop(uint32_t millis) {
currentTime = millis;
server.loop();
server.loop(millis);
servo.loop(millis);
ensureWebSocketConnection();
}
// MARK: Local
@ -199,20 +197,6 @@ void SesameController::prepareResponseBuffer(MessageResult result, Message* mess
}
}
void SesameController::ensureWebSocketConnection() {
/*
if (isReconnecting && WiFi.status() == WL_CONNECTED) {
isReconnecting = false;
Serial.print("WiFi IP address: ");
Serial.println(WiFi.localIP());
server.connect();
timeCheck.startNTP();
timeCheck.printLocalTime();
localWebServer.begin();
}
*/
}
// MARK: Helper
/**

View File

@ -4,6 +4,15 @@
*
* The code for a simple door unlock mechanism where a servo pushes on an existing
* physical button.
*
* On compile error:
*
* In <Server.h>
*
* change:
* virtual void begin(uint16_t port=0) =0;
* to:
* virtual void begin() =0;
*/
#include <Arduino.h>
@ -35,6 +44,9 @@ void setup() {
.path = serverPath,
.key = serverAccessKey,
.reconnectTime = 5000,
.socketHeartbeatIntervalMs = socketHeartbeatIntervalMs,
.socketHeartbeatTimeoutMs = socketHeartbeatTimeoutMs,
.socketHeartbeatFailureReconnectCount = socketHeartbeatFailureReconnectCount,
};
EthernetConfiguration ethernetConfig {
@ -47,9 +59,6 @@ void setup() {
.dhcpLeaseResponseTimeoutMs = dhcpLeaseResponseTimeoutMs,
.manualIp = manualIpAddress,
.manualDnsAddress = manualDnsServerAddress,
.socketHeartbeatIntervalMs = socketHeartbeatIntervalMs,
.socketHeartbeatTimeoutMs = socketHeartbeatTimeoutMs,
.socketHeartbeatFailureReconnectCount = socketHeartbeatFailureReconnectCount,
};
KeyConfiguration keyConfig {

View File

@ -20,7 +20,8 @@ void ServerConnection::connect() {
return;
}
webSocket.beginSSL(configuration.url, configuration.port, configuration.path);
webSocket.begin(configuration.url, configuration.port, configuration.path);
webSocket.setAuthorization(configuration.key);
std::function<void(WStype_t, uint8_t *, size_t)> f = [this](WStype_t type, uint8_t *payload, size_t length) {
this->webSocketEventHandler(type, payload, length);
@ -29,23 +30,41 @@ void ServerConnection::connect() {
webSocket.setReconnectInterval(configuration.reconnectTime);
}
void ServerConnection::didDisconnect() {
if (shouldReconnect) {
return; // Disconnect already registered.
}
Serial.println("[INFO] Socket disconnected");
nextReconnectAttemptMs = currentTime + configuration.socketHeartbeatIntervalMs;
shouldReconnect = true;
}
void ServerConnection::didConnect() {
Serial.println("[INFO] Socket connected");
webSocket.sendTXT(configuration.key);
webSocket.enableHeartbeat(configuration.socketHeartbeatIntervalMs, configuration.socketHeartbeatTimeoutMs, configuration.socketHeartbeatFailureReconnectCount);
}
void ServerConnection::disconnect() {
webSocket.disconnect();
}
void ServerConnection::loop() {
void ServerConnection::loop(uint32_t millis) {
currentTime = millis;
webSocket.loop();
if (shouldReconnect) {
shouldReconnect = false;
connect();
}
}
void ServerConnection::webSocketEventHandler(WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.println("[INFO] Socket disconnected.");
didDisconnect();
break;
case WStype_CONNECTED:
webSocket.sendTXT(configuration.key);
Serial.printf("[INFO] Socket connected to url: %s\n", payload);
webSocket.enableHeartbeat(pingInterval, pongTimeout, disconnectTimeoutCount);
didConnect();
break;
case WStype_TEXT:
controller->sendServerError(MessageResult::TextReceived);
@ -67,5 +86,7 @@ switch(type) {
}
void ServerConnection::sendResponse(uint8_t* buffer, uint16_t length) {
if (socketIsConnected()) {
webSocket.sendBIN(buffer, length);
}
}