Merge pull request #21 from SummerSigh/main

fix/add proper scan timeouts
This commit is contained in:
Lorow
2025-12-13 20:02:52 +01:00
committed by GitHub
8 changed files with 55 additions and 24 deletions

View File

@@ -74,8 +74,8 @@ std::function<CommandResult()> CommandManager::createCommand(const CommandType t
case CommandType::RESTART_DEVICE:
return restartDeviceCommand;
case CommandType::SCAN_NETWORKS:
return [this]
{ return scanNetworksCommand(this->registry); };
return [this, json]
{ return scanNetworksCommand(this->registry, json); };
case CommandType::START_STREAMING:
return startStreamingCommand;
case CommandType::GET_WIFI_STATUS:

View File

@@ -1,7 +1,7 @@
#include "scan_commands.hpp"
#include "sdkconfig.h"
CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry)
CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry, const nlohmann::json &json)
{
#if !CONFIG_GENERAL_ENABLE_WIRELESS
return CommandResult::getErrorResult("Not supported by current firmware");
@@ -12,7 +12,14 @@ CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry)
return CommandResult::getErrorResult("Not supported by current firmware");
}
auto networks = wifiManager->ScanNetworks();
// Extract timeout from JSON if provided, default to 15000ms (15 seconds)
int timeout_ms = 15000;
if (json.contains("timeout_ms") && json["timeout_ms"].is_number_integer())
{
timeout_ms = json["timeout_ms"].get<int>();
}
auto networks = wifiManager->ScanNetworks(timeout_ms);
nlohmann::json result;
std::vector<nlohmann::json> networksJson;

View File

@@ -8,6 +8,6 @@
#include <string>
#include <nlohmann-json.hpp>
CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry);
CommandResult scanNetworksCommand(std::shared_ptr<DependencyRegistry> registry, const nlohmann::json &json);
#endif

View File

