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 "nvs_flash.h"
#include "defines.h"
#define httpSrv "http://192.168.1.190:3000/"
#include "esp_crt_bundle.h"
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) {
std::string url = std::string(httpSrv) + endpoint;
std::string url = urlBase + endpoint;
std::string responseBuffer = "";
esp_http_client_config_t config = {};
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);
@@ -20,50 +43,24 @@ bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) {
esp_http_client_set_header(client, "Authorization", authHeader.c_str());
// 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;
if (err == ESP_OK) {
int content_length = esp_http_client_fetch_headers(client);
int status_code = esp_http_client_get_status_code(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;
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));
// Read the response body
while (total_read < content_length) {
read_len = esp_http_client_read(client, buffer + total_read, content_length - total_read);
if (read_len <= 0) break;
total_read += read_len;
if (status_code == 200) {
printf("Response: %s\n", responseBuffer.c_str());
JSONresponse = cJSON_Parse(responseBuffer.c_str());
if (JSONresponse) success = true;
}
buffer[total_read] = '\0';
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");
}
} else {
printf("HTTP GET failed: %s\n", esp_err_to_name(err));
}
esp_http_client_close(client);
} else printf("HTTP request failed: %s\n", esp_err_to_name(err));
esp_http_client_cleanup(client);
return success;
esp_http_client_cleanup(client);
return success;
}
void deleteWiFiAndTokenDetails() {

View File

@@ -27,14 +27,20 @@
#define nvsServo "SERVO"
#define posTag "POS"
#define ENCODER_PIN_A GPIO_NUM_23
#define ENCODER_PIN_B GPIO_NUM_16
#define secureSrv true
// #define srvAddr "192.168.1.190:3000"
#define srvAddr "wahwa.com"
#define InputEnc_PIN_A GPIO_NUM_1
#define InputEnc_PIN_B GPIO_NUM_2
#define ENCODER_PIN_A GPIO_NUM_23 // d5
#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 servoLEDCChannel LEDC_CHANNEL_0
#define servoSwitch GPIO_NUM_17
#define debugLED GPIO_NUM_22 // d4
#endif

View File

@@ -9,7 +9,8 @@ static const char *TAG = "ENCODER";
// Constructor
Encoder::Encoder(gpio_num_t pinA, gpio_num_t pinB)
: 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
void IRAM_ATTR Encoder::isr_handler(void* arg)
@@ -48,7 +49,11 @@ void IRAM_ATTR Encoder::isr_handler(void* arg)
encoder->count += 1;
encoder->last_count_base -= 4;
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->serverListen) servoServerListen();
}
@@ -56,7 +61,11 @@ void IRAM_ATTR Encoder::isr_handler(void* arg)
encoder->count -= 1;
encoder->last_count_base += 4;
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->serverListen) servoServerListen();
}
@@ -107,9 +116,9 @@ void Encoder::setupWatchdog() {
feedWDog = true;
}
void Encoder::pauseWatchdog() {
void IRAM_ATTR Encoder::pauseWatchdog() {
if (watchdog_handle != nullptr) esp_timer_stop(watchdog_handle);
feedWDog = false;
if (watchdog_handle != NULL) esp_timer_stop(watchdog_handle);
}
Encoder::~Encoder() {

View File

@@ -41,8 +41,14 @@ void servoInit() {
gpio_set_direction(servoSwitch, GPIO_MODE_OUTPUT);
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();
if (calib.getCalibrated()) initMainLoop();
debugLEDSwitch(1);
}
void servoOn(uint8_t dir, uint8_t manOrServer) {
@@ -65,13 +71,22 @@ void servoMainSwitch(uint8_t onOff) {
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() {
topEnc->pauseWatchdog();
// get ready for calibration by clearing all these listeners
bottomEnc->wandListen = false;
topEnc->wandListen = false;
topEnc->serverListen = false;
bottomEnc->wandListen.store(false, std::memory_order_release);
topEnc->wandListen.store(false, std::memory_order_release);
topEnc->serverListen.store(false, std::memory_order_release);
if (!calib.clearCalibrated()) return false;
if (topEnc == nullptr || bottomEnc == nullptr) {
printf("ERROR: CALIBRATION STARTED BEFORE SERVO INITIALIZATION\n");
@@ -82,11 +97,20 @@ bool servoInitCalib() {
return true;
}
void servoCancelCalib() {
calibListen = false;
servoOff();
}
void servoCalibListen() {
int32_t effDiff = (bottomEnc->getCount() - topEnc->getCount()) - baseDiff;
if (effDiff > 1) servoOn(CCW, manual);
else if (effDiff < -1) servoOn(CW, manual);
else servoOff();
else if (effDiff < -1) {
servoOn(CW, manual);
}
else {
servoOff();
}
}
bool servoBeginDownwardCalib() {
@@ -111,7 +135,7 @@ bool servoCompleteCalib() {
void initMainLoop() {
topEnc->setupWatchdog();
servoSavePos();
bottomEnc->wandListen = true;
bottomEnc->wandListen.store(true, std::memory_order_release);
}
void IRAM_ATTR watchdogCallback(void* arg) {
@@ -121,9 +145,9 @@ void IRAM_ATTR watchdogCallback(void* arg) {
topEnc->pauseWatchdog();
// get ready for recalibration by clearing all these listeners
bottomEnc->wandListen = false;
topEnc->wandListen = false;
topEnc->serverListen = false;
bottomEnc->wandListen.store(false, std::memory_order_release);
topEnc->wandListen.store(false, std::memory_order_release);
topEnc->serverListen.store(false, std::memory_order_release);
servoOff();
}
else {
@@ -170,7 +194,7 @@ int32_t servoReadPos() {
void stopServerRun() {
// stop listener and stop running if serverRun is still active.
topEnc->serverListen = false;
topEnc->serverListen.store(false, std::memory_order_release);
if (runningServer) servoOff();
}
@@ -199,21 +223,27 @@ void servoWandListen() {
// if effective difference is 0, stop servo and servo-listener
// otherwise, run servo in whichever direction necessary and
// 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();
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) {
topEnc->wandListen = true;
topEnc->wandListen.store(true, std::memory_order_release);
servoOn(CCW, manual);
}
else if (effDiff < -1) {
topEnc->wandListen = true;
topEnc->wandListen.store(true, std::memory_order_release);
servoOn(CW, manual);
}
else {
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;
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
vTaskDelay(pdMS_TO_TICKS(500));
int32_t topCount = topEnc->getCount();
target = calib.convertToTicks(appPos); // calculate target encoder position
if (abs(topCount - target) <= 1) return;
startLess = topCount < target;
if (runningManual) return; // check again before starting remote control
if (startLess) servoOn(CCW, server); // begin servo movement
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 servoBeginDownwardCalib();
bool servoCompleteCalib();
void servoCancelCalib();
void debugLEDSwitch(uint8_t onOff);
void debugLEDTgl();
void initMainLoop();
void watchdogCallback(void* arg);

View File

@@ -6,6 +6,8 @@
#include "cJSON.h"
#include "calibration.hpp"
#include "servo.hpp"
#include "defines.h"
#include "esp_crt_bundle.h"
static esp_socketio_client_handle_t io_client;
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");
}
else {
if (!servoInitCalib()) emitCalibError("Initialization failed");
else emitCalibStage1Ready();
printf("Running initCalib...\n");
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");
emitCalibError("Non-1 Port");
}
else {
else {
if (!servoBeginDownwardCalib())
emitCalibError("Direction Switch Failed");
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)
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: {
printf("Socket.IO Error!\n");
// Check WebSocket error details
servoCancelCalib();
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->error_handle.esp_ws_handshake_status_code == 401 ||
ws_event->error_handle.esp_ws_handshake_status_code == 403) {
printf("Authentication failed - invalid token\n");
}
if (ws_event) {
// 1. Check for TLS/SSL specific errors (Certificate issues)
if (ws_event->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) {
// 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;
statusResolved = true;
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() {
// Prepare the Authorization Header (Bearer format)
std::string authHeader = "Authorization: Bearer " + webToken + "\r\n";
@@ -259,8 +316,13 @@ void initSocketIO() {
connected = false;
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();
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);
tx_packet = esp_socketio_client_get_tx_packet(io_client);