Researched the exact modules the user is building with and fixed three
concrete issues the earlier speculative firmware got wrong:
1. WiFi: confirmed the target board (Waveshare ESP32-P4-Module-DEV-KIT,
chip ESP32-P4NRW32) bridges WiFi through an onboard ESP32-C6
co-processor over a fixed 7-pin SDIO link (CLK18/CMD19/D0-14/D1-15/
D2-16/D3-17/RESET54, cross-confirmed against Espressif's own
esp-hosted-mcu docs). wifi_manager.c's esp_wifi_init()/esp_wifi_start()
calls don't need to change — esp_wifi_remote/esp_hosted provide a
drop-in-compatible API — but the component manifest (new
main/idf_component.yml) and sdkconfig.defaults were missing entirely.
2. Real pin conflict: the presence sensor's original UART pins (17/18)
directly collided with the SDIO CLK/D3 pins above — wiring it there
would have broken WiFi, the sensor, or both. Moved to GPIO4/5.
3. Swapped placeholder parts for the user's actual hardware:
- BME280 -> BMP280 (GY-BMP280 module): temp+pressure only, no humidity.
Rewrote the driver rather than just renaming it — the old code would
have read nonexistent humidity registers and reported garbage
forever. 3.3V-only wiring note added (the BME280 assumption of
5V-tolerant logic doesn't hold for this specific breakout).
- LD2410 -> RD-03E (Ai-Thinker, not Hi-Link — a different manufacturer
with a different, incompatible UART protocol). Rewrote the frame
parser against the RD-03E's actual (if less-documented) 5-byte
simple-report format. Reports numeric distance instead of a boolean,
which better fits both the hardware's actual output and the backend's
statistical anomaly detector.
README, CMakeLists.txt, and all cross-references updated to match.
134 lines
5.1 KiB
C
134 lines
5.1 KiB
C
// Wi-Fi station-mode connection manager — see wifi_manager.h for how Wi-Fi
|
|
// actually reaches the network on this target (ESP32-C6 co-processor over
|
|
// SDIO via esp_wifi_remote/esp_hosted). The esp_wifi_*/esp_netif_* calls
|
|
// below are the same ones a Wi-Fi-native chip would use.
|
|
//
|
|
// Structure follows ESP-IDF's own documented Wi-Fi station example pattern
|
|
// (event-driven connect via WIFI_EVENT/IP_EVENT + an event group the rest
|
|
// of the app can block on), extended with an exponential-backoff reconnect
|
|
// instead of giving up after N attempts — a sensor node left running for
|
|
// weeks needs to ride out a router reboot or a home Wi-Fi outage
|
|
// indefinitely, not park itself in a permanent failure state.
|
|
//
|
|
// UNVERIFIED AGAINST REAL HARDWARE — see README.md.
|
|
|
|
#include <inttypes.h>
|
|
#include "wifi_manager.h"
|
|
#include "device_config.h"
|
|
#include "esp_wifi.h"
|
|
#include "esp_event.h"
|
|
#include "esp_netif.h"
|
|
#include "esp_log.h"
|
|
#include "esp_timer.h"
|
|
#include "nvs_flash.h"
|
|
#include "freertos/event_groups.h"
|
|
|
|
static const char *TAG = "wifi_manager";
|
|
|
|
#define WIFI_CONNECTED_BIT BIT0
|
|
|
|
#define WIFI_RECONNECT_BASE_DELAY_MS 1000
|
|
#define WIFI_RECONNECT_MAX_DELAY_MS 30000
|
|
#define WIFI_RECONNECT_BACKOFF_CAP_SHIFT 5 // 1000ms << 5 = 32000ms, then clamped to MAX
|
|
|
|
static EventGroupHandle_t s_wifi_event_group = NULL;
|
|
static esp_timer_handle_t s_reconnect_timer = NULL;
|
|
static uint32_t s_retry_count = 0;
|
|
|
|
static void reconnect_timer_cb(void *arg) {
|
|
ESP_LOGI(TAG, "attempting Wi-Fi reconnect");
|
|
esp_err_t err = esp_wifi_connect();
|
|
if (err != ESP_OK) {
|
|
ESP_LOGW(TAG, "esp_wifi_connect() failed: %s", esp_err_to_name(err));
|
|
}
|
|
}
|
|
|
|
static void schedule_reconnect(void) {
|
|
uint32_t shift = s_retry_count < WIFI_RECONNECT_BACKOFF_CAP_SHIFT ? s_retry_count : WIFI_RECONNECT_BACKOFF_CAP_SHIFT;
|
|
uint32_t delay_ms = WIFI_RECONNECT_BASE_DELAY_MS << shift;
|
|
if (delay_ms > WIFI_RECONNECT_MAX_DELAY_MS) {
|
|
delay_ms = WIFI_RECONNECT_MAX_DELAY_MS;
|
|
}
|
|
s_retry_count++;
|
|
ESP_LOGW(TAG, "reconnecting in %" PRIu32 " ms (attempt %" PRIu32 ")", delay_ms, s_retry_count);
|
|
esp_timer_stop(s_reconnect_timer); // no-op if not running; keeps this idempotent
|
|
esp_timer_start_once(s_reconnect_timer, (uint64_t)delay_ms * 1000ULL);
|
|
}
|
|
|
|
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
|
int32_t event_id, void *event_data) {
|
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
esp_wifi_connect();
|
|
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
|
wifi_event_sta_disconnected_t *disc = (wifi_event_sta_disconnected_t *)event_data;
|
|
ESP_LOGW(TAG, "Wi-Fi disconnected (reason %d)", disc ? disc->reason : -1);
|
|
schedule_reconnect();
|
|
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
ip_event_got_ip_t *evt = (ip_event_got_ip_t *)event_data;
|
|
ESP_LOGI(TAG, "got IP: " IPSTR, IP2STR(&evt->ip_info.ip));
|
|
s_retry_count = 0;
|
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
|
}
|
|
}
|
|
|
|
esp_err_t wifi_manager_start(void) {
|
|
esp_err_t err = nvs_flash_init();
|
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
err = nvs_flash_init();
|
|
}
|
|
ESP_ERROR_CHECK(err);
|
|
|
|
s_wifi_event_group = xEventGroupCreate();
|
|
|
|
ESP_ERROR_CHECK(esp_netif_init());
|
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
esp_netif_create_default_wifi_sta();
|
|
|
|
wifi_init_config_t init_cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
ESP_ERROR_CHECK(esp_wifi_init(&init_cfg));
|
|
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL));
|
|
|
|
const esp_timer_create_args_t timer_args = {
|
|
.callback = &reconnect_timer_cb,
|
|
.name = "wifi_reconnect",
|
|
};
|
|
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &s_reconnect_timer));
|
|
|
|
wifi_config_t wifi_config = {
|
|
.sta = {
|
|
.ssid = DEVICE_WIFI_SSID,
|
|
.password = DEVICE_WIFI_PASSWORD,
|
|
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
|
|
},
|
|
};
|
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
|
ESP_ERROR_CHECK(esp_wifi_start());
|
|
|
|
ESP_LOGI(TAG, "Wi-Fi station starting, SSID \"%s\"", DEVICE_WIFI_SSID);
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t wifi_manager_wait_connected(TickType_t timeout_ticks) {
|
|
if (s_wifi_event_group == NULL) {
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
EventBits_t bits = xEventGroupWaitBits(
|
|
s_wifi_event_group, WIFI_CONNECTED_BIT,
|
|
pdFALSE /* don't clear on exit */, pdFALSE /* any bit */, timeout_ticks);
|
|
return (bits & WIFI_CONNECTED_BIT) ? ESP_OK : ESP_ERR_TIMEOUT;
|
|
}
|
|
|
|
bool wifi_manager_is_connected(void) {
|
|
if (s_wifi_event_group == NULL) {
|
|
return false;
|
|
}
|
|
return (xEventGroupGetBits(s_wifi_event_group) & WIFI_CONNECTED_BIT) != 0;
|
|
}
|