@@ -1,5 +1,6 @@
#include "WiFiScanner.hpp"
#include <cstring>
#include "esp_timer.h"
static const char *TAG = "WiFiScanner";
@@ -42,7 +43,7 @@ void WiFiScanner::scanResultCallback(void *arg, esp_event_base_t event_base,
}
// todo this is garbage
std::vector<WiFiNetwork> WiFiScanner::scanNetworks()
std::vector<WiFiNetwork> WiFiScanner::scanNetworks(int timeout_ms)
{
std::vector<WiFiNetwork> scan_results;
@@ -92,11 +93,22 @@ std::vector<WiFiNetwork> WiFiScanner::scanNetworks()
}
else
{
// Sequential channel scan - scan each channel individually
// Sequential channel scan - scan each channel individually with timeout tracking
std::vector<wifi_ap_record_t> all_records;
int64_t start_time = esp_timer_get_time() / 1000; // Convert to ms
for (uint8_t ch = 1; ch <= 13; ch++)
{
// Check if we've exceeded the timeout
int64_t current_time = esp_timer_get_time() / 1000;
int64_t elapsed = current_time - start_time;
if (elapsed >= timeout_ms)
{
ESP_LOGW(TAG, "Sequential scan timeout after %lld ms at channel %d", elapsed, ch);
break;
}
wifi_scan_config_t scan_config = {
.ssid = nullptr,
.bssid = nullptr,
@@ -144,35 +156,42 @@ std::vector<WiFiNetwork> WiFiScanner::scanNetworks()
scan_results.push_back(network);
}
int64_t total_time = (esp_timer_get_time() / 1000) - start_time;
ESP_LOGI(TAG, "Sequential scan completed in %lld ms, found %d APs", total_time, scan_results.size());
// Skip the normal result processing
return scan_results;
}
// Wait for scan completion with timeout
int timeout_ms = 15000; // 15 second timeout
int elapsed_ms = 0;
int64_t start_time = esp_timer_get_time() / 1000; // Convert to ms
int64_t elapsed_ms = 0;
bool scan_done = false;
while (elapsed_ms < timeout_ms)
{
// Check if scan is actually complete by trying to get AP count
// When scan is done, this will return ESP_OK with a valid count
uint16_t temp_count = 0;
esp_err_t count_err = esp_wifi_scan_get_ap_num(&temp_count);
if (count_err == ESP_OK)
// If we can successfully get the AP count, the scan is likely complete
// However, we should still wait for the scan to fully finish
if (count_err == ESP_OK && temp_count > 0)
{
// Wait a bit longer after finding networks to ensure scan is complete
if (temp_count > 0 && elapsed_ms > 5000)
{
break;
}
// Give it a bit more time to ensure all channels are scanned
vTaskDelay(pdMS_TO_TICKS(500));
scan_done = true;
break;
}
vTaskDelay(pdMS_TO_TICKS(200));
elapsed_ms += 200;
elapsed_ms = (esp_timer_get_time() / 1000) - start_time;
}
if (elapsed_ms >= timeout_ms)
if (!scan_done && elapsed_ms >= timeout_ms)
{
ESP_LOGE(TAG, "Scan timeout after %d ms", timeout_ms);
ESP_LOGE(TAG, "Scan timeout after %lld ms", elapsed_ms);
esp_wifi_scan_stop();
return scan_results;
}

View File

@@ -20,7 +20,7 @@ class WiFiScanner
{
public:
WiFiScanner();
std::vector<WiFiNetwork> scanNetworks();
std::vector<WiFiNetwork> scanNetworks(int timeout_ms = 15000);
static void scanResultCallback(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
private:

View File

@@ -240,7 +240,7 @@ void WiFiManager::SetupAccessPoint()
ESP_LOGI(WIFI_MANAGER_TAG, "AP started.");
}
std::vector<WiFiNetwork> WiFiManager::ScanNetworks()
std::vector<WiFiNetwork> WiFiManager::ScanNetworks(int timeout_ms)
{
wifi_mode_t current_mode;
esp_err_t err = esp_wifi_get_mode(&current_mode);
@@ -288,7 +288,7 @@ std::vector<WiFiNetwork> WiFiManager::ScanNetworks()
vTaskDelay(pdMS_TO_TICKS(2000));
// Perform scan
auto networks = wifiScanner->scanNetworks();
auto networks = wifiScanner->scanNetworks(timeout_ms);
// Restore AP-only mode
ESP_LOGI(WIFI_MANAGER_TAG, "Restoring AP-only mode");
@@ -304,7 +304,7 @@ std::vector<WiFiNetwork> WiFiManager::ScanNetworks()
}
// If already in STA or APSTA mode, scan directly
return wifiScanner->scanNetworks();
return wifiScanner->scanNetworks(timeout_ms);
}
WiFiState_e WiFiManager::GetCurrentWiFiState()

View File

@@ -49,7 +49,7 @@ private:
public:
WiFiManager(std::shared_ptr<ProjectConfig> deviceConfig, QueueHandle_t eventQueue, StateManager *stateManager);
void Begin();
std::vector<WiFiNetwork> ScanNetworks();
std::vector<WiFiNetwork> ScanNetworks(int timeout_ms = 15000);
WiFiState_e GetCurrentWiFiState();
void TryConnectToStoredNetworks();
};

View File

@@ -228,7 +228,12 @@ class WiFiScanner:
print(
f"🔍 Scanning for WiFi networks (this may take up to {timeout} seconds)..."
)
response = self.device.send_command("scan_networks", timeout=timeout)
# Convert timeout from seconds to milliseconds for the ESP
timeout_ms = timeout * 1000
# Send timeout_ms in the command data AND as serial timeout
response = self.device.send_command(
"scan_networks", params={"timeout_ms": timeout_ms}, timeout=timeout
)
if has_command_failed(response):
print(f"❌ Scan failed: {response['error']}")
return