CONNECTS TO WEBSOCKET!!

This commit is contained in:
2025-12-23 17:21:44 -06:00
parent c8f95463a5
commit 322f7f0699
13 changed files with 903 additions and 61 deletions

View File

@@ -2,6 +2,7 @@
#include "NimBLEDevice.h"
#include "WiFi.hpp"
#include "nvs_flash.h"
#include "socketIO.hpp"
#include "defines.h"
#include <mutex>
#include "bmHTTP.hpp"
@@ -46,7 +47,7 @@ NimBLEAdvertising* initBLE() {
// Create all characteristics with callbacks
MyCharCallbacks* charCallbacks = new MyCharCallbacks();
// 0x0000 - SSID List (READ + NOTIFY)
// 0x0000 - SSID List (READ)
ssidListChar = pService->createCharacteristic(
"0000",
NIMBLE_PROPERTY::READ
@@ -75,7 +76,7 @@ NimBLEAdvertising* initBLE() {
);
authConfirmChar.load()->createDescriptor("2902"); // Add BLE2902 descriptor for notifications
// 0x0004 - SSID Refresh (WRITE)
// 0x0004 - SSID Refresh
ssidRefreshChar = pService->createCharacteristic(
"0004",
NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY
@@ -119,6 +120,7 @@ void notifyAuthStatus(bool success) {
}
bool BLEtick(NimBLEAdvertising* pAdvertising) {
printf("BleTick\n");
if(flag_scan_requested) {
flag_scan_requested = false;
if (!scanBlock) {
@@ -229,6 +231,7 @@ bool BLEtick(NimBLEAdvertising* pAdvertising) {
void reset() {
esp_wifi_scan_stop();
if (!connected) esp_wifi_disconnect();
scanBlock = false;
flag_scan_requested = false;
credsGiven = false;

View File

@@ -10,6 +10,7 @@ esp_event_handler_instance_t WiFi::instance_any_id = NULL;
esp_event_handler_instance_t WiFi::instance_got_ip = NULL;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_STARTED_BIT BIT1
WiFi bmWiFi;
@@ -17,8 +18,13 @@ WiFi bmWiFi;
void WiFi::event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) {
// WiFi driver has finished initialization
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
printf("WiFi initialized and ready\n");
xEventGroupSetBits(s_wifi_event_group, WIFI_STARTED_BIT);
}
// We got disconnected -> Retry automatically
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
// 1. Cast the data to the correct struct
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
@@ -29,11 +35,9 @@ void WiFi::event_handler(void* arg, esp_event_base_t event_base,
case WIFI_REASON_AUTH_EXPIRE: // Reason 2
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: // Reason 15 (Most Common for Wrong Pass)
case WIFI_REASON_BEACON_TIMEOUT: // Reason 200
case WIFI_REASON_AUTH_FAIL: // Reason 203
case WIFI_REASON_ASSOC_FAIL: // Reason 204
case WIFI_REASON_HANDSHAKE_TIMEOUT: // Reason 205
case WIFI_REASON_AUTH_FAIL: // Reason 202
case WIFI_REASON_HANDSHAKE_TIMEOUT: // Reason 204
printf("ERROR: Likely Wrong Password!\n");
// OPTIONAL: Don't retry immediately if password is wrong
authFailed = true;
break;
@@ -41,10 +45,20 @@ void WiFi::event_handler(void* arg, esp_event_base_t event_base,
printf("ERROR: SSID Not Found\n");
authFailed = true;
break;
case WIFI_REASON_ASSOC_LEAVE: // Reason 8 - Manual disconnect
printf("Manual disconnect, not retrying\n");
break;
case WIFI_REASON_ASSOC_FAIL: // Reason 203 (Can be AP busy/rate limiting)
printf("Association failed, will retry...\n");
vTaskDelay(pdMS_TO_TICKS(1000)); // Wait 1 second before retry to avoid rate limiting
esp_wifi_connect();
break;
default:
printf("Retrying...\n");
esp_wifi_connect(); // Retry for other reasons (interference, etc)
esp_wifi_connect();
break;
}
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
@@ -95,6 +109,7 @@ void WiFi::init() {
));
ESP_ERROR_CHECK(esp_wifi_start());
xEventGroupWaitBits(s_wifi_event_group, WIFI_STARTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
}
// --- CHECK STATUS ---
@@ -162,11 +177,6 @@ bool WiFi::awaitConnected() {
uint8_t attempts = 0;
while (!isConnected() && attempts < 20) {
if (!isBLEClientConnected) {
printf("BLE Disconnected: Aborting WiFi connection attempt.\n");
esp_wifi_disconnect();
return false;
}
if (authFailed) {
printf("SSID/Password was wrong! Aborting connection attempt.\n");
return false;

View File

@@ -17,29 +17,47 @@ bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) {
std::string authHeader = "Bearer " + token;
esp_http_client_set_header(client, "Authorization", authHeader.c_str());
esp_err_t err = esp_http_client_perform(client);
// Open connection and fetch headers
esp_err_t err = esp_http_client_open(client, 0);
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);
int content_length = esp_http_client_get_content_length(client);
printf("HTTP Status = %d, content_length = %d\n", status_code, content_length);
if (status_code == 200) {
std::string responseData = "";
char buffer[512]; // Read in 512-byte blocks
int read_len;
// Read until the server stops sending (read_len <= 0)
while ((read_len = esp_http_client_read(client, buffer, sizeof(buffer))) > 0)
responseData.append(buffer, read_len);
if (!responseData.empty()) {
JSONresponse = cJSON_Parse(responseData.c_str());
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
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;
}
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");
}
}
esp_http_client_close(client);
} else printf("HTTP request failed: %s\n", esp_err_to_name(err));
esp_http_client_cleanup(client);

View File

@@ -3,9 +3,10 @@
#include "WiFi.hpp"
void initialSetup() {
printf("Entered Setup\n");
NimBLEAdvertising* pAdv = initBLE();
while (!BLEtick(pAdv)) {
vTaskDelay(pdMS_TO_TICKS(10));
vTaskDelay(pdMS_TO_TICKS(100));
}
}

119
include/socketIO.cpp Normal file
View File

@@ -0,0 +1,119 @@
#include "socketIO.hpp"
#include "esp_socketio_client.h"
#include "bmHTTP.hpp" // To access webToken
#include "WiFi.hpp"
#include "setup.hpp"
#include "cJSON.h"
static esp_socketio_client_handle_t io_client;
static esp_socketio_packet_handle_t tx_packet = NULL;
std::atomic<bool> statusResolved{false};
std::atomic<bool> connected{false};
// Event handler for Socket.IO events
static void socketio_event_handler(void *handler_args, esp_event_base_t base,
int32_t event_id, void *event_data) {
esp_socketio_event_data_t *data = (esp_socketio_event_data_t *)event_data;
esp_socketio_packet_handle_t packet = data->socketio_packet;
switch (event_id) {
case SOCKETIO_EVENT_OPENED:
printf("Socket.IO Received OPEN packet\n");
// Connect to default namespace "/"
esp_socketio_client_connect_nsp(data->client, NULL, NULL);
break;
case SOCKETIO_EVENT_NS_CONNECTED: {
printf("Socket.IO Connected to namespace!\n");
// Check if connected to default namespace
char *nsp = esp_socketio_packet_get_nsp(packet);
if (strcmp(nsp, "/") == 0) {
printf("Connected to default namespace\n");
}
connected = true;
statusResolved = true;
break;
}
case SOCKETIO_EVENT_DATA: {
printf("Received Socket.IO data\n");
// Parse the received packet
cJSON *json = esp_socketio_packet_get_json(packet);
if (json) {
char *json_str = cJSON_Print(json);
printf("Data: %s\n", json_str);
free(json_str);
}
break;
}
case SOCKETIO_EVENT_ERROR: {
printf("Socket.IO Error!\n");
// Check WebSocket error details
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");
}
}
// 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();
connected = false;
statusResolved = true;
break;
}
}
}
void initSocketIO() {
// Prepare the Authorization Header (Bearer format)
std::string authHeader = "Authorization: Bearer " + webToken + "\r\n";
statusResolved = false;
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.headers = authHeader.c_str();
io_client = esp_socketio_client_init(&config);
tx_packet = esp_socketio_client_get_tx_packet(io_client);
esp_socketio_register_events(io_client, SOCKETIO_EVENT_ANY, socketio_event_handler, NULL);
esp_socketio_client_start(io_client);
}
// 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 "/"
if (esp_socketio_packet_set_header(tx_packet, EIO_PACKET_TYPE_MESSAGE,
SIO_PACKET_TYPE_EVENT, NULL, -1) == ESP_OK) {
// Create JSON array with event name and data
cJSON *array = cJSON_CreateArray();
cJSON_AddItemToArray(array, cJSON_CreateString("calib_done"));
cJSON *data = cJSON_CreateObject();
cJSON_AddNumberToObject(data, "port", port);
cJSON_AddItemToArray(array, data);
// Set the JSON payload
esp_socketio_packet_set_json(tx_packet, array);
// Send the packet
esp_socketio_client_send_data(io_client, tx_packet);
// Reset packet for reuse
esp_socketio_packet_reset(tx_packet);
cJSON_Delete(array);
}
}

14
include/socketIO.hpp Normal file
View File

@@ -0,0 +1,14 @@
#ifndef SOCKETIO_HPP
#define SOCKETIO_HPP
#include <atomic>
extern std::atomic<bool> statusResolved;
extern std::atomic<bool> connected;
// Initialize Socket.IO client and connect to server
void initSocketIO();
// Emit calibration done event to server
void emitCalibDone(int port);
#endif // SOCKETIO_HPP