diff --git a/.cursor/rules b/.cursor/rules deleted file mode 100644 index b82809d..0000000 --- a/.cursor/rules +++ /dev/null @@ -1,2 +0,0 @@ -## Build -- use ./ctl build target diff --git a/ctl.sh b/ctl.sh index 02c5c0b..992ffb9 100755 --- a/ctl.sh +++ b/ctl.sh @@ -51,8 +51,4 @@ function cluster { ${@:-info} } -function monitor { - pio run -t monitor -} - ${@:-info} diff --git a/examples/wifiscan/README.md b/examples/wifiscan/README.md deleted file mode 100644 index 152986e..0000000 --- a/examples/wifiscan/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# WiFi Scanner Example - -This example demonstrates how to use the async WiFi scanning functionality in SPORE with periodic scanning via tasks. - -## Features - -- **Async WiFi Scanning**: Non-blocking WiFi network discovery via NetworkManager -- **Task-based Periodic Scanning**: Automatically scans for networks every minute using TaskManager -- **Event-driven**: Uses the event system to handle scan events -- **REST API**: HTTP endpoints to manually trigger scans and view results -- **Detailed Results**: Shows SSID, RSSI, channel, and encryption type for each network - -## Usage - -1. Upload this example to your ESP8266 device -2. Open the Serial Monitor at 115200 baud -3. The device will automatically start scanning for WiFi networks every minute -4. Results will be displayed in the Serial Monitor -5. Use the REST API to manually trigger scans or view current results - -## Event System - -The WiFi scanner uses the following events: - -- `wifi/scan/start`: Fired when scan starts (both manual and periodic) -- `wifi/scan/complete`: Fired when scan completes successfully -- `wifi/scan/error`: Fired when scan fails to start -- `wifi/scan/timeout`: Fired when scan times out (10 seconds) - -## Task Management - -The example registers a periodic task: -- **Task Name**: `wifi_scan_periodic` -- **Interval**: 60 seconds (60000ms) -- **Function**: Fires `wifi/scan/start` event and starts WiFi scan - -## REST API - -### Manual Scan Control -- **Start Scan**: `POST /api/wifi/scan` -- **Get Status**: `GET /api/wifi/status` - -### Example API Usage -```bash -# Start a manual scan -curl -X POST http://192.168.1.50/api/wifi/scan - -# Get current scan status and results -curl http://192.168.1.50/api/wifi/status - -# Check task status -curl http://192.168.1.50/api/tasks/status - -# Disable periodic scanning -curl -X POST http://192.168.1.50/api/tasks/control \ - -d task=wifi_scan_periodic -d action=disable -``` - -## Architecture - -- **WiFiScannerService**: Manages periodic scanning and API endpoints -- **NetworkManager**: Handles WiFi scanning operations and callbacks -- **NodeContext**: Stores the WiFi access points data -- **TaskManager**: Schedules periodic scan tasks -- **Event System**: Provides communication between components - -## WiFiAccessPoint Structure - -```cpp -struct WiFiAccessPoint { - String ssid; // Network name - int32_t rssi; // Signal strength - uint8_t encryption; // Encryption type - uint8_t* bssid; // MAC address - int32_t channel; // WiFi channel - bool isHidden; // Hidden network flag -}; -``` - -## Task Configuration - -The periodic scanning task can be controlled via the standard TaskManager API: -- Enable/disable the task -- Change the scan interval -- Monitor task status -- Start/stop the task - -This provides flexibility to adjust scanning behavior based on application needs. \ No newline at end of file diff --git a/examples/wifiscan/main.cpp b/examples/wifiscan/main.cpp deleted file mode 100644 index d82f591..0000000 --- a/examples/wifiscan/main.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include "Globals.h" -#include "NodeContext.h" -#include "NetworkManager.h" -#include "ClusterManager.h" -#include "ApiServer.h" -#include "TaskManager.h" - -using namespace std; - -class WiFiScannerService { -public: - WiFiScannerService(NodeContext& ctx, TaskManager& taskMgr, NetworkManager& networkMgr) - : ctx(ctx), taskManager(taskMgr), network(networkMgr) { - registerTasks(); - } - - void registerApi(ApiServer& api) { - api.addEndpoint("/api/wifi/scan", HTTP_POST, [this](AsyncWebServerRequest* request) { - if (network.isWiFiScanning()) { - JsonDocument resp; - resp["success"] = false; - resp["message"] = "WiFi scan already in progress"; - String json; - serializeJson(resp, json); - request->send(409, "application/json", json); - return; - } - - network.startWiFiScan(); - - JsonDocument resp; - resp["success"] = true; - resp["message"] = "WiFi scan started"; - String json; - serializeJson(resp, json); - request->send(200, "application/json", json); - }); - - api.addEndpoint("/api/wifi/status", HTTP_GET, [this](AsyncWebServerRequest* request) { - JsonDocument doc; - doc["scanning"] = network.isWiFiScanning(); - doc["networks_found"] = ctx.wifiAccessPoints->size(); - - JsonArray networks = doc["networks"].to(); - for (const auto& ap : *ctx.wifiAccessPoints) { - JsonObject network = networks.add(); - network["ssid"] = ap.ssid; - network["rssi"] = ap.rssi; - network["channel"] = ap.channel; - network["encryption"] = ap.encryption; - network["hidden"] = ap.isHidden; - } - - String json; - serializeJson(doc, json); - request->send(200, "application/json", json); - }); - } - -private: - void registerTasks() { - // Register task to start WiFi scan every minute (60000ms) - taskManager.registerTask("wifi_scan_periodic", 60000, [this]() { - if (!network.isWiFiScanning()) { - Serial.println("[WiFiScannerService] Starting periodic WiFi scan..."); - ctx.fire("wifi/scan/start", nullptr); - network.startWiFiScan(); - } else { - Serial.println("[WiFiScannerService] Skipping scan - already in progress"); - } - }); - } - - NodeContext& ctx; - TaskManager& taskManager; - NetworkManager& network; -}; - -NodeContext ctx({ - {"app", "wifiscan"}, - {"role", "demo"} -}); -NetworkManager network(ctx); -TaskManager taskManager(ctx); -ClusterManager cluster(ctx, taskManager); -ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port); -WiFiScannerService wifiScanner(ctx, taskManager, network); - -// WiFi scan start callback -void onWiFiScanStart(void* data) { - Serial.println("[WiFi] Scan started..."); -} - -// WiFi scan complete callback -void onWiFiScanComplete(void* data) { - Serial.println("\n=== WiFi Scan Results ==="); - - std::vector* accessPoints = static_cast*>(data); - - if (accessPoints->empty()) { - Serial.println("No networks found"); - return; - } - - Serial.printf("Found %d networks:\n", accessPoints->size()); - Serial.println("SSID\t\t\tRSSI\tChannel\tEncryption"); - Serial.println("----------------------------------------"); - - for (const auto& ap : *accessPoints) { - String encryptionStr = "Unknown"; - switch (ap.encryption) { - case ENC_TYPE_NONE: - encryptionStr = "Open"; - break; - case ENC_TYPE_WEP: - encryptionStr = "WEP"; - break; - case ENC_TYPE_TKIP: - encryptionStr = "WPA"; - break; - case ENC_TYPE_CCMP: - encryptionStr = "WPA2"; - break; - case ENC_TYPE_AUTO: - encryptionStr = "Auto"; - break; - } - - Serial.printf("%-20s\t%d\t%d\t%s\n", - ap.ssid.c_str(), ap.rssi, ap.channel, encryptionStr.c_str()); - } - Serial.println("========================\n"); -} - -// WiFi scan error callback -void onWiFiScanError(void* data) { - Serial.println("[WiFi] Scan failed - error occurred"); -} - -// WiFi scan timeout callback -void onWiFiScanTimeout(void* data) { - Serial.println("[WiFi] Scan failed - timeout"); -} - -void setup() { - Serial.begin(115200); - Serial.println("\n=== WiFi Scanner Example ==="); - - // Initialize task manager first - taskManager.initialize(); - ctx.taskManager = &taskManager; - - // Initialize network tasks - network.initTasks(); - - // Setup WiFi - network.setupWiFi(); - - // Start the API server - apiServer.begin(); - wifiScanner.registerApi(apiServer); - - // Register WiFi scan event callbacks - ctx.on("wifi/scan/start", onWiFiScanStart); - ctx.on("wifi/scan/complete", onWiFiScanComplete); - ctx.on("wifi/scan/error", onWiFiScanError); - ctx.on("wifi/scan/timeout", onWiFiScanTimeout); - - // Start an initial WiFi scan - Serial.println("Starting initial WiFi scan..."); - ctx.fire("wifi/scan/start", nullptr); - network.startWiFiScan(); - - // Print initial task status - taskManager.printTaskStatus(); -} - -void loop() { - taskManager.execute(); - yield(); -} \ No newline at end of file diff --git a/include/NetworkManager.h b/include/NetworkManager.h index 6c9042b..9a98672 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -7,18 +7,6 @@ public: NetworkManager(NodeContext& ctx); void setupWiFi(); void setHostnameFromMac(); - void startWiFiScan(); - void updateWiFiScan(); - bool isWiFiScanning() const; - void processScanResults(int networksFound); - void initTasks(); // Initialize tasks after TaskManager is ready // Public method to process scan results - private: NodeContext& ctx; - bool wifiScanInProgress; - unsigned long wifiScanStartTime; - static const unsigned long WIFI_SCAN_TIMEOUT_MS = 10000; // 10 seconds timeout - static const char* const WIFI_SCAN_MONITOR_TASK; // Task name for WiFi scan monitoring - - void onWiFiScanComplete(int networksFound); // Keep private for internal use }; diff --git a/include/NodeContext.h b/include/NodeContext.h index f41d142..76576de 100644 --- a/include/NodeContext.h +++ b/include/NodeContext.h @@ -2,33 +2,12 @@ #include #include -#include #include "NodeInfo.h" #include #include #include #include "Config.h" -// Forward declaration -class TaskManager; - -// WiFi access point structure -struct WiFiAccessPoint { - String ssid; - int32_t rssi; - uint8_t encryption; - uint8_t* bssid; - int32_t channel; - bool isHidden; - - WiFiAccessPoint() : rssi(0), encryption(0), bssid(nullptr), channel(0), isHidden(false) {} - ~WiFiAccessPoint() { - if (bssid) { - delete[] bssid; - } - } -}; - class NodeContext { public: NodeContext(); @@ -40,14 +19,10 @@ public: NodeInfo self; std::map* memberList; Config config; - TaskManager* taskManager; using EventCallback = std::function; std::map> eventRegistry; void on(const std::string& event, EventCallback cb); void fire(const std::string& event, void* data); - - // WiFi access points storage - std::vector* wifiAccessPoints; }; diff --git a/include/TaskManager.h b/include/TaskManager.h index d5947a9..ffe1488 100644 --- a/include/TaskManager.h +++ b/include/TaskManager.h @@ -4,11 +4,9 @@ #include #include #include +#include "NodeContext.h" #include -// Forward declaration -class NodeContext; - // Define our own callback type to avoid conflict with TaskScheduler using TaskFunction = std::function; diff --git a/platformio.ini b/platformio.ini index 7a726f2..e2bd428 100644 --- a/platformio.ini +++ b/platformio.ini @@ -124,32 +124,3 @@ build_src_filter = + + + - -[env:esp01_1m_wifiscan] -platform = platformio/espressif8266@^4.2.1 -board = esp01_1m -framework = arduino -upload_speed = 115200 -monitor_speed = 115200 -board_build.partitions = partitions_ota_1M.csv -board_build.flash_mode = dout -board_build.flash_size = 1M -lib_deps = ${common.lib_deps} -build_src_filter = - + - + - + - -[env:d1_mini_wifiscan] -platform = platformio/espressif8266@^4.2.1 -board = d1_mini -framework = arduino -upload_speed = 115200 -monitor_speed = 115200 -board_build.flash_mode = dio -board_build.flash_size = 4M -lib_deps = ${common.lib_deps} -build_src_filter = - + - + - + diff --git a/src/NetworkManager.cpp b/src/NetworkManager.cpp index 2c50f2d..cae4ca0 100644 --- a/src/NetworkManager.cpp +++ b/src/NetworkManager.cpp @@ -1,29 +1,8 @@ #include "NetworkManager.h" -#include "TaskManager.h" // SSID and password are now configured via Config class -const char* const NetworkManager::WIFI_SCAN_MONITOR_TASK = "wifi_scan_monitor"; - -NetworkManager::NetworkManager(NodeContext& ctx) : ctx(ctx), wifiScanInProgress(false), wifiScanStartTime(0) { - // Register scan process callback - ctx.on("wifi/scan/process", [this](void* data) { - int networksFound = reinterpret_cast(data); - this->processScanResults(networksFound); - }); -} - -void NetworkManager::initTasks() { - if (!ctx.taskManager) { - Serial.println("[WiFi] Error: TaskManager not initialized"); - return; - } - - // Register task to check scan status every 100ms (initially disabled) - ctx.taskManager->registerTask(WIFI_SCAN_MONITOR_TASK, 100, [this]() { - this->updateWiFiScan(); - }, false); // false = disabled by default -} +NetworkManager::NetworkManager(NodeContext& ctx) : ctx(ctx) {} void NetworkManager::setHostnameFromMac() { uint8_t mac[6]; @@ -86,133 +65,3 @@ void NetworkManager::setupWiFi() { // Notify listeners that the node is (re)discovered ctx.fire("node_discovered", &ctx.self); } - -void NetworkManager::startWiFiScan() { - if (wifiScanInProgress) { - Serial.println("[WiFi] Scan already in progress"); - return; - } - - // Check if we're in AP mode only - if (WiFi.getMode() == WIFI_AP) { - // Enable STA mode while keeping AP mode - WiFi.mode(WIFI_AP_STA); - delay(100); // Give some time for mode change - } - - // Ensure we have STA mode enabled - if (WiFi.getMode() != WIFI_STA && WiFi.getMode() != WIFI_AP_STA) { - Serial.println("[WiFi] Error: Cannot scan without STA mode enabled"); - ctx.fire("wifi/scan/error", nullptr); - return; - } - - Serial.println("[WiFi] Starting WiFi scan..."); - wifiScanInProgress = true; - wifiScanStartTime = millis(); - - // Enable the monitoring task if TaskManager is available - if (ctx.taskManager) { - ctx.taskManager->enableTask(WIFI_SCAN_MONITOR_TASK); - } - - // Clear previous results safely - if (ctx.wifiAccessPoints) { - ctx.wifiAccessPoints->clear(); - } - - // Disable interrupts briefly during scan start - noInterrupts(); - // Start the scan - WiFi.scanNetworksAsync([this](int networksFound) { - // Schedule callback in main loop - ctx.fire("wifi/scan/process", reinterpret_cast(networksFound)); - }, true); // Show hidden networks - interrupts(); -} - -void NetworkManager::updateWiFiScan() { - if (!wifiScanInProgress) { - return; - } - - // Check for timeout - if (millis() - wifiScanStartTime > WIFI_SCAN_TIMEOUT_MS) { - Serial.println("[WiFi] WiFi scan timeout"); - wifiScanInProgress = false; - if (ctx.taskManager) { - ctx.taskManager->disableTask(WIFI_SCAN_MONITOR_TASK); - } - ctx.fire("wifi/scan/timeout", nullptr); - } -} - -void NetworkManager::processScanResults(int networksFound) { - // This is called from the main loop context via the event system - if (!wifiScanInProgress) { - return; // Ignore if we're not expecting results - } - - wifiScanInProgress = false; - // Disable the monitoring task if TaskManager is available - if (ctx.taskManager) { - ctx.taskManager->disableTask(WIFI_SCAN_MONITOR_TASK); - } - - Serial.printf("[WiFi] Processing scan results, found %d networks\n", networksFound); - - // Create a temporary vector to hold new results - std::vector newAccessPoints; - - if (networksFound > 0) { - newAccessPoints.reserve(networksFound); // Pre-allocate space - - // Process each found network - for (int i = 0; i < networksFound; i++) { - WiFiAccessPoint ap; - ap.ssid = WiFi.SSID(i); - ap.rssi = WiFi.RSSI(i); - ap.encryption = WiFi.encryptionType(i); - ap.channel = WiFi.channel(i); - ap.isHidden = WiFi.isHidden(i); - - // Copy BSSID - with null check and bounds protection - uint8_t* bssid = WiFi.BSSID(i); - ap.bssid = nullptr; // Initialize to null first - if (bssid != nullptr) { - ap.bssid = new (std::nothrow) uint8_t[6]; // Use nothrow to prevent exceptions - if (ap.bssid != nullptr) { - memcpy(ap.bssid, bssid, 6); - } - } - - newAccessPoints.push_back(ap); - - Serial.printf("[WiFi] %d: %s (RSSI: %d, Ch: %d, Enc: %d)\n", - i, ap.ssid.c_str(), ap.rssi, ap.channel, ap.encryption); - } - } - - // Free the scan results from WiFi to prevent memory leaks - WiFi.scanDelete(); - - // Safely swap the new results with the stored results - if (ctx.wifiAccessPoints) { - ctx.wifiAccessPoints->swap(newAccessPoints); - // Fire the scan complete event with a copy of the pointer - auto accessPoints = ctx.wifiAccessPoints; - ctx.fire("wifi/scan/complete", accessPoints); - } else { - Serial.println("[WiFi] Error: wifiAccessPoints is null"); - ctx.fire("wifi/scan/error", nullptr); - } -} - -void NetworkManager::onWiFiScanComplete(int networksFound) { - // Internal callback that schedules processing in the main loop - ctx.fire("wifi/scan/process", reinterpret_cast(networksFound)); -} - -bool NetworkManager::isWiFiScanning() const { - return wifiScanInProgress; -} diff --git a/src/NodeContext.cpp b/src/NodeContext.cpp index 4d12998..e5833d3 100644 --- a/src/NodeContext.cpp +++ b/src/NodeContext.cpp @@ -1,11 +1,8 @@ #include "NodeContext.h" -#include "TaskManager.h" NodeContext::NodeContext() { udp = new WiFiUDP(); memberList = new std::map(); - wifiAccessPoints = new std::vector(); - taskManager = nullptr; // Will be set by TaskManager constructor hostname = ""; self.hostname = ""; self.ip = IPAddress(); @@ -22,7 +19,6 @@ NodeContext::NodeContext(std::initializer_list> initia NodeContext::~NodeContext() { delete udp; delete memberList; - delete wifiAccessPoints; } void NodeContext::on(const std::string& event, EventCallback cb) {