From 456e3dcfd34c16c3369c438f189c5100a51a683d Mon Sep 17 00:00:00 2001 From: pulipakaa24 Date: Wed, 24 Dec 2025 18:39:21 -0600 Subject: [PATCH] Delete/add_device cycle works smoothly now. All cases tested, next up is using position and calibration data to move motors and use encoders etc. --- include/BLE.cpp | 19 ++++++-- include/WiFi.hpp | 2 - include/setup.cpp | 95 +++++++++++++++++++++++++++++++++++++ include/setup.hpp | 1 + include/socketIO.cpp | 109 +++++++++++++++++++++++++++++++++++++++---- include/socketIO.hpp | 3 ++ src/main.cpp | 84 +++++---------------------------- 7 files changed, 224 insertions(+), 89 deletions(-) diff --git a/include/BLE.cpp b/include/BLE.cpp index b5b7d7d..713cf0e 100644 --- a/include/BLE.cpp +++ b/include/BLE.cpp @@ -12,6 +12,7 @@ std::atomic credsGiven{false}; std::atomic tokenGiven{false}; std::atomic isBLEClientConnected{false}; std::atomic scanBlock{false}; +std::atomic finalAuth{false}; std::mutex dataMutex; wifi_auth_mode_t auth; @@ -29,6 +30,8 @@ std::atomic tokenChar = nullptr; std::atomic ssidRefreshChar = nullptr; NimBLEAdvertising* initBLE() { + finalAuth = false; + NimBLEDevice::init("BlindMaster-C6"); // Optional: Boost power for better range (ESP32-C6 supports up to +20dBm) @@ -101,7 +104,6 @@ NimBLEAdvertising* initBLE() { pAdvertising->start(); printf("BLE Started. Waiting...\n"); - flag_scan_requested = true; return pAdvertising; } @@ -223,7 +225,9 @@ bool BLEtick(NimBLEAdvertising* pAdvertising) { } else printf("Failed to parse JSON response\n"); + finalAuth = true; notifyAuthStatus(success); + if (success) NimBLEDevice::deinit(true); // deinitialize BLE return success; } return false; @@ -231,7 +235,7 @@ bool BLEtick(NimBLEAdvertising* pAdvertising) { void reset() { esp_wifi_scan_stop(); - if (!connected) esp_wifi_disconnect(); + if (!finalAuth) esp_wifi_disconnect(); scanBlock = false; flag_scan_requested = false; credsGiven = false; @@ -260,8 +264,13 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI printf("onWrite called! UUID: %s, Value length: %d\n", uuidStr.c_str(), val.length()); + // Load atomic pointers for comparison + NimBLECharacteristic* currentCredsChar = credsChar.load(); + NimBLECharacteristic* currentTokenChar = tokenChar.load(); + NimBLECharacteristic* currentRefreshChar = ssidRefreshChar.load(); + // Check which characteristic was written to - if (pChar == credsChar) { + if (pChar == currentCredsChar) { // Credentials JSON characteristic if (val.length() > 0) { printf("Received JSON: %s\n", val.c_str()); @@ -315,7 +324,7 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI } } } - else if (pChar == tokenChar) { + else if (pChar == currentTokenChar) { if (val.length() > 0) { printf("Received Token: %s\n", val.c_str()); std::lock_guard lock(dataMutex); @@ -323,7 +332,7 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI tokenGiven = true; } } - else if (pChar == ssidRefreshChar) { + else if (pChar == currentRefreshChar) { if (val == "Start") { // Refresh characteristic printf("Refresh Requested\n"); diff --git a/include/WiFi.hpp b/include/WiFi.hpp index e6c1705..77bde73 100644 --- a/include/WiFi.hpp +++ b/include/WiFi.hpp @@ -29,6 +29,4 @@ class WiFi { extern WiFi bmWiFi; -void scanAndUpdateSSIDList(); - #endif \ No newline at end of file diff --git a/include/setup.cpp b/include/setup.cpp index 3f0cc32..dc52fb4 100644 --- a/include/setup.cpp +++ b/include/setup.cpp @@ -1,6 +1,10 @@ #include "setup.hpp" #include "BLE.hpp" #include "WiFi.hpp" +#include "nvs_flash.h" +#include "defines.h" +#include "bmHTTP.hpp" +#include "socketIO.hpp" void initialSetup() { printf("Entered Setup\n"); @@ -9,4 +13,95 @@ void initialSetup() { while (!BLEtick(pAdv)) { vTaskDelay(pdMS_TO_TICKS(100)); } +} + +void setupLoop() { + bool initSuccess = false; + while(!initSuccess) { + nvs_handle_t WiFiHandle; + if (nvs_open(nvsWiFi, NVS_READONLY, &WiFiHandle) == ESP_OK) { + size_t ssidSize; + esp_err_t WiFiPrefsError = nvs_get_str(WiFiHandle, ssidTag, NULL, &ssidSize); + size_t pwSize; + WiFiPrefsError |= nvs_get_str(WiFiHandle, passTag, NULL, &pwSize); + uint8_t authMode; + WiFiPrefsError |= nvs_get_u8(WiFiHandle, authTag, &authMode); + printf("World\n"); + if (WiFiPrefsError == ESP_ERR_NVS_NOT_FOUND) { + printf("Didn't find creds\n"); + // Make the RGB LED a certain color (Blue?) + nvs_close(WiFiHandle); + initialSetup(); + } else if (WiFiPrefsError == ESP_OK) { + char ssid[ssidSize]; + nvs_get_str(WiFiHandle, ssidTag, ssid, &ssidSize); + char pw[pwSize]; + nvs_get_str(WiFiHandle, passTag, pw, &pwSize); + nvs_close(WiFiHandle); + if (!bmWiFi.attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) { + // Make RGB LED certain color (Blue?) + printf("Found credentials, failed to connect.\n"); + initialSetup(); + } + else { + printf("Connected to WiFi from NVS credentials\n"); + nvs_handle_t authHandle; + if (nvs_open(nvsAuth, NVS_READONLY, &authHandle) == ESP_OK) { + size_t tokenSize; + if (nvs_get_str(authHandle, tokenTag, NULL, &tokenSize) == ESP_OK) { + char token[tokenSize]; + nvs_get_str(authHandle, tokenTag, token, &tokenSize); + nvs_close(authHandle); + + // Use permanent device token to connect to Socket.IO + // The server will verify the token during connection handshake + webToken = std::string(token); + printf("Connecting to Socket.IO server with saved token...\n"); + statusResolved = false; + initSocketIO(); + + // Wait for device_init message from server with timeout + int timeout_count = 0; + const int MAX_TIMEOUT = 60; // 10 seconds (20 * 500ms) + while (!statusResolved && timeout_count < MAX_TIMEOUT) { + printf("Waiting for device_init message... (%d/%d)\n", timeout_count, MAX_TIMEOUT); + vTaskDelay(pdMS_TO_TICKS(500)); + timeout_count++; + } + + if (timeout_count >= MAX_TIMEOUT) { + printf("Timeout waiting for device_init - connection failed\n"); + stopSocketIO(); + initSuccess = false; + initialSetup(); + } else { + initSuccess = connected; + if (!initSuccess) { + printf("Device authentication failed - entering setup\n"); + initialSetup(); + } + } + } + else { + printf("Token read unsuccessful, entering setup.\n"); + initialSetup(); + } + } + else { + printf("Auth NVS segment doesn't exist, entering setup.\n"); + initialSetup(); + } + } + } else { + // Make RGB LED certain color (Blue?) + nvs_close(WiFiHandle); + printf("Program error in Wifi Connection\n"); + initialSetup(); + } + } + else { + printf("WiFi NVS segment doesn't exist, entering setup.\n"); + initialSetup(); + } + } } \ No newline at end of file diff --git a/include/setup.hpp b/include/setup.hpp index 847a91d..4e5ae4c 100644 --- a/include/setup.hpp +++ b/include/setup.hpp @@ -2,5 +2,6 @@ #define SETUP_H void initialSetup(); +void setupLoop(); #endif \ No newline at end of file diff --git a/include/socketIO.cpp b/include/socketIO.cpp index 4603570..11e0db3 100644 --- a/include/socketIO.cpp +++ b/include/socketIO.cpp @@ -8,7 +8,7 @@ static esp_socketio_client_handle_t io_client; static esp_socketio_packet_handle_t tx_packet = NULL; -std::atomic statusResolved{false}; +std::atomic statusResolved{true}; std::atomic connected{false}; // Event handler for Socket.IO events @@ -29,10 +29,9 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, // Check if connected to default namespace char *nsp = esp_socketio_packet_get_nsp(packet); if (strcmp(nsp, "/") == 0) { - printf("Connected to default namespace\n"); + printf("Connected to default namespace - waiting for device_init...\n"); } - connected = true; - statusResolved = true; + // Don't set connected yet - wait for device_init message from server break; } @@ -43,6 +42,82 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, if (json) { char *json_str = cJSON_Print(json); printf("Data: %s\n", json_str); + + // Check if this is an array event + if (cJSON_IsArray(json) && cJSON_GetArraySize(json) >= 2) { + cJSON *eventName = cJSON_GetArrayItem(json, 0); + + if (cJSON_IsString(eventName)) { + // Handle error event + if (strcmp(eventName->valuestring, "error") == 0) { + printf("Received error message from server\n"); + cJSON *data = cJSON_GetArrayItem(json, 1); + + if (data) { + cJSON *message = cJSON_GetObjectItem(data, "message"); + if (message && cJSON_IsString(message)) { + printf("Server error: %s\n", message->valuestring); + } + } + + // Mark connection as failed + connected = false; + statusResolved = true; + } + // Handle device_init event + else if (strcmp(eventName->valuestring, "device_init") == 0) { + printf("Received device_init message\n"); + cJSON *data = cJSON_GetArrayItem(json, 1); + + if (data) { + cJSON *type = cJSON_GetObjectItem(data, "type"); + if (type && strcmp(type->valuestring, "success") == 0) { + printf("Device authenticated successfully\n"); + + // Parse device state + cJSON *deviceState = cJSON_GetObjectItem(data, "deviceState"); + if (cJSON_IsArray(deviceState)) { + int stateCount = cJSON_GetArraySize(deviceState); + printf("Device has %d peripheral(s):\n", stateCount); + + for (int i = 0; i < stateCount; i++) { + cJSON *periph = cJSON_GetArrayItem(deviceState, i); + int port = cJSON_GetObjectItem(periph, "port")->valueint; + int lastPos = cJSON_GetObjectItem(periph, "lastPos")->valueint; + bool awaitCalib = cJSON_IsTrue(cJSON_GetObjectItem(periph, "awaitCalib")); + bool calibrated = cJSON_IsTrue(cJSON_GetObjectItem(periph, "calibrated")); + // TODO: UPDATE MOTOR/ENCODER STATES BASED ON THIS, as well as the successive websocket updates. + printf(" Port %d: pos=%d, calibrated=%d, awaitCalib=%d\n", + port, lastPos, calibrated, awaitCalib); + } + } + + // Now mark as connected + connected = true; + statusResolved = true; + } else { + printf("Device authentication failed\n"); + connected = false; + statusResolved = true; + } + } + } + // Handle device_deleted event + else if (strcmp(eventName->valuestring, "device_deleted") == 0) { + printf("Device has been deleted from account - disconnecting\n"); + cJSON *data = cJSON_GetArrayItem(json, 1); + if (data) { + cJSON *message = cJSON_GetObjectItem(data, "message"); + if (message && cJSON_IsString(message)) { + printf("Server message: %s\n", message->valuestring); + } + } + connected = false; + statusResolved = true; + } + } + } + free(json_str); } break; @@ -61,17 +136,19 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, } } - // Disconnect and enter setup mode - printf("Disconnecting and entering setup mode...\n"); - esp_socketio_client_close(io_client, pdMS_TO_TICKS(1000)); - - esp_socketio_client_destroy(io_client); - initialSetup(); + // Set flags to indicate connection failure connected = false; statusResolved = true; break; } } + + // Handle WebSocket-level disconnections + if (data->websocket_event_id == WEBSOCKET_EVENT_DISCONNECTED) { + printf("WebSocket disconnected\n"); + connected = false; + statusResolved = true; + } } void initSocketIO() { @@ -92,6 +169,18 @@ void initSocketIO() { esp_socketio_client_start(io_client); } +void stopSocketIO() { + if (io_client != NULL) { + printf("Stopping Socket.IO client...\n"); + esp_socketio_client_close(io_client, pdMS_TO_TICKS(1000)); + esp_socketio_client_destroy(io_client); + io_client = NULL; + tx_packet = NULL; + connected = false; + statusResolved = false; + } +} + // Function to emit 'calib_done' as expected by your server void emitCalibDone(int port) { // Set packet header: EIO MESSAGE type, SIO EVENT type, default namespace "/" diff --git a/include/socketIO.hpp b/include/socketIO.hpp index 31a3408..de144f0 100644 --- a/include/socketIO.hpp +++ b/include/socketIO.hpp @@ -8,6 +8,9 @@ extern std::atomic connected; // Initialize Socket.IO client and connect to server void initSocketIO(); +// Stop and destroy Socket.IO client +void stopSocketIO(); + // Emit calibration done event to server void emitCalibDone(int port); diff --git a/src/main.cpp b/src/main.cpp index a515954..e421538 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,12 +3,9 @@ #include "defines.h" #include "nvs_flash.h" #include "NimBLEDevice.h" -#include "BLE.hpp" #include "WiFi.hpp" #include "setup.hpp" -#include "bmHTTP.hpp" #include "socketIO.hpp" -#include "cJSON.h" extern "C" void app_main() { printf("Hello "); @@ -22,80 +19,23 @@ extern "C" void app_main() { bmWiFi.init(); - bool initSuccess = false; - - while(!initSuccess) { - nvs_handle_t WiFiHandle; - if (nvs_open(nvsWiFi, NVS_READONLY, &WiFiHandle) == ESP_OK) { - size_t ssidSize; - esp_err_t WiFiPrefsError = nvs_get_str(WiFiHandle, ssidTag, NULL, &ssidSize); - size_t pwSize; - WiFiPrefsError |= nvs_get_str(WiFiHandle, passTag, NULL, &pwSize); - uint8_t authMode; - WiFiPrefsError |= nvs_get_u8(WiFiHandle, authTag, &authMode); - printf("World\n"); - if (WiFiPrefsError == ESP_ERR_NVS_NOT_FOUND) { - printf("Didn't find creds\n"); - // Make the RGB LED a certain color (Blue?) - nvs_close(WiFiHandle); - initialSetup(); - } else if (WiFiPrefsError == ESP_OK) { - char ssid[ssidSize]; - nvs_get_str(WiFiHandle, ssidTag, ssid, &ssidSize); - char pw[pwSize]; - nvs_get_str(WiFiHandle, passTag, pw, &pwSize); - nvs_close(WiFiHandle); - if (!bmWiFi.attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) { - // Make RGB LED certain color (Blue?) - printf("Found credentials, failed to connect.\n"); - initialSetup(); - } - else { - printf("Connected to WiFi from NVS credentials\n"); - nvs_handle_t authHandle; - if (nvs_open(nvsAuth, NVS_READONLY, &authHandle) == ESP_OK) { - size_t tokenSize; - if (nvs_get_str(authHandle, tokenTag, NULL, &tokenSize) == ESP_OK) { - char token[tokenSize]; - nvs_get_str(authHandle, tokenTag, token, &tokenSize); - nvs_close(authHandle); - - // Use permanent device token to connect to Socket.IO - // The server will verify the token during connection handshake - webToken = std::string(token); - printf("Connecting to Socket.IO server with saved token...\n"); - initSocketIO(); - while (!statusResolved) vTaskDelay(pdMS_TO_TICKS(100)); - initSuccess = connected; - } - else { - printf("Token read unsuccessful, entering setup.\n"); - initialSetup(); - } - } - else { - printf("Auth NVS segment doesn't exist, entering setup.\n"); - initialSetup(); - } - } - } else { - // Make RGB LED certain color (Blue?) - nvs_close(WiFiHandle); - printf("Program error in Wifi Connection\n"); - initialSetup(); - } - } - else { - printf("WiFi NVS segment doesn't exist, entering setup.\n"); - initialSetup(); - } - } + setupLoop(); + statusResolved = false; // Main loop while (1) { + if (statusResolved) { + if (!connected) { + printf("Disconnected! Beginning setup loop.\n"); + stopSocketIO(); + setupLoop(); + } + else printf("Reconnected!\n"); + statusResolved = false; + } // Your main application logic here vTaskDelay(pdMS_TO_TICKS(1000)); - printf("Main Loop\n"); + printf("loop\n"); } } \ No newline at end of file