CONNECTS TO WEBSOCKET!!
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -4,4 +4,7 @@
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
||||
managed_components/
|
||||
compile_commands.json
|
||||
@@ -1,8 +1,34 @@
|
||||
dependencies:
|
||||
bubblesnake/esp_socketio_client:
|
||||
component_hash: 6f9d397a583384ca80779af0b2861b8cee99509a308f8b3f25524d8f4ba8f8f9
|
||||
dependencies:
|
||||
- name: espressif/esp_websocket_client
|
||||
registry_url: https://components.espressif.com
|
||||
require: public
|
||||
version: '>=1.2.3'
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>=5.0'
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 1.0.0
|
||||
espressif/esp_websocket_client:
|
||||
component_hash: 723aba370113196c66321442426cd6452c351eef31c85c83bd1446831ef9f8f4
|
||||
dependencies:
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>=5.0'
|
||||
source:
|
||||
registry_url: https://components.espressif.com
|
||||
type: service
|
||||
version: 1.6.0
|
||||
idf:
|
||||
source:
|
||||
type: idf
|
||||
version: 5.5.1
|
||||
manifest_hash: 24b4d087511378b31aec46ab95615da067c81c6477aaa4515b222e977e29004a
|
||||
direct_dependencies:
|
||||
- bubblesnake/esp_socketio_client
|
||||
manifest_hash: d73c96c5d6ddd24707089a2953e50f36a12ebbc66b5458ada3d4f55c0987ccf1
|
||||
target: esp32c6
|
||||
version: 2.0.0
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
119
include/socketIO.cpp
Normal 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
14
include/socketIO.hpp
Normal 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
|
||||
599
index.js
Normal file
599
index.js
Normal file
@@ -0,0 +1,599 @@
|
||||
const { verify, hash } = require('argon2');
|
||||
const express = require('express');
|
||||
const { json } = require('express');
|
||||
const { Pool } = require('pg');
|
||||
require('dotenv').config();
|
||||
const jwt = require('jsonwebtoken');
|
||||
const http = require('http');
|
||||
const socketIo = require('socket.io');
|
||||
const connectDB = require('./db'); // Your Mongoose DB connection
|
||||
const { initializeAgenda } = require('./agenda'); // Agenda setup
|
||||
const format = require('pg-format');
|
||||
const cronParser = require('cron-parser');
|
||||
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
app.use(json());
|
||||
const pool = new Pool();
|
||||
const server = http.createServer(app);
|
||||
const io = socketIo(server, {
|
||||
pingInterval: 15000,
|
||||
pingTimeout: 10000,
|
||||
});
|
||||
|
||||
let agenda;
|
||||
|
||||
(async () => {
|
||||
// 1. Connect to MongoDB (for your application data)
|
||||
await connectDB();
|
||||
|
||||
agenda = await initializeAgenda('mongodb://localhost:27017/myScheduledApp', pool, io);
|
||||
})();
|
||||
|
||||
(async () => {
|
||||
await pool.query("update user_tokens set connected=FALSE where connected=TRUE");
|
||||
await pool.query("update device_tokens set connected=FALSE where connected=TRUE");
|
||||
})();
|
||||
const JWT_SECRET = process.env.JWT_SECRET;
|
||||
const TOKEN_EXPIRY = '5d';
|
||||
|
||||
io.on('connection', async (socket) => {
|
||||
console.log("periph connected");
|
||||
const token = socket.handshake.auth.token ?? socket.handshake.headers['authorization']?.split(' ')[1];
|
||||
try {
|
||||
if (!token) throw new Error("no token!");
|
||||
const payload = jwt.verify(token, JWT_SECRET);
|
||||
let table;
|
||||
let idCol;
|
||||
let id;
|
||||
|
||||
if (payload.type === "user") {
|
||||
table = "user_tokens";
|
||||
idCol = "user_id";
|
||||
socket.user = true;
|
||||
id = payload.userId;
|
||||
}
|
||||
else if (payload.type === "peripheral") {
|
||||
table = "device_tokens";
|
||||
idCol = "device_id";
|
||||
socket.user = false;
|
||||
id = payload.peripheralId;
|
||||
}
|
||||
else {
|
||||
throw new Error("Unauthorized");
|
||||
}
|
||||
|
||||
const query = format(`update %I set connected=TRUE, socket=$1 where %I=$2 and token=$3 and connected=FALSE`,
|
||||
table, idCol
|
||||
);
|
||||
|
||||
const result = await pool.query(query, [socket.id, id, token]);
|
||||
|
||||
if (result.rowCount != 1) {
|
||||
const errorResponse = {
|
||||
type: 'error',
|
||||
code: 404,
|
||||
message: 'Device not found or already connected'
|
||||
};
|
||||
socket.emit("error", errorResponse);
|
||||
socket.disconnect(true);
|
||||
}
|
||||
|
||||
else {
|
||||
const successResponse = {
|
||||
type: 'success',
|
||||
code: 200,
|
||||
message: 'Device found'
|
||||
};
|
||||
console.log("success");
|
||||
socket.emit("success", successResponse);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error during periph authentication:', error);
|
||||
|
||||
// Send an error message to the client
|
||||
socket.emit('error', { type: 'error', code: 500 });
|
||||
|
||||
// Disconnect the client
|
||||
socket.disconnect(true);
|
||||
}
|
||||
|
||||
socket.on('calib_done', async (data) => {
|
||||
console.log(`Received 'calib_done' event from client ${socket.id}:`);
|
||||
console.log(data);
|
||||
try {
|
||||
const {rows} = await pool.query("select device_id from device_tokens where socket=$1 and connected=TRUE", [socket.id]);
|
||||
if (rows.length != 1) throw new Error("No device with that ID connected to Socket.");
|
||||
const result = await pool.query("update peripherals set await_calib=FALSE, calibrated=TRUE where device_id=$1 and peripheral_number=$2 returning id, user_id",
|
||||
[rows[0].device_id, data.port]
|
||||
);
|
||||
if (result.rowCount != 1) throw new Error("No such peripheral in database");
|
||||
|
||||
const {rows: userRows} = await pool.query("select socket from user_tokens where user_id=$1", [result.rows[0].user_id]);
|
||||
if (userRows.length == 1) {
|
||||
if (userRows[0]){
|
||||
const userSocket = userRows[0].socket;
|
||||
io.to(userSocket).emit("calib_done", {periphID: result.rows[0].id});
|
||||
}
|
||||
}
|
||||
else console.log("No App connected");
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error processing job:`, error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('pos_hit', async (data) => {
|
||||
console.log(`Received 'pos_hit' event from client ${socket.id}:`);
|
||||
console.log(data);
|
||||
const dateTime = new Date();
|
||||
try {
|
||||
const {rows} = await pool.query("select device_id from device_tokens where socket=$1 and connected=TRUE", [socket.id]);
|
||||
if (rows.length != 1) throw new Error("No device with that ID connected to Socket.");
|
||||
const result = await pool.query("update peripherals set last_pos=$1, last_set=$2 where device_id=$3 and peripheral_number=$4 returning id, user_id",
|
||||
[data.pos, dateTime, rows[0].device_id, data.port]
|
||||
);
|
||||
if (result.rowCount != 1) throw new Error("No such peripheral in database");
|
||||
|
||||
const {rows: userRows} = await pool.query("select socket from user_tokens where user_id=$1", [result.rows[0].user_id]);
|
||||
if (userRows.length == 1) {
|
||||
if (userRows[0]){
|
||||
const userSocket = userRows[0].socket;
|
||||
io.to(userSocket).emit("pos_hit", {periphID: result.rows[0].id});
|
||||
}
|
||||
}
|
||||
else console.log("No App connected");
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error processing job:`, error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("disconnect", async () => {
|
||||
if (socket.user) {
|
||||
console.log("user disconnect");
|
||||
await pool.query("update user_tokens set connected=FALSE where socket=$1", [socket.id]);
|
||||
}
|
||||
else {
|
||||
console.log("device disconnect");
|
||||
await pool.query("update device_tokens set connected=FALSE where socket=$1", [socket.id]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
async function createToken(userId) {
|
||||
const token = jwt.sign({ type: 'user', userId }, JWT_SECRET, { expiresIn: TOKEN_EXPIRY });
|
||||
await pool.query("delete from user_tokens where user_id=$1", [userId]);
|
||||
await pool.query("insert into user_tokens (user_id, token) values ($1, $2)", [userId, token]);
|
||||
return token;
|
||||
}
|
||||
|
||||
async function createPeripheralToken(peripheralId) {
|
||||
const token = jwt.sign({ type: 'peripheral', peripheralId }, JWT_SECRET);
|
||||
await pool.query("insert into device_tokens (device_id, token) values ($1, $2)", [peripheralId, token]);
|
||||
return token;
|
||||
}
|
||||
|
||||
async function createTempPeriphToken(peripheralId) {
|
||||
const token = jwt.sign({type: 'peripheral', peripheralId}, JWT_SECRET, {expiresIn: '2m'} );
|
||||
await pool.query("insert into device_tokens (device_id, token) values ($1, $2)", [peripheralId, token]);
|
||||
return token;
|
||||
}
|
||||
|
||||
async function authenticateToken(req, res, next) {
|
||||
const authHeader = req.headers['authorization'];
|
||||
const token = authHeader?.split(' ')[1];
|
||||
|
||||
if (!token) return res.sendStatus(401);
|
||||
|
||||
try {
|
||||
const payload = jwt.verify(token, JWT_SECRET);
|
||||
if (payload.type === 'user') {
|
||||
const {rows} = await pool.query("select user_id from user_tokens where token=$1", [token]);
|
||||
if (rows.length != 1) throw new Error("Invalid/Expired Token");
|
||||
req.user = payload.userId; // make Id accessible in route handlers
|
||||
}
|
||||
else if (payload.type === 'peripheral'){
|
||||
const {rows} = await pool.query("select device_id from device_tokens where token=$1", [token]);
|
||||
if (rows.length != 1) throw new Error("Invalid/Expired Token");
|
||||
req.peripheral = payload.peripheralId;
|
||||
}
|
||||
else {
|
||||
throw new Error("Invalid/Expired Token");
|
||||
}
|
||||
next();
|
||||
} catch {
|
||||
return res.sendStatus(403); // invalid/expired token
|
||||
}
|
||||
}
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.send('Hello World!');
|
||||
});
|
||||
|
||||
app.post('/login', async (req, res) => {
|
||||
const { email, password } = req.body;
|
||||
console.log('login');
|
||||
if (!email || !password) return res.status(400).json({error: 'email and password required'});
|
||||
try {
|
||||
const {rows} = await pool.query('select id, password_hash_string from users where email = $1', [email]);
|
||||
if (rows.length === 0) return res.status(401).json({error: 'Invalid Credentials'});
|
||||
const user = rows[0]
|
||||
console.log('user found');
|
||||
const verified = await verify(user.password_hash_string, password);
|
||||
|
||||
if (!verified) return res.status(401).json({ error: 'Invalid credentials' });
|
||||
console.log("password correct");
|
||||
const token = await createToken(user.id); // token is now tied to ID
|
||||
|
||||
res.status(200).json({token});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/create_user', async (req, res) => {
|
||||
console.log("got post req");
|
||||
const {name, email, password} = req.body
|
||||
try {
|
||||
|
||||
const hashedPass = await hash(password);
|
||||
|
||||
await pool.query("insert into users (name, email, password_hash_string) values (nullif($1, ''), $2, $3)",
|
||||
[name, email, hashedPass]
|
||||
);
|
||||
return res.sendStatus(201);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err.code === '23505') {
|
||||
return res.status(409).json({ error: 'Email already in use' });
|
||||
}
|
||||
return res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/verify', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
// Issue a new token to extend session
|
||||
const newToken = await createToken(req.user);
|
||||
res.status(200).json({token: newToken});
|
||||
} catch {
|
||||
res.status(500).json({ error: 'server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/device_list', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
console.log("device List request");
|
||||
console.log(req.user);
|
||||
const {rows} = await pool.query('select id, device_name from devices where user_id = $1', [req.user]);
|
||||
const deviceNames = rows.map(row => row.device_name);
|
||||
const deviceIds = rows.map(row => row.id);
|
||||
res.status(200).json({ device_ids: deviceIds, devices: deviceNames });
|
||||
} catch {
|
||||
res.status(500).json({error: 'Internal Server Error'});
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/device_name', authenticateToken, async (req, res) => {
|
||||
console.log("deviceName");
|
||||
try {
|
||||
const {deviceId} = req.query;
|
||||
const {rows} = await pool.query('select device_name from devices where id=$1 and user_id=$2',
|
||||
[deviceId, req.user]);
|
||||
if (rows.length != 1) return res.sendStatus(404);
|
||||
const deviceName = rows[0].device_name;
|
||||
res.status(200).json({device_name: deviceName});
|
||||
} catch {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/peripheral_list', authenticateToken, async (req, res) => {
|
||||
console.log("periph list")
|
||||
try {
|
||||
const {deviceId} = req.query;
|
||||
const {rows} = await pool.query('select id, peripheral_number, peripheral_name from peripherals where device_id=$1 and user_id=$2',
|
||||
[deviceId, req.user]);
|
||||
const peripheralIds = rows.map(row => row.id);
|
||||
const portNums = rows.map(row => row.peripheral_number);
|
||||
const peripheralNames = rows.map(row => row.peripheral_name);
|
||||
res.status(200).json({peripheral_ids: peripheralIds, port_nums: portNums, peripheral_names: peripheralNames});
|
||||
} catch {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/add_device', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
console.log("add device request");
|
||||
console.log(req.user);
|
||||
console.log(req.peripheral);
|
||||
const {deviceName} = req.body;
|
||||
console.log(deviceName);
|
||||
const {rows} = await pool.query("insert into devices (user_id, device_name) values ($1, $2) returning id",
|
||||
[req.user, deviceName]
|
||||
); // finish token return based on device ID.
|
||||
const deviceInitToken = await createTempPeriphToken(rows[0].id);
|
||||
res.status(201).json({token: deviceInitToken});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
if (err.code == '23505') {
|
||||
return res.status(409).json({ error: 'Device Name in use' });
|
||||
}
|
||||
res.status(500).json({error: 'Internal Server Error'});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/add_peripheral', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const {device_id, port_num, peripheral_name} = req.body;
|
||||
await pool.query("insert into peripherals (device_id, peripheral_number, peripheral_name, user_id) values ($1, $2, $3, $4)",
|
||||
[device_id, port_num, peripheral_name, req.user]
|
||||
);
|
||||
res.sendStatus(201);
|
||||
} catch (err){
|
||||
if (err.code == '23505') return res.sendStatus(409);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/verify_device', authenticateToken, async (req, res) => {
|
||||
console.log("device verify");
|
||||
try{
|
||||
console.log(req.peripheral);
|
||||
await pool.query("delete from device_tokens where device_id=$1", [req.peripheral]);
|
||||
const newToken = await createPeripheralToken(req.peripheral);
|
||||
console.log("New Token", newToken);
|
||||
res.json({token: newToken, id: req.peripheral});
|
||||
} catch {
|
||||
res.status(500).json({error: "server error"});
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/position', authenticateToken, async (req, res) => {
|
||||
console.log("devicepos");
|
||||
try {
|
||||
const {rows} = await pool.query("select last_pos, peripheral_number, await_calib from peripherals where device_id=$1",
|
||||
[req.peripheral]);
|
||||
|
||||
if (rows.length == 0) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
|
||||
res.status(200).json(rows);
|
||||
} catch {
|
||||
res.status(500).json({error: "server error"});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/manual_position_update', authenticateToken, async (req, res) => {
|
||||
console.log("setpos");
|
||||
try {
|
||||
const {periphId, periphNum, deviceId, newPos} = req.body;
|
||||
const changedPosList = [{periphNum: periphNum, periphID: periphId, pos: newPos}];
|
||||
|
||||
// Schedule the job to run immediately
|
||||
const job = await agenda.now('posChange', {deviceID: deviceId, changedPosList: changedPosList, userID: req.user});
|
||||
|
||||
res.status(202).json({ // 202 Accepted, as processing happens in background
|
||||
success: true,
|
||||
message: 'Request accepted for immediate processing.',
|
||||
jobId: job.attrs._id
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error triggering immediate action:', error);
|
||||
res.status(500).json({ success: false, message: 'Failed to trigger immediate action', error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/calib', authenticateToken, async (req, res) => {
|
||||
console.log("calibrate");
|
||||
try {
|
||||
const {periphId} = req.body;
|
||||
// Schedule the job to run immediately
|
||||
const job = await agenda.now('calib', {periphID: periphId, userID: req.user});
|
||||
|
||||
res.status(202).json({ // 202 Accepted, as processing happens in background
|
||||
success: true,
|
||||
message: 'Request accepted for immediate processing.',
|
||||
jobId: job.attrs._id
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Error triggering immediate action:', err);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/cancel_calib', authenticateToken, async (req, res) => {
|
||||
console.log("cancelCalib");
|
||||
try {
|
||||
const {periphId} = req.body;
|
||||
const job = await agenda.now('cancel_calib', {periphID: periphId, userID: req.user});
|
||||
|
||||
res.status(202).json({ // 202 Accepted, as processing happens in background
|
||||
success: true,
|
||||
message: 'Request accepted for immediate processing.',
|
||||
jobId: job.attrs._id
|
||||
});
|
||||
} catch {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/peripheral_status', authenticateToken, async (req, res) => {
|
||||
console.log("status");
|
||||
try {
|
||||
const {periphId} = req.query;
|
||||
const {rows} = await pool.query("select last_pos, last_set, calibrated, await_calib from peripherals where id=$1 and user_id=$2",
|
||||
[periphId, req.user]
|
||||
);
|
||||
if (rows.length != 1) return res.sendStatus(404);
|
||||
res.status(200).json({last_pos: rows[0].last_pos, last_set: rows[0].last_set,
|
||||
calibrated: rows[0].calibrated, await_calib: rows[0].await_calib});
|
||||
} catch {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/peripheral_name', authenticateToken, async (req, res) => {
|
||||
console.log("urmom");
|
||||
try {
|
||||
const {periphId} = req.query;
|
||||
const {rows} = await pool.query("select peripheral_name from peripherals where id=$1 and user_id=$2",
|
||||
[periphId, req.user]
|
||||
);
|
||||
if (rows.length != 1) return res.sendStatus(404);
|
||||
res.status(200).json({name: rows[0].peripheral_name});
|
||||
} catch {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/completed_calib', authenticateToken, async (req, res) => {
|
||||
console.log("calibration complete");
|
||||
try {
|
||||
const {portNum} = req.body;
|
||||
const result = await pool.query("update peripherals set calibrated=true, await_calib=false where device_id=$1 and peripheral_number=$2",
|
||||
[req.peripheral, portNum]
|
||||
);
|
||||
if (result.rowCount === 0) return res.sendStatus(404);
|
||||
res.sendStatus(204);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/rename_device', authenticateToken, async (req, res) => {
|
||||
console.log("Hub rename");
|
||||
try {
|
||||
const {deviceId, newName} = req.body;
|
||||
const result = await pool.query("update devices set device_name=$1 where id=$2 and user_id=$3", [newName, deviceId, req.user]);
|
||||
if (result.rowCount === 0) return res.sendStatus(404);
|
||||
res.sendStatus(204);
|
||||
} catch (err) {
|
||||
if (err.code == '23505') return res.sendStatus(409);
|
||||
console.error(err);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/rename_peripheral', authenticateToken, async (req, res) => {
|
||||
console.log("Hub rename");
|
||||
try {
|
||||
const {periphId, newName} = req.body;
|
||||
const result = await pool.query("update peripherals set peripheral_name=$1 where id=$2 and user_id=$3", [newName, periphId, req.user]);
|
||||
if (result.rowCount === 0) return res.sendStatus(404);
|
||||
res.sendStatus(204);
|
||||
} catch (err) {
|
||||
if (err.code == '23505') return res.sendStatus(409);
|
||||
console.error(err);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/delete_device', authenticateToken, async (req, res) => {
|
||||
console.log("delete device");
|
||||
try {
|
||||
const {deviceId} = req.body;
|
||||
const {rows} = await pool.query("delete from devices where user_id=$1 and id=$2 returning id",
|
||||
[req.user, deviceId]
|
||||
);
|
||||
if (rows.length != 1) {
|
||||
return res.status(404).json({ error: 'Device not found' });
|
||||
}
|
||||
|
||||
await pool.query("delete from device_tokens where device_id=$1", [rows[0].id]);
|
||||
|
||||
res.sendStatus(204);
|
||||
} catch {
|
||||
res.status(500).json({error: "server error"});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/delete_peripheral', authenticateToken, async (req, res) => {
|
||||
console.log("delete peripheral");
|
||||
try {
|
||||
const {periphId} = req.body;
|
||||
const {rows} = await pool.query("delete from peripherals where user_id = $1 and id=$2 returning id",
|
||||
[req.user, periphId]
|
||||
);
|
||||
if (rows.length != 1) {
|
||||
return res.status(404).json({ error: 'Device not found' });
|
||||
}
|
||||
res.sendStatus(204);
|
||||
} catch {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
})
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`Example app listening at http://localhost:${port}`);
|
||||
});
|
||||
|
||||
app.post('/periph_schedule_list', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
console.log("Schedule List request for user:", req.user);
|
||||
const { periphId } = req.body;
|
||||
|
||||
if (!periphId) {
|
||||
return res.status(400).json({ error: 'periphId is required in the request body.' });
|
||||
}
|
||||
|
||||
// FIX 1: Assign the returned array directly to a variable (e.g., 'jobs')
|
||||
const jobs = await agenda.jobs({
|
||||
'name': 'posChangeScheduled',
|
||||
'data.changedPosList': { $size: 1 },
|
||||
'data.changedPosList.0.periphID': periphId,
|
||||
'data.userID': req.user
|
||||
});
|
||||
|
||||
// FIX 2: Use .filter() and .map() to handle all cases cleanly.
|
||||
// This creates a cleaner, more predictable transformation pipeline.
|
||||
const details = jobs
|
||||
// Step 1: Filter out any jobs that are not recurring.
|
||||
.filter(job => job.attrs.repeatInterval)
|
||||
// Step 2: Map the remaining recurring jobs to our desired format.
|
||||
.map(job => {
|
||||
const { repeatInterval, data, repeatTimezone } = job.attrs;
|
||||
try {
|
||||
const interval = cronParser.parseExpression(repeatInterval, {
|
||||
tz: repeatTimezone || undefined
|
||||
});
|
||||
const fields = interval.fields;
|
||||
|
||||
// Make sure to declare the variable
|
||||
const parsedSchedule = {
|
||||
minutes: fields.minute,
|
||||
hours: fields.hour,
|
||||
daysOfMonth: fields.dayOfMonth,
|
||||
months: fields.month,
|
||||
daysOfWeek: fields.dayOfWeek,
|
||||
};
|
||||
|
||||
return {
|
||||
id: job.attrs._id, // It's good practice to return the job ID
|
||||
schedule: parsedSchedule,
|
||||
pos: data.changedPosList[0].pos
|
||||
};
|
||||
} catch (err) {
|
||||
// If parsing fails for a specific job, log it and filter it out.
|
||||
console.error(`Could not parse "${repeatInterval}" for job ${job.attrs._id}. Skipping.`);
|
||||
return null; // Return null for now
|
||||
}
|
||||
})
|
||||
// Step 3: Filter out any nulls that resulted from a parsing error.
|
||||
.filter(detail => detail !== null);
|
||||
|
||||
res.status(200).json({ scheduledUpdates: details });
|
||||
|
||||
} catch (error) { // FIX 3: Capture and log the actual error
|
||||
console.error("Error in /periph_schedule_list:", error);
|
||||
res.status(500).json({ error: 'Internal Server Error' });
|
||||
}
|
||||
});
|
||||
@@ -2584,6 +2584,17 @@ CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH=20
|
||||
CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT=31
|
||||
CONFIG_NIMBLE_CPP_IDF=y
|
||||
# end of ESP-NimBLE-CPP configuration
|
||||
|
||||
#
|
||||
# ESP Socket.IO client
|
||||
#
|
||||
|
||||
#
|
||||
# ESP WebSocket client
|
||||
#
|
||||
# CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER is not set
|
||||
# CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK is not set
|
||||
# end of ESP WebSocket client
|
||||
# end of Component config
|
||||
|
||||
# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set
|
||||
|
||||
@@ -5,4 +5,4 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.* ${CMAKE_SOURCE_DIR}/in
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES nvs_flash esp-nimble-cpp)
|
||||
REQUIRES nvs_flash esp-nimble-cpp esp_socketio_client)
|
||||
|
||||
2
src/idf_component.yml
Normal file
2
src/idf_component.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
dependencies:
|
||||
bubblesnake/esp_socketio_client: "^1.0.0"
|
||||
98
src/main.cpp
98
src/main.cpp
@@ -6,8 +6,12 @@
|
||||
#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 ");
|
||||
esp_err_t ret = nvs_flash_init(); // change to secure init logic soon!!
|
||||
// 2. If NVS is full or corrupt (common after flashing new code), erase and retry
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
@@ -17,44 +21,76 @@ extern "C" void app_main() {
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
bmWiFi.init();
|
||||
|
||||
nvs_handle_t WiFiHandle;
|
||||
if (nvs_open(nvsWiFi, NVS_READWRITE, &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);
|
||||
|
||||
if (WiFiPrefsError == ESP_ERR_NVS_NOT_FOUND) {
|
||||
// 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);
|
||||
// TODO: add enterprise support
|
||||
if (!bmWiFi.attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) {
|
||||
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 {
|
||||
// Make RGB LED certain color (Blue?)
|
||||
nvs_close(WiFiHandle);
|
||||
printf("Program error in Wifi Connection\n");
|
||||
}
|
||||
else {
|
||||
printf("WiFi NVS segment doesn't exist, entering setup.\n");
|
||||
initialSetup();
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("ERROR: Couldn't open wifi NVS segment\nProgram stopped.\n");
|
||||
while (1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Main loop
|
||||
while (1) {
|
||||
|
||||
Reference in New Issue
Block a user