ESP Wi-Fi Service
简介
Wi-Fi Service 把设备联网流程中的凭据存储、配网交互、自动连接、网络选择和质量探测统一到一套 ESP Service 服务接口中。使用它之后,应用不需要分别维护凭据存储、SoftAP/Web 配网、BluFi 配网、断线重连和多 AP 选择逻辑,可以更快构建稳定、便于现场运维的联网产品。
功能清单
Profile 管理:维护多组 Wi-Fi 凭据,支持新增、更新、启用、禁用、删除和清理,配网通道与连接选择共享同一个 profile manager
可插拔存储:复用 ESP Config Manager 的 NVS、文件系统、双分区 raw flash 或自定义存储适配层,并支持加密回调保护已保存凭据
多通道配网:HTTP SoftAP/Web UI、BluFi,以及应用自定义配网流程,所有通道写入同一份共享 profile
自动启动策略:服务启动时根据是否存在已启用配置,自动进入连接选择流程或启动已配置的配网流程
智能选择与切换:按用户优先级、信号质量、历史连通性和临时黑名单选择更合适的 AP,并在断线或链路退化后重新评估
网络质量探测:支持连通性、延迟和吞吐退化判断,处理“已连接但业务不可用”的场景
可选 MCP 工具支持:同时启用
CONFIG_ESP_MCP_ENABLE和CONFIG_WIFI_SERVICE_MCP_ENABLE后,可通过 ESP Service 的 MCP 服务器远程查询状态、管理 profile 和触发配网/连接
技术拆解
Profile 管理与存储
每个 Wi-Fi 凭据保存为一个 esp_wifi_service_profile_t(SSID、密码、优先级、启用标志),由 esp_wifi_service_profile_mgr_t 统一管理并持久化。profile manager 的存储层直接复用 ESP Config Manager 的存储适配接口,创建时需要先准备好一个 esp_config_storage_t 句柄:
esp_config_storage_nvs_t nvs_cfg = {
.nvs_namespace = "wifi_store",
.key_primary = "profile_p",
.key_backup = "profile_b",
};
esp_config_storage_t profile_store = NULL;
esp_config_storage_init_nvs(&nvs_cfg, &profile_store);
esp_wifi_service_profile_mgr_cfg_t profile_cfg = {
.max_profiles = 8,
.storage = profile_store,
};
esp_wifi_service_profile_mgr_t profile_manager = NULL;
esp_wifi_service_profile_mgr_init(&profile_cfg, &profile_manager);
同一个 profile_manager 句柄要同时传给 Wi-Fi Service 和每个配网通道的配置,这样配网写入的凭据才能被连接选择逻辑立即看到。
配网通道
服务启动时如果存在至少一个已启用的 profile,就直接进入连接选择流程;否则启动 prov_list 中配置的所有配网通道。内置提供 HTTP SoftAP/Web UI 和 BluFi 两种通道,也可以由应用自行实现自定义配网流程写入同一个 profile manager:
HTTP 通道启动 SoftAP、DNS captive portal、HTTP server 和默认或自定义 Web UI,凭据通过
POST /prov/profiles提交BluFi 通道通过手机侧蓝牙发送网络信息,凭据同样落到共享 profile manager,依赖
CONFIG_WIFI_SERVICE_PROV_BLUFI_ENABLE及底层 BLUFI 协议栈两种通道都可以并行启用,配网结束后统一由 selector 逻辑接管连接
esp_wifi_service_prov_t *http_agent = NULL;
esp_wifi_service_prov_http_config_t http_cfg = {
.name = "http",
.port = 80,
.profile_manager = profile_manager,
.default_priority = 10,
};
esp_wifi_service_prov_http_create(&http_cfg, &http_agent);
esp_wifi_service_config_t cfg = {
.name = "wifi_service",
.profile_manager = profile_manager,
.prov_list = &http_agent,
.prov_num = 1,
};
esp_wifi_service_t *svc = NULL;
esp_wifi_service_create(&cfg, &svc);
esp_service_start((esp_service_t *)svc);
选择与切换
selector 在多网络环境下自动决策连接哪个 AP:重新评估时先扫描周围 AP,只保留匹配已保存且已启用 profile 的候选项,再按用户优先级、信号质量、最近一次可正常访问的记录,以及临时黑名单排序,而不是简单选择信号最强的 AP。
flowchart TD
Init[服务初始化] --> Check{存在已启用配置}
Check -- 是 --> Selector[启动 selector]
Check -- 否 --> Prov[启动配网通道]
Prov --> Save[接收凭据并保存]
Save --> Selector
Selector --> Scan[扫描候选 AP 并排序]
Scan --> Decide{需要切换}
Decide -- 否 --> Keep[保持当前连接]
Decide -- 是 --> Switch[切换或故障转移]
Switch --> Probe[连接后进行质量探测]
Probe --> Decide2{探测失败或退化}
Decide2 -- 否 --> Keep
Decide2 -- 是 --> Scan
没有找到可用候选网络时,selector 按内置退避表(1000, 5000, 10000, 20000, 30000 ms)重试扫描,可通过 selector_policy.retry 覆盖;应用也可以调用 esp_wifi_service_request_connect() 跳过扫描和重新评估,直接连接一个已保存的 SSID,适合命令行工具或远程管理场景。
网络质量探测
已连接 Wi-Fi 但业务不可用是常见的现场问题:设备已经拿到 IP,但云端接口访问失败、延迟过高或吞吐不足。质量探测覆盖连通性检查(访问指定 URL 判断外部连通性)和延迟/吞吐检查(统计请求耗时和实际吞吐),在连续失败或持续退化后才触发处理,避免因为一次偶发抖动就切换网络;确认退化后,当前 BSSID 会被临时加入黑名单,交由 selector 重新选择候选网络。
应用示例
examples目录下的示例演示 NVS profile 存储、HTTP 配网、自定义 selector 策略的最小接入流程,完整代码可参考组件仓库。
FAQ
Q1:max_connect_retry 设为 0 会一直重试吗?
会。0 表示保持原有行为、持续重试;设为非 0 值后,连续连接失败达到该次数会停止自动重新评估,直到调用 esp_wifi_service_request_connect() 或 esp_wifi_service_request_reeval() 才会重新计数。
API 参考
Header File
Functions
-
esp_err_t esp_wifi_service_create(const esp_wifi_service_config_t *cfg, esp_wifi_service_t **out_service)
Create Wi-Fi service instance.
备注
The caller is responsible for creating the profile manager before calling this function and destroying it after
esp_wifi_service_destroyreturns. The same handle should be passed to each provisioning config so that all components share one profile store.- 参数:
cfg – [in] Required configuration;
profile_managermust be a valid, initialised handleout_service – [out] Created service handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid argument
ESP_ERR_NO_MEM Out of memory
-
esp_err_t esp_wifi_service_destroy(esp_wifi_service_t *service)
Destroy the service.
- 参数:
service – [in] Service handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid argument
-
esp_err_t esp_wifi_service_get_profile_manager(esp_wifi_service_t *service, esp_wifi_service_profile_mgr_t *manager_out)
Get profile manager handle owned by service.
- 参数:
service – [in] Service handle
manager_out – [out] Profile manager handle owned by service
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL argument
-
esp_err_t esp_wifi_service_get_scan_handle(esp_wifi_service_t *service, esp_wifi_service_scan_handle_t *scan_handle_out)
Get the shared scan handle owned by service.
备注
Selector, provisioning transports, and application code should share this agent so scan requests can be coalesced and receive the same driver scan records.
- 参数:
service – [in] Service handle
scan_handle_out – [out] Scan handle owned by service
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL argument
-
esp_err_t esp_wifi_service_start_provisioning(esp_wifi_service_t *service)
Start all provisioning instances.
- 参数:
service – [in] Service handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid argument
Others Provisioning-specific error
-
esp_err_t esp_wifi_service_stop_provisioning(esp_wifi_service_t *service)
Stop all started provisioning instances.
- 参数:
service – [in] Service handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid argument
Others Provisioning-specific error
-
esp_err_t esp_wifi_service_is_provisioning_running(esp_wifi_service_t *service, bool *running_out)
Query provisioning running state.
- 参数:
service – [in] Service handle
running_out – [out] True if any provisioning instance is running
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid argument
-
esp_err_t esp_wifi_service_request_connect(esp_wifi_service_t *service, char *ssid, char *password, uint8_t prio, uint32_t wait_sec)
Save a Wi-Fi profile and request connection to the specified SSID.
备注
This API stores or updates the profile as enabled, stops provisioning, starts the selector if needed, and asks the selector to connect to the specified saved profile directly without running a scan/re-evaluation cycle.
- 参数:
service – [in] Service handle
ssid – [in] NUL-terminated SSID
password – [in] NUL-terminated password; NULL is treated as an empty password
prio – [in] Profile priority, 0 to ::ESP_WIFI_SERVICE_PROFILE_PRIORITY_MAX
wait_sec – [in] Seconds to wait for STA got IP; 0 returns after the request is accepted
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid argument
ESP_ERR_TIMEOUT
wait_secis non-zero and STA did not get IP in timeOthers From profile manager or selector
-
esp_err_t esp_wifi_service_request_reeval(esp_wifi_service_t *service)
Request one Wi-Fi selector re-evaluation cycle.
备注
This API is asynchronous. It returns after the request is accepted, not after scan results are evaluated or a connection decision is completed. If the selector is already running and no re-evaluation is in flight, this API attempts to start a Wi-Fi scan before returning. If a scan/re-evaluation is already in flight, the request is marked pending and runs after the current cycle finishes. If the selector is not running but saved profiles exist, the service starts the selector and schedules evaluation.
- 参数:
service – [in] Service handle
- 返回:
ESP_OK On success or when the request is throttled
ESP_ERR_INVALID_ARG service is NULL
ESP_ERR_NOT_FOUND No Wi-Fi profile is available to evaluate
Others Selector-specific error
Structures
-
struct esp_wifi_service_config_t
Wi-Fi service configuration.
Public Members
-
const char *name
Service instance name for service manager
-
esp_wifi_service_profile_mgr_t profile_manager
Required profile manager handle; created and owned by the caller
-
esp_wifi_service_prov_t *prov_list
Provisioning handle array owned by application
-
size_t prov_num
Number of entries in prov_list
-
const esp_wifi_service_selector_cfg_t *selector_policy
Selector policy; NULL uses selector built-in defaults
-
const char *name
Type Definitions
-
typedef struct esp_wifi_service esp_wifi_service_t
Opaque Wi-Fi service handle.
Enumerations
-
enum esp_wifi_service_event_t
Wi-Fi service event identifiers.
Values:
-
enumerator ESP_WIFI_SERVICE_EVENT_CONNECTED
Wi-Fi service reports connected
-
enumerator ESP_WIFI_SERVICE_EVENT_DISCONNECTED
Wi-Fi service reports disconnected
-
enumerator ESP_WIFI_SERVICE_EVENT_PROV_STARTED
Provisioning transport started
-
enumerator ESP_WIFI_SERVICE_EVENT_PROV_STOPPED
Provisioning transport stopped
-
enumerator ESP_WIFI_SERVICE_EVENT_PROV_PEER_CONNECTED
Provisioning peer connected
-
enumerator ESP_WIFI_SERVICE_EVENT_PROV_PEER_DISCONNECTED
Provisioning peer disconnected
-
enumerator ESP_WIFI_SERVICE_EVENT_PROV_CREDENTIAL_RECEIVED
Provisioning credential received
-
enumerator ESP_WIFI_SERVICE_EVENT_PROV_CUSTOM_DATA_RECEIVED
Provisioning custom data received
-
enumerator ESP_WIFI_SERVICE_EVENT_PROV_ERROR
Provisioning runtime error
-
enumerator ESP_WIFI_SERVICE_EVENT_STA_CONFIG
STA config can be adjusted before connect
-
enumerator ESP_WIFI_SERVICE_EVENT_STA_GOT_IP
Wi-Fi service reports station got IP
-
enumerator ESP_WIFI_SERVICE_EVENT_STA_LOST_IP
Wi-Fi service reports station lost IP
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_CANDIDATE
Selector candidate chosen from scan result
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_SWITCHING
Selector decided to switch/connect
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_SWITCH_FAILED
Selector switch/connect failed
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_BLACKLISTED
Selector blacklisted one BSSID
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_ACCESS_FAILED
Selector probe access check failed
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_LATENCY_DEGRADED
Selector latency check degraded
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_THROUGHPUT_DEGRADED
Selector throughput check degraded
-
enumerator ESP_WIFI_SERVICE_EVENT_SELECTOR_RSSI_LOW
Selector RSSI check is below threshold
-
enumerator ESP_WIFI_SERVICE_EVENT_CONNECTED
Header File
Functions
-
esp_err_t esp_wifi_service_profile_mgr_init(const esp_wifi_service_profile_mgr_cfg_t *cfg, esp_wifi_service_profile_mgr_t *out_handle)
Create profile manager and esp_config_manager handle.
- 参数:
cfg – [in] Configuration;
cfg->storagefrom ::esp_config_storage_init_nvs (or related) and must outlive the profile managerout_handle – [out] Profile manager handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid configuration;
max_profilesmust be greater than 0ESP_ERR_NO_MEM Allocation failure
Others From esp_config_manager
-
void esp_wifi_service_profile_mgr_deinit(esp_wifi_service_profile_mgr_t handle)
Destroy wifi_profile instance.
- 参数:
handle – [in] Profile manager handle
-
esp_err_t esp_wifi_service_profile_mgr_count(esp_wifi_service_profile_mgr_t handle, uint8_t *count_out)
Get number of profiles.
- 参数:
handle – [in] Profile manager handle
count_out – [out] Number of profiles
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL argument
-
esp_err_t esp_wifi_service_profile_mgr_foreach(esp_wifi_service_profile_mgr_t handle, bool (*callback)(const esp_wifi_service_profile_t *profile, void *user_ctx), void *user_ctx)
Iterate all stored profiles in insertion order.
备注
The callback is invoked under the internal lock; it must not call any profile manager API that acquires the same lock.
- 参数:
handle – [in] Profile manager handle
callback – [in] Called for each profile; return
falseto stop earlyuser_ctx – [in] Forwarded to every callback invocation
- 返回:
ESP_OK On success (including early stop by callback)
ESP_ERR_INVALID_ARG NULL argument
-
esp_err_t esp_wifi_service_profile_mgr_get(esp_wifi_service_profile_mgr_t handle, const char *ssid, esp_wifi_service_profile_t *profile_out)
Get profile by SSID.
- 参数:
handle – [in] Profile manager handle
ssid – [in] SSID to match
profile_out – [out] Profile content
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid SSID or NULL handle
ESP_ERR_NOT_FOUND SSID not in store
Others From load/save
-
esp_err_t esp_wifi_service_profile_mgr_add(esp_wifi_service_profile_mgr_t handle, esp_wifi_service_profile_t *profile)
Append or replace by SSID: add credentials, or update if SSID exists.
- 参数:
handle – [in] Profile manager handle
profile – [in] Profile to add or update; caller retains ownership
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Invalid SSID/password/priority or NULL argument
ESP_ERR_NO_MEM Profile table full on add
Others From load/save
-
esp_err_t esp_wifi_service_profile_mgr_set_enabled(esp_wifi_service_profile_mgr_t handle, const char *ssid, bool enabled)
Set profile enabled flag by SSID.
- 参数:
handle – [in] Profile manager handle
ssid – [in] NUL-terminated SSID
enabled – [in] True to enable
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL argument
ESP_ERR_NOT_FOUND SSID not in store
Others From load/save
-
esp_err_t esp_wifi_service_profile_mgr_set_last_working(esp_wifi_service_profile_mgr_t handle, const char *ssid)
Record the last successfully connected profile by SSID.
- 参数:
handle – [in] Profile manager handle
ssid – [in] NUL-terminated SSID; pass NULL or empty string to clear
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL handle
ESP_ERR_NOT_FOUND Non-empty SSID not in store
Others From load/save
-
esp_err_t esp_wifi_service_profile_mgr_get_last_working(esp_wifi_service_profile_mgr_t handle, char *ssid, size_t ssid_len)
Get the SSID of the last successfully connected profile.
- 参数:
handle – [in] Profile manager handle
ssid – [out] Buffer to receive NUL-terminated SSID
ssid_len – [in] Size of ssid; must be at least ::ESP_WIFI_SERVICE_PROFILE_SSID_MAX_LEN + 1
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL argument or ssid_len too small
ESP_ERR_NOT_FOUND No last-working profile recorded
-
esp_err_t esp_wifi_service_profile_mgr_delete(esp_wifi_service_profile_mgr_t handle, const char *ssid)
Delete profile by SSID.
- 参数:
handle – [in] Profile manager handle
ssid – [in] SSID to remove
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL argument
ESP_ERR_NOT_FOUND SSID not found
Others From load/save
-
esp_err_t esp_wifi_service_profile_mgr_clear_all(esp_wifi_service_profile_mgr_t handle)
Remove all profiles and reset store to defaults.
- 参数:
handle – [in] Profile manager handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG NULL handle
Others From load/save
Structures
-
struct esp_wifi_service_profile_t
One saved Wi-Fi profile (filled by provisioning or application)
-
struct esp_wifi_service_profile_mgr_cfg_t
Initialization parameters for ::esp_wifi_service_profile_mgr_init.
Public Members
-
uint8_t max_profiles
Maximum number of profiles to keep; must be greater than 0
-
esp_config_storage_t storage
From esp_config_storage_init_*; must outlive profile manager
-
const esp_config_crypto_ops_t *crypto
NULL: plaintext record except private metadata
-
size_t crypto_extra_size
Extra bytes crypto may add to the profile store
-
uint8_t max_profiles
Macros
-
ESP_WIFI_SERVICE_PROFILE_PRIORITY_MAX
-
ESP_WIFI_SERVICE_PROFILE_SSID_MAX_LEN
-
ESP_WIFI_SERVICE_PROFILE_PASS_MAX_LEN
-
ESP_WIFI_SERVICE_PROFILE_FLAG_ENABLED
Type Definitions
-
typedef void *esp_wifi_service_profile_mgr_t
Opaque handle to wifi_profile instance.