tls handling and bug fixes

This commit is contained in:
2026-01-07 16:53:50 -06:00
parent 4e4add5287
commit 3ccd1705f0
6 changed files with 191 additions and 82 deletions

View File

@@ -2,16 +2,39 @@
#include "esp_http_client.h" #include "esp_http_client.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "defines.h" #include "defines.h"
#define httpSrv "http://192.168.1.190:3000/" #include "esp_crt_bundle.h"
std::string webToken; std::string webToken;
const std::string urlBase = std::string("http") + (secureSrv ? "s" : "") + "://" + srvAddr + "/";
esp_err_t _http_event_handler(esp_http_client_event_t *evt) {
switch(evt->event_id) {
case HTTP_EVENT_ON_DATA: {
// Append received data to buffer (handles both chunked and non-chunked)
if (evt->data_len > 0 && evt->user_data != NULL) {
std::string* rxBuffer = (std::string*)evt->user_data;
rxBuffer->append((char*)evt->data, evt->data_len);
}
break;
}
default:
break;
}
return ESP_OK;
}
bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) { bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) {
std::string url = std::string(httpSrv) + endpoint; std::string url = urlBase + endpoint;
std::string responseBuffer = "";
esp_http_client_config_t config = {}; esp_http_client_config_t config = {};
config.url = url.c_str(); config.url = url.c_str();
config.method = HTTP_METHOD_GET; config.event_handler = _http_event_handler; // Attach the bucket
config.user_data = &responseBuffer; // Pass pointer to our string so the handler can write to it
if (secureSrv) {
config.transport_type = HTTP_TRANSPORT_OVER_SSL;
config.crt_bundle_attach = esp_crt_bundle_attach;
}
esp_http_client_handle_t client = esp_http_client_init(&config); esp_http_client_handle_t client = esp_http_client_init(&config);
@@ -20,50 +43,24 @@ bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) {
esp_http_client_set_header(client, "Authorization", authHeader.c_str()); esp_http_client_set_header(client, "Authorization", authHeader.c_str());
// Open connection and fetch headers // Open connection and fetch headers
esp_err_t err = esp_http_client_open(client, 0); esp_err_t err = esp_http_client_perform(client);
bool success = false; bool success = false;
if (err == ESP_OK) { if (err == ESP_OK) {
int content_length = esp_http_client_fetch_headers(client); int status_code = esp_http_client_get_status_code(client);
int status_code = esp_http_client_get_status_code(client); printf("Status = %d, Content Length = %d\n", status_code, esp_http_client_get_content_length(client));
printf("HTTP Status = %d, content_length = %d\n", status_code, content_length);
if (status_code == 200 && content_length > 0) {
// Allocate buffer for the response
char *buffer = (char *)malloc(content_length + 1);
if (buffer) {
int total_read = 0;
int read_len;
// Read the response body if (status_code == 200) {
while (total_read < content_length) { printf("Response: %s\n", responseBuffer.c_str());
read_len = esp_http_client_read(client, buffer + total_read, content_length - total_read); JSONresponse = cJSON_Parse(responseBuffer.c_str());
if (read_len <= 0) break; if (JSONresponse) success = true;
total_read += read_len;
} }
} else {
buffer[total_read] = '\0'; printf("HTTP GET failed: %s\n", esp_err_to_name(err));
printf("Response body: %s\n", buffer);
JSONresponse = cJSON_Parse(buffer);
success = (JSONresponse != NULL);
if (!success) {
printf("Failed to parse JSON\n");
}
free(buffer);
} else {
printf("Failed to allocate buffer for response\n");
}
} }
esp_http_client_close(client); esp_http_client_cleanup(client);
} else printf("HTTP request failed: %s\n", esp_err_to_name(err)); return success;
esp_http_client_cleanup(client);
return success;
} }
void deleteWiFiAndTokenDetails() { void deleteWiFiAndTokenDetails() {

View File

@@ -27,14 +27,20 @@
#define nvsServo "SERVO" #define nvsServo "SERVO"
#define posTag "POS" #define posTag "POS"
#define ENCODER_PIN_A GPIO_NUM_23 #define secureSrv true
#define ENCODER_PIN_B GPIO_NUM_16 // #define srvAddr "192.168.1.190:3000"
#define srvAddr "wahwa.com"
#define InputEnc_PIN_A GPIO_NUM_1 #define ENCODER_PIN_A GPIO_NUM_23 // d5
#define InputEnc_PIN_B GPIO_NUM_2 #define ENCODER_PIN_B GPIO_NUM_16 // d6
#define InputEnc_PIN_A GPIO_NUM_1 // d1
#define InputEnc_PIN_B GPIO_NUM_2 // d2
#define servoPin GPIO_NUM_20 #define servoPin GPIO_NUM_20
#define servoLEDCChannel LEDC_CHANNEL_0 #define servoLEDCChannel LEDC_CHANNEL_0
#define servoSwitch GPIO_NUM_17 #define servoSwitch GPIO_NUM_17
#define debugLED GPIO_NUM_22 // d4
#endif #endif

View File

@@ -9,7 +9,8 @@ static const char *TAG = "ENCODER";
// Constructor // Constructor
Encoder::Encoder(gpio_num_t pinA, gpio_num_t pinB) Encoder::Encoder(gpio_num_t pinA, gpio_num_t pinB)
: pin_a(pinA), pin_b(pinB), count(0), : pin_a(pinA), pin_b(pinB), count(0),
last_state_a(0), last_state_b(0), last_count_base(0) {} last_state_a(0), last_state_b(0), last_count_base(0),
watchdog_handle(nullptr) {}
// Static ISR - receives Encoder instance via arg // Static ISR - receives Encoder instance via arg
void IRAM_ATTR Encoder::isr_handler(void* arg) void IRAM_ATTR Encoder::isr_handler(void* arg)
@@ -48,7 +49,11 @@ void IRAM_ATTR Encoder::isr_handler(void* arg)
encoder->count += 1; encoder->count += 1;
encoder->last_count_base -= 4; encoder->last_count_base -= 4;
if (calibListen) servoCalibListen(); if (calibListen) servoCalibListen();
if (encoder->feedWDog) esp_timer_restart(encoder->watchdog_handle, 500000); if (encoder->feedWDog) {
esp_timer_stop(encoder->watchdog_handle);
esp_timer_start_once(encoder->watchdog_handle, 500000);
debugLEDTgl();
}
if (encoder->wandListen) servoWandListen(); if (encoder->wandListen) servoWandListen();
if (encoder->serverListen) servoServerListen(); if (encoder->serverListen) servoServerListen();
} }
@@ -56,7 +61,11 @@ void IRAM_ATTR Encoder::isr_handler(void* arg)
encoder->count -= 1; encoder->count -= 1;
encoder->last_count_base += 4; encoder->last_count_base += 4;
if (calibListen) servoCalibListen(); if (calibListen) servoCalibListen();
if (encoder->feedWDog) esp_timer_restart(encoder->watchdog_handle, 500000); if (encoder->feedWDog) {
esp_timer_stop(encoder->watchdog_handle);
esp_timer_start_once(encoder->watchdog_handle, 500000);
debugLEDTgl();
}
if (encoder->wandListen) servoWandListen(); if (encoder->wandListen) servoWandListen();
if (encoder->serverListen) servoServerListen(); if (encoder->serverListen) servoServerListen();
} }
@@ -107,9 +116,9 @@ void Encoder::setupWatchdog() {
feedWDog = true; feedWDog = true;
} }
void Encoder::pauseWatchdog() { void IRAM_ATTR Encoder::pauseWatchdog() {
if (watchdog_handle != nullptr) esp_timer_stop(watchdog_handle);
feedWDog = false; feedWDog = false;
if (watchdog_handle != NULL) esp_timer_stop(watchdog_handle);
} }
Encoder::~Encoder() { Encoder::~Encoder() {

View File

@@ -41,8 +41,14 @@ void servoInit() {
gpio_set_direction(servoSwitch, GPIO_MODE_OUTPUT); gpio_set_direction(servoSwitch, GPIO_MODE_OUTPUT);
gpio_set_level(servoSwitch, 0); // Start with servo power off gpio_set_level(servoSwitch, 0); // Start with servo power off
// Configure debug LED pin as output
gpio_reset_pin(GPIO_NUM_22);
gpio_set_direction(debugLED, GPIO_MODE_OUTPUT);
gpio_set_level(debugLED, 0); // Start with LED off
topEnc->count = servoReadPos(); topEnc->count = servoReadPos();
if (calib.getCalibrated()) initMainLoop(); if (calib.getCalibrated()) initMainLoop();
debugLEDSwitch(1);
} }
void servoOn(uint8_t dir, uint8_t manOrServer) { void servoOn(uint8_t dir, uint8_t manOrServer) {
@@ -65,13 +71,22 @@ void servoMainSwitch(uint8_t onOff) {
gpio_set_level(servoSwitch, onOff ? 1 : 0); gpio_set_level(servoSwitch, onOff ? 1 : 0);
} }
void debugLEDSwitch(uint8_t onOff) {
gpio_set_level(debugLED, onOff ? 1 : 0);
}
void debugLEDTgl() {
static bool onOff = false;
gpio_set_level(debugLED, onOff);
onOff = !onOff;
}
bool servoInitCalib() { bool servoInitCalib() {
topEnc->pauseWatchdog(); topEnc->pauseWatchdog();
// get ready for calibration by clearing all these listeners // get ready for calibration by clearing all these listeners
bottomEnc->wandListen = false; bottomEnc->wandListen.store(false, std::memory_order_release);
topEnc->wandListen = false; topEnc->wandListen.store(false, std::memory_order_release);
topEnc->serverListen = false; topEnc->serverListen.store(false, std::memory_order_release);
if (!calib.clearCalibrated()) return false; if (!calib.clearCalibrated()) return false;
if (topEnc == nullptr || bottomEnc == nullptr) { if (topEnc == nullptr || bottomEnc == nullptr) {
printf("ERROR: CALIBRATION STARTED BEFORE SERVO INITIALIZATION\n"); printf("ERROR: CALIBRATION STARTED BEFORE SERVO INITIALIZATION\n");
@@ -82,11 +97,20 @@ bool servoInitCalib() {
return true; return true;
} }
void servoCancelCalib() {
calibListen = false;
servoOff();
}
void servoCalibListen() { void servoCalibListen() {
int32_t effDiff = (bottomEnc->getCount() - topEnc->getCount()) - baseDiff; int32_t effDiff = (bottomEnc->getCount() - topEnc->getCount()) - baseDiff;
if (effDiff > 1) servoOn(CCW, manual); if (effDiff > 1) servoOn(CCW, manual);
else if (effDiff < -1) servoOn(CW, manual); else if (effDiff < -1) {
else servoOff(); servoOn(CW, manual);
}
else {
servoOff();
}
} }
bool servoBeginDownwardCalib() { bool servoBeginDownwardCalib() {
@@ -111,7 +135,7 @@ bool servoCompleteCalib() {
void initMainLoop() { void initMainLoop() {
topEnc->setupWatchdog(); topEnc->setupWatchdog();
servoSavePos(); servoSavePos();
bottomEnc->wandListen = true; bottomEnc->wandListen.store(true, std::memory_order_release);
} }
void IRAM_ATTR watchdogCallback(void* arg) { void IRAM_ATTR watchdogCallback(void* arg) {
@@ -121,9 +145,9 @@ void IRAM_ATTR watchdogCallback(void* arg) {
topEnc->pauseWatchdog(); topEnc->pauseWatchdog();
// get ready for recalibration by clearing all these listeners // get ready for recalibration by clearing all these listeners
bottomEnc->wandListen = false; bottomEnc->wandListen.store(false, std::memory_order_release);
topEnc->wandListen = false; topEnc->wandListen.store(false, std::memory_order_release);
topEnc->serverListen = false; topEnc->serverListen.store(false, std::memory_order_release);
servoOff(); servoOff();
} }
else { else {
@@ -170,7 +194,7 @@ int32_t servoReadPos() {
void stopServerRun() { void stopServerRun() {
// stop listener and stop running if serverRun is still active. // stop listener and stop running if serverRun is still active.
topEnc->serverListen = false; topEnc->serverListen.store(false, std::memory_order_release);
if (runningServer) servoOff(); if (runningServer) servoOff();
} }
@@ -199,21 +223,27 @@ void servoWandListen() {
// if effective difference is 0, stop servo and servo-listener // if effective difference is 0, stop servo and servo-listener
// otherwise, run servo in whichever direction necessary and // otherwise, run servo in whichever direction necessary and
// ensure servo-listener is active. // ensure servo-listener is active.
if (abs(topCount - upBound) <= 1 || abs(topCount - downBound) <= 1) { if (topCount >= (MAX(upBound, downBound) - 1)
&& effDiff > 1) { // TODO: see whether these margins need to be removed.
servoOff(); servoOff();
topEnc->wandListen = false; topEnc->wandListen.store(false, std::memory_order_release);
}
else if (topCount <= (MIN(upBound, downBound) + 1)
&& effDiff < -1) {
servoOff();
topEnc->wandListen.store(false, std::memory_order_release);
} }
else if (effDiff > 1) { else if (effDiff > 1) {
topEnc->wandListen = true; topEnc->wandListen.store(true, std::memory_order_release);
servoOn(CCW, manual); servoOn(CCW, manual);
} }
else if (effDiff < -1) { else if (effDiff < -1) {
topEnc->wandListen = true; topEnc->wandListen.store(true, std::memory_order_release);
servoOn(CW, manual); servoOn(CW, manual);
} }
else { else {
servoOff(); servoOff();
topEnc->wandListen = false; topEnc->wandListen.store(false, std::memory_order_release);
} }
} }
@@ -230,14 +260,16 @@ void runToAppPos(uint8_t appPos) {
if (runningManual || !calib.getCalibrated()) return; if (runningManual || !calib.getCalibrated()) return;
servoOff(); servoOff();
target = calib.convertToTicks(appPos); // calculate target encoder position
printf("runToAppPos Called, running to %d from %d", target.load(), topEnc->getCount());
// allow servo position to settle // allow servo position to settle
vTaskDelay(pdMS_TO_TICKS(500)); vTaskDelay(pdMS_TO_TICKS(500));
int32_t topCount = topEnc->getCount(); int32_t topCount = topEnc->getCount();
target = calib.convertToTicks(appPos); // calculate target encoder position
if (abs(topCount - target) <= 1) return; if (abs(topCount - target) <= 1) return;
startLess = topCount < target; startLess = topCount < target;
if (runningManual) return; // check again before starting remote control if (runningManual) return; // check again before starting remote control
if (startLess) servoOn(CCW, server); // begin servo movement if (startLess) servoOn(CCW, server); // begin servo movement
else servoOn(CW, server); else servoOn(CW, server);
topEnc->serverListen = true; // start listening for shutoff point topEnc->serverListen.store(true, std::memory_order_release); // start listening for shutoff point
} }

View File

@@ -25,6 +25,9 @@ void servoCalibListen();
bool servoInitCalib(); bool servoInitCalib();
bool servoBeginDownwardCalib(); bool servoBeginDownwardCalib();
bool servoCompleteCalib(); bool servoCompleteCalib();
void servoCancelCalib();
void debugLEDSwitch(uint8_t onOff);
void debugLEDTgl();
void initMainLoop(); void initMainLoop();
void watchdogCallback(void* arg); void watchdogCallback(void* arg);

View File

@@ -6,6 +6,8 @@
#include "cJSON.h" #include "cJSON.h"
#include "calibration.hpp" #include "calibration.hpp"
#include "servo.hpp" #include "servo.hpp"
#include "defines.h"
#include "esp_crt_bundle.h"
static esp_socketio_client_handle_t io_client; static esp_socketio_client_handle_t io_client;
static esp_socketio_packet_handle_t tx_packet = NULL; static esp_socketio_packet_handle_t tx_packet = NULL;
@@ -139,8 +141,15 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
emitCalibError("Non-1 Port"); emitCalibError("Non-1 Port");
} }
else { else {
if (!servoInitCalib()) emitCalibError("Initialization failed"); printf("Running initCalib...\n");
else emitCalibStage1Ready(); if (!servoInitCalib()) {
printf("initCalib returned False\n");
emitCalibError("Initialization failed");
}
else {
printf("Ready to calibrate\n");
emitCalibStage1Ready();
}
} }
} }
} }
@@ -157,11 +166,11 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
printf("Error, non-1 port received for calibration\n"); printf("Error, non-1 port received for calibration\n");
emitCalibError("Non-1 Port"); emitCalibError("Non-1 Port");
} }
else { else {
if (!servoBeginDownwardCalib()) if (!servoBeginDownwardCalib())
emitCalibError("Direction Switch Failed"); emitCalibError("Direction Switch Failed");
else emitCalibStage2Ready(); else emitCalibStage2Ready();
} }
} }
} }
} }
@@ -184,6 +193,24 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
} }
} }
} }
// Handle user_stage1_complete event
else if (strcmp(eventName->valuestring, "cancel_calib") == 0) {
printf("Canceling calibration process...\n");
cJSON *data = cJSON_GetArrayItem(json, 1);
if (data) {
cJSON *port = cJSON_GetObjectItem(data, "port");
if (port && cJSON_IsNumber(port)) {
if (port->valueint != 1) {
printf("Error, non-1 port received for calibration\n");
emitCalibError("Non-1 Port");
}
else {
servoCancelCalib();
}
}
}
}
// Handle server position change (manual or scheduled) // Handle server position change (manual or scheduled)
else if (strcmp(eventName->valuestring, "posUpdates") == 0) { else if (strcmp(eventName->valuestring, "posUpdates") == 0) {
@@ -225,18 +252,47 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
case SOCKETIO_EVENT_ERROR: { case SOCKETIO_EVENT_ERROR: {
printf("Socket.IO Error!\n"); printf("Socket.IO Error!\n");
servoCancelCalib();
// Check WebSocket error details
esp_websocket_event_data_t *ws_event = data->websocket_event; esp_websocket_event_data_t *ws_event = data->websocket_event;
if (ws_event && ws_event->error_handle.esp_ws_handshake_status_code != 0) {
printf("HTTP Status: %d\n", ws_event->error_handle.esp_ws_handshake_status_code); if (ws_event) {
if (ws_event->error_handle.esp_ws_handshake_status_code == 401 || // 1. Check for TLS/SSL specific errors (Certificate issues)
ws_event->error_handle.esp_ws_handshake_status_code == 403) { if (ws_event->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) {
printf("Authentication failed - invalid token\n");
} // This prints the "MbedTLS" error code (The low-level crypto library)
// Common codes: -0x2700 (CRT verify failed), -0x7200 (SSL handshake failed)
if (ws_event->error_handle.esp_tls_stack_err != 0) {
printf("TLS/SSL Stack Error: -0x%x\n", -ws_event->error_handle.esp_tls_stack_err);
}
// 2. Check the Certificate Verification Flags
// If this is non-zero, the certificate was rejected.
if (ws_event->error_handle.esp_tls_cert_verify_flags != 0) {
uint32_t flags = ws_event->error_handle.esp_tls_cert_verify_flags;
printf("Certificate Verification FAILED. Flags: 0x%lx\n", flags);
// Simple decoder for common flags:
if (flags & (1 << 0)) printf(" - CRT_NOT_TRUSTED (Root CA not found in bundle)\n");
if (flags & (1 << 1)) printf(" - CRT_BAD_KEY_USAGE\n");
if (flags & (1 << 2)) printf(" - CRT_EXPIRED (Check your ESP32 system time!)\n");
if (flags & (1 << 3)) printf(" - CRT_CN_MISMATCH (Domain name doesn't match cert)\n");
}
}
// 3. Check for HTTP Handshake errors (401/403/404)
// This happens if SSL worked, but the server rejected your path or token
else if (ws_event->error_handle.error_type == WEBSOCKET_ERROR_TYPE_HANDSHAKE) {
int status = ws_event->error_handle.esp_ws_handshake_status_code;
printf("HTTP Handshake Error: %d\n", status);
if (status == 401 || status == 403) {
printf("Authentication failed - invalid token\n");
} else if (status == 404) {
printf("404 Not Found - Check your URI/Path\n");
}
}
} }
// Set flags to indicate connection failure
connected = false; connected = false;
statusResolved = true; statusResolved = true;
break; break;
@@ -251,6 +307,7 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
} }
} }
const std::string uriString = std::string("ws") + (secureSrv ? "s" : "") + "://" + srvAddr + "/socket.io/?EIO=4&transport=websocket";
void initSocketIO() { void initSocketIO() {
// Prepare the Authorization Header (Bearer format) // Prepare the Authorization Header (Bearer format)
std::string authHeader = "Authorization: Bearer " + webToken + "\r\n"; std::string authHeader = "Authorization: Bearer " + webToken + "\r\n";
@@ -259,8 +316,13 @@ void initSocketIO() {
connected = false; connected = false;
esp_socketio_client_config_t config = {}; esp_socketio_client_config_t config = {};
config.websocket_config.uri = "ws://192.168.1.190:3000/socket.io/?EIO=4&transport=websocket"; config.websocket_config.uri = uriString.c_str();
config.websocket_config.headers = authHeader.c_str(); config.websocket_config.headers = authHeader.c_str();
if (secureSrv) {
config.websocket_config.transport = WEBSOCKET_TRANSPORT_OVER_SSL;
config.websocket_config.crt_bundle_attach = esp_crt_bundle_attach;
}
io_client = esp_socketio_client_init(&config); io_client = esp_socketio_client_init(&config);
tx_packet = esp_socketio_client_get_tx_packet(io_client); tx_packet = esp_socketio_client_get_tx_packet(io_client);