feat: Initial esp32-hacking project with firmware sources and docs

This commit is contained in:
user
2026-02-04 12:59:28 +01:00
commit 298e98befb
120 changed files with 22094 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
add_compile_options(-fdiagnostics-color=always)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
string(REGEX REPLACE ".*/\(.*\)" "\\1" CURDIR ${CMAKE_CURRENT_SOURCE_DIR})
project(${CURDIR})
git_describe(PROJECT_VERSION ${COMPONENT_DIR})
message("Project commit: " ${PROJECT_VERSION})

View File

@@ -0,0 +1,79 @@
# Adding Wi-Fi CSI Functionality in ESP RainMaker [[中文]](./README_cn.md)
## Build and Flashing Instructions
Follow the ESP RainMaker documentation [Getting Started](https://rainmaker.espressif.com/docs/get-started.html) section to build and flash the firmware.
## How to Use This Example
### Parameter Description
- **someone_status**: false - no one, true - someone
- **someone_timeout**: If someone moves within this time in the room, it will be marked as someone present. Time is in seconds.
- **move_status**: false - no movement, true - movement
- **move_count**: Number of times movement is detected between the last ESP RainMaker report.
- **move_threshold**: Threshold value to determine if there is movement.
- **filter_window**: Size of the buffer queue for Wi-Fi CSI waveform jitter values, used for filtering outliers.
- **filter_count**: If the jitter value of the Wi-Fi CSI waveform exceeds the `move_threshold` for `filter_count` times within the buffer queue, it is marked as movement detected.
- **threshold_calibrate**: Enable threshold auto-calibration.
- **threshold_calibrate_timeout**: Auto-calibration timeout, in seconds.
### App Version
- ESP RainMaker App: [v2.11.1](https://m.apkpure.com/p/com.espressif.rainmaker)+
> Note: `ESP RainMaker` App version before 2.11.1 does not support `time series` function, `move_count` cannot be displayed normally
### App Operation
1. Open the RainMaker App.
2. Click on `+` to add a device.
3. Wait for the device to connect to the cloud.
4. Enable `threshold_calibrate` to perform auto-calibration. Ensure there is no one or no movement in the room during calibration.
5. After calibration, the threshold value for movement detection will be displayed in `move_threshold`, and `move_status` will become true when movement is detected.
### Device
- [x] ESP32-S3-DevKitC-1
- [x] ESP32-C3-DevKitC
### Device Operation
1. **Factory Reset**: Press and hold the `BOOT` button for more than 5 seconds to reset the development board to factory defaults.
## Device Status
- Human Movement Detection
- Green LED indicates movement detected in the room.
- White LED indicates no movement detected in the room.
- Human Presence Detection
> The current algorithm for human presence detection is not ideal. Therefore, the presence of someone is determined by whether there has been any movement within 1 minute. If there is movement, it is considered someone is present; otherwise, it is considered no one is present.
- LED lights up when there is someone in the room.
- LED turns off when there is no one in the room.
- Human Movement Detection Threshold
> - The threshold for human movement detection can be set via the mobile app or obtained through auto-calibration. If not set, the default value will be used.
> - During calibration, ensure there is no one or no movement in the room. After calibration, the detection sensitivity will be increased. However, if there is movement in the room, it may result in false detection. Therefore, it is recommended to perform calibration when there is no one in the room.
> - The calibrated threshold will be saved in NVS and will be used after the next reboot.
- During human movement threshold calibration, the LED will flash yellow.
## Common Issues
### RainMaker Reporting Failure
------
- **Issue**: The device-side logs show the following error:
```shell
E (399431) esp_rmaker_mqtt: Out of MQTT Budget. Dropping publish message.
```
- **Cause**: The amount of data being reported by the device exceeds the limit of `ESP RainMaker`.
------
- **Issue**: Continuous movement detection without actual movement or the device does not detect any movement.
- **Solution**:
1. Incorrect human movement detection threshold leading to false recognition.
- The default Wi-Fi CSI human movement detection threshold may not meet the actual requirements. Adjust it according to the actual situation or enable auto-calibration through the mobile app.
- The default outlier filtering window size for Wi-Fi CSI may not meet the actual requirements. Adjust it according to the actual situation through the mobile app.
2. Unstable network causing inaccurate detection.
- Check if it works properly after replacing the router.
- Try placing the router in a more suitable location.
3. The above methods still cannot solve the problem, modify the LOG level and submit [issue](https://github.com/espressif/esp-csi/issues) on github
```c
esp_log_level_set("esp_radar", ESP_LOG_DEBUG);
```

View File

@@ -0,0 +1,78 @@
# ESP RainMaker 中添加 Wi-Fi CSI 功能 [[English]](./README.md)
## 编译下载
按照 ESP RainMaker 文档 [入门](https://rainmaker.espressif.com/docs/get-started.html) 部分构建和烧录固件
## 如何使用这个例子
### 参数说明
- **someone_status**: false - 无人, true - 有人
- **someone_timeout**: 房间内在此时间内有人移动则标识为有人,单位为秒
- **move_status**: false - 无人移动, true - 有人移动
- **move_count**: 与上一次上报 `ESP RainMaker` 之间检测到的有人移动的次数
- **move_threshold**: 用于判断是否有人在移动的阈值
- **filter_window**: `Wi-Fi CSI` 的波形的抖动值的缓冲队列的大小,用于过滤异常值
- **filter_count**: 在波形的抖动值的缓冲队列内,当检测到 `filter_count` 次,`Wi-Fi CSI` 的波形的抖动值大于 `move_threshold`,标记为有人移动
- **threshold_calibrate**: 是否使能自校准
- **threshold_calibrate_timeout**: 自校准超时时间,单位为秒
### App 版本
- ESP RainMaker App: [v2.11.1](https://m.apkpure.com/p/com.espressif.rainmaker)+
> 注: `ESP RainMaker` App 2.11.1 版本之前的版本不支持 `time series` 功能,`move_count` 无法正常显示
### APP 操作
1. 打开 RainMaker App
2. 点击 `+` 添加设备
3. 等待设备连接到云端
4. 点击 `threshold_calibrate` 使能自校准,校准时需要保证房间内无人或人不移动
5. 校准完成后,有人移动的阈值会显示在 `move_threshold` 中,此时检测到有人移动 move_status 会变为 true
### 设备
- [x] ESP32-S3-DevKitC-1
- [x] ESP32-C3-DevKitC
### 设备操作
1. **恢复出厂设置**:按住 `BOOT` 按钮 5 秒以上可将开发板重置为出厂默认设置
## 设备状态
- 人体移动检测
- 房间内有人移动: LED 亮绿灯
- 房间内无人移动: LED 亮白灯
- 人体存在检测
> 当前算法人体存在检测效果不理想因此判断是否有人移动的依据是1 分钟内是否有人移动,如果有人移动则认为有人存在,否则认为无人存在
- 房间内有人: LED 亮起
- 房间内无人: LED 熄灭
- 人体移动检测阈值
> - 人体移动检测阈值可以通过手机 App 设置也可以通过自校准获取,如果没有设置则使用默认值
> - 校准时需要保证房间内无人或人不移动,校准后检测灵敏度会提高,但是如果房间内有人移动则会导致误检测,因此建议在房间内无人时进行校准
> - 校准后将会保存在 NVS 中,下次重启后会使用保存的阈值
- 进行人体移动阈值校准时LED 黄色闪烁
## 常见问题
### RainMaker 上报失败
------
- **问题**: 设备端日志上打印如下错误
```shell
E (399431) esp_rmaker_mqtt: Out of MQTT Budget. Dropping publish message.
```
- **原因**: 设备端上报的数据量超过了 `ESP RainMaker` 的限制
------
- **问题**: 一直检测到有人移动但是实际上没有人移动,或者设备端一直检测不到人移动
- **解决方式**:
1. 人体移动检测阈值不对导致误识别
- Wi-Fi CSI 默认人体移动检测阈值无法满足实际需求,需要根据实际情况调整或使能自校准,可以通过手机 App 设置
- Wi-Fi CSI 默认的离群点过滤窗口大小无法满足实际需求,需要根据实际情况调整,可以通过手机 App 设置
2. 网络不稳定导致检测不准确
- 更换路由器后是否能正常工作
- 是否可以尝试将路由器放置在更合适的位置
3. 以上方式仍旧无法解决,修改 LOG 等级,在 github 上提交 [issue](https://github.com/espressif/esp-csi/issues)
```c
esp_log_level_set("esp_radar", ESP_LOG_DEBUG);
```

View File

@@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@@ -0,0 +1,481 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "freertos/timers.h"
#include <esp_log.h>
#include <nvs_flash.h>
#include "ping/ping_sock.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include <esp_rmaker_core.h>
#include <esp_rmaker_standard_params.h>
#include <esp_rmaker_standard_devices.h>
#include <esp_rmaker_schedule.h>
#include <esp_rmaker_scenes.h>
#include <esp_rmaker_utils.h>
#include <esp_rmaker_core.h>
#include <esp_rmaker_common_events.h>
#include <esp_rmaker_standard_types.h>
#include <app_wifi.h>
#include <app_reset.h>
#include "led_strip.h"
#include <iot_button.h>
#include "esp_radar.h"
#include "esp_ping.h"
#if CONFIG_IDF_TARGET_ESP32C5
#define WS2812_GPIO 27
#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61
#define WS2812_GPIO 8
#elif CONFIG_IDF_TARGET_ESP32S3
#define WS2812_GPIO 38
#elif CONFIG_IDF_TARGET_ESP32S2
#define WS2812_GPIO 18
#elif CONFIG_IDF_TARGET_ESP32C3
#define WS2812_GPIO 8
#endif
#ifdef CONFIG_IDF_TARGET_ESP32C3
#define BUTTON_GPIO GPIO_NUM_8
#else
#define BUTTON_GPIO GPIO_NUM_0
#endif
#define BUTTON_WIFI_RESET_TIMEOUT 3
#define BUTTON_FACTORY_RESET_TIMEOUT 5
#define AUTO_CALIBRATE_RAPORT_INTERVAL 5
#define RADAR_PING_DATA_INTERVAL 10
#define RADAR_DETECT_BUFF_MAX_SIZE 16
#define RADAR_PARAM_SOMEONE_STATUS "someone_status"
#define RADAR_PARAM_SOMEONE_TIMEOUT "someone_timeout"
#define RADAR_PARAM_MOVE_STATUS "move_status"
#define RADAR_PARAM_MOVE_COUNT "move_count"
#define RADAR_PARAM_MOVE_THRESHOLD "move_threshold"
#define RADAR_PARAM_FILTER_WINDOW "filter_window"
#define RADAR_PARAM_FILTER_COUNT "filter_count"
#define RADAR_PARAM_THRESHOLD_CALIBRATE "threshold_calibrate"
#define RADAR_PARAM_THRESHOLD_CALIBRATE_TIMEOUT "threshold_calibrate_timeout"
static led_strip_handle_t led_strip;
typedef struct {
bool threshold_calibrate; /**< Self-calibration acquisition, the most suitable threshold, calibration is to ensure that no one is in the room */
uint8_t threshold_calibrate_timeout; /**< Calibration timeout, the unit is second */
float someone_timeout; /**< The unit is second, how long no one moves in the room is marked as no one */
float move_threshold; /**< Use to determine whether someone is moving */
uint8_t filter_window; /**< window without filtering outliers */
uint8_t filter_count; /**< Detect multiple times within the outlier window greater than move_threshold to mark as someone moving */
} radar_detect_config_t;
static const char *TAG = "app_main";
static float g_someone_threshold = 0.002;
static nvs_handle_t g_nvs_handle = 0;
static int32_t g_auto_calibrate_timerleft = 0;
static TimerHandle_t g_auto_calibrate_timerhandle = NULL;
static esp_rmaker_device_t *radar_device = NULL;
static radar_detect_config_t g_detect_config = {
.someone_timeout = 3 * 60,
.move_threshold = 0.002,
.filter_window = 5,
.filter_count = 2,
.threshold_calibrate_timeout = 60,
};
static esp_err_t ping_router_start(uint32_t interval_ms)
{
static esp_ping_handle_t ping_handle = NULL;
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
config.count = 0;
config.timeout_ms = 1000;
config.data_size = 1;
config.interval_ms = interval_ms;
/**
* @brief Get the Router IP information from the esp-netif
*/
esp_netif_ip_info_t local_ip;
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &local_ip);
ESP_LOGI(TAG, "Ping: got ip:" IPSTR ", gw: " IPSTR, IP2STR(&local_ip.ip), IP2STR(&local_ip.gw));
config.target_addr.u_addr.ip4.addr = ip4_addr_get_u32(&local_ip.gw);
config.target_addr.type = ESP_IPADDR_TYPE_V4;
// esp_ping_get_target(PING_TARGET_IP_ADDRESS, &config.target_addr, sizeof(ip_addr_t));
esp_ping_callbacks_t cbs = { 0 };
esp_ping_new_session(&config, &cbs, &ping_handle);
esp_ping_start(ping_handle);
return ESP_OK;
}
static void radar_cb(void *ctx, const wifi_radar_info_t *info)
{
bool someone_status = false;
bool move_status = false;
/**
* @brief Filtering outliers is more accurate using detection,
* but it takes more time, lower sensitive to the environment
*
* @note Current algorithm limitations:
* 1. Calibration is required to detect whether there are people in the room;
* 2. No calibration is required to detect movement, but the sensitivity is higher after calibration
*/
static uint32_t s_buff_count = 0;
static float s_buff_jitter[RADAR_DETECT_BUFF_MAX_SIZE] = {0};
uint32_t buff_max_size = g_detect_config.filter_window;
uint32_t buff_outliers_num = g_detect_config.filter_count;
s_buff_jitter[s_buff_count % buff_max_size] = info->waveform_jitter;
if (++s_buff_count < buff_max_size) {
return;
}
for (int i = 0, move_count = 0; i < buff_max_size; i++) {
if (s_buff_jitter[i] > g_detect_config.move_threshold) {
move_count++;
}
if (move_count >= buff_outliers_num) {
move_status = true;
}
}
someone_status = (info->waveform_jitter > g_someone_threshold) ? true : false;
static uint32_t s_count = 0;
if (!s_count++) {
ESP_LOGI(TAG, "================ RADAR RECV ================");
ESP_LOGI(TAG, "type,sequence,timestamp,waveform_wander,someone_threshold,someone_status,waveform_jitter,move_threshold,move_status\n");
}
ESP_LOGI("RADAR_DADA", "RADAR_DADA,%d,%u,%.6f,%.6f,%d,%.6f,%.6f,%d",
s_count, esp_log_timestamp(),
info->waveform_wander, g_someone_threshold, someone_status,
info->waveform_jitter, g_detect_config.move_threshold, move_status);
/* Calibrate the environment, LED will flash yellow */
if (g_detect_config.threshold_calibrate) {
static bool led_status = false;
if (led_status) {
led_strip_set_pixel(led_strip, 0, 0, 0);
} else {
led_strip_set_pixel(led_strip, 0, 255, 255, 0);
}
led_strip_refresh(led_strip);
led_status = !led_status;
return;
}
/**
* @brief Use LED and LOG to display the detection results
* 1. Someone moves in the room, LED will flash green
* 2. No one moves in the room, LED will flash white
* 3. No one in the room, LED will turn off
*/
static uint32_t s_last_move_time = 0;
static bool s_last_move_status = false;
if (esp_log_timestamp() - s_last_move_time < g_detect_config.someone_timeout * 1000) {
someone_status = true;
} else {
someone_status = false;
}
if (move_status) {
if (move_status != s_last_move_status) {
led_strip_set_pixel(led_strip, 0, 0, 255, 0);
ESP_LOGI(TAG, "someone moves in the room");
}
s_last_move_time = esp_log_timestamp();
} else if (move_status != s_last_move_status) {
ESP_LOGI(TAG, "No one moves in the room");
} else if (esp_log_timestamp() - s_last_move_time > 3 * 1000) {
if (someone_status) {
led_strip_set_pixel(led_strip, 0, 255, 255, 255);
} else {
led_strip_set_pixel(led_strip, 0, 0, 0, 0);
}
}
led_strip_refresh(led_strip);
s_last_move_status = move_status;
/**
* @brief Report the room status to the cloud every 10 seconds or when the room status changes
*/
if (!esp_rmaker_time_check()) {
return;
}
static bool s_report_someone_status = false;
static bool s_report_move_status = false;
static uint32_t s_report_move_count = 0;
static uint32_t s_report_move_timestamp = 0;
s_report_move_count = move_status ? s_report_move_count + 1 : s_report_move_count;
if (s_report_someone_status != someone_status && !someone_status) {
esp_rmaker_param_t *someone_status_param = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_SOMEONE_STATUS);
esp_rmaker_param_update_and_report(someone_status_param, esp_rmaker_bool(someone_status));
s_report_someone_status = someone_status;
}
if (move_status != s_report_move_status
/* Reduce the number of times to report data and reduce server pressure */
|| (move_status && esp_log_timestamp() - s_report_move_timestamp > 10 * 1000)) {
esp_rmaker_param_t *someone_status_param = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_SOMEONE_STATUS);
esp_rmaker_param_update(someone_status_param, esp_rmaker_bool(someone_status));
esp_rmaker_param_t *move_status_param = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_MOVE_STATUS);
esp_rmaker_param_update(move_status_param, esp_rmaker_bool(move_status | (s_report_move_count > 0)));
esp_rmaker_param_t *move_count_param = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_MOVE_COUNT);
esp_rmaker_param_update_and_report(move_count_param, esp_rmaker_int(s_report_move_count));
if (!s_report_move_status || !s_report_move_count) {
s_report_move_status = move_status;
}
s_report_move_count = 0;
s_report_move_timestamp = esp_log_timestamp();
}
}
static esp_err_t radar_start()
{
esp_radar_config_t radar_config = ESP_RADAR_CONFIG_DEFAULT();
#if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61
// radar_config.csi_config.acquire_csi_lltf = true;
// radar_config.csi_config.htltf_en = true;
#else
// radar_config.csi_config.lltf_en = true;
// radar_config.csi_config.htltf_en = true;
#endif
radar_config.dec_config.wifi_radar_cb = radar_cb;
wifi_ap_record_t ap_info = {0x0};
esp_wifi_sta_get_ap_info(&ap_info);
memcpy(radar_config.csi_config.filter_mac, ap_info.bssid, sizeof(ap_info.bssid));
ESP_ERROR_CHECK(esp_radar_csi_init(&radar_config.csi_config));
ESP_ERROR_CHECK(esp_radar_dec_init(&radar_config.dec_config));
esp_radar_start();
return ESP_OK;
}
static void auto_calibrate_timercb(TimerHandle_t timer)
{
g_auto_calibrate_timerleft -= AUTO_CALIBRATE_RAPORT_INTERVAL;
if (g_auto_calibrate_timerleft < AUTO_CALIBRATE_RAPORT_INTERVAL) {
g_auto_calibrate_timerleft = g_detect_config.threshold_calibrate_timeout;
g_detect_config.threshold_calibrate = false;
xTimerStop(g_auto_calibrate_timerhandle, portMAX_DELAY);
esp_radar_train_stop(&g_someone_threshold, &g_detect_config.move_threshold);
esp_rmaker_param_t *move_threshold_param = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_MOVE_THRESHOLD);
esp_rmaker_param_update(move_threshold_param, esp_rmaker_float(g_detect_config.move_threshold));
nvs_set_blob(g_nvs_handle, "detect_config", &g_detect_config, sizeof(radar_detect_config_t));
nvs_commit(g_nvs_handle);
}
esp_rmaker_param_t *param_threshold_calibrate = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_THRESHOLD_CALIBRATE);
esp_rmaker_param_update(param_threshold_calibrate, esp_rmaker_bool(g_detect_config.threshold_calibrate));
esp_rmaker_param_t *param_threshold_calibrate_timeout = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_THRESHOLD_CALIBRATE_TIMEOUT);
esp_rmaker_param_update_and_report(param_threshold_calibrate_timeout, esp_rmaker_int(g_auto_calibrate_timerleft));
}
/* Callback to handle commands received from the RainMaker cloud */
static esp_err_t write_cb(const esp_rmaker_device_t *device, const esp_rmaker_param_t *param,
const esp_rmaker_param_val_t val, void *priv_data, esp_rmaker_write_ctx_t *ctx)
{
const char *param_name = esp_rmaker_param_get_name(param);
if (strcmp(param_name, RADAR_PARAM_SOMEONE_TIMEOUT) == 0) {
g_detect_config.someone_timeout = val.val.i;
} else if (strcmp(param_name, RADAR_PARAM_MOVE_THRESHOLD) == 0) {
g_detect_config.move_threshold = val.val.f;
} else if (strcmp(param_name, RADAR_PARAM_FILTER_WINDOW) == 0) {
g_detect_config.filter_window = val.val.i;
} else if (strcmp(param_name, RADAR_PARAM_FILTER_COUNT) == 0) {
g_detect_config.filter_count = val.val.i;
} else if (strcmp(param_name, RADAR_PARAM_THRESHOLD_CALIBRATE) == 0) {
g_detect_config.threshold_calibrate = val.val.b;
if (!g_auto_calibrate_timerhandle) {
g_auto_calibrate_timerhandle = xTimerCreate("auto_calibrate", pdMS_TO_TICKS(AUTO_CALIBRATE_RAPORT_INTERVAL * 1000),
true, NULL, auto_calibrate_timercb);
}
if (g_detect_config.threshold_calibrate) {
g_auto_calibrate_timerleft = g_detect_config.threshold_calibrate_timeout;
xTimerStart(g_auto_calibrate_timerhandle, portMAX_DELAY);
esp_radar_train_start();
} else {
g_auto_calibrate_timerleft = 0;
auto_calibrate_timercb(NULL);
}
} else if (strcmp(param_name, RADAR_PARAM_THRESHOLD_CALIBRATE_TIMEOUT) == 0) {
g_detect_config.threshold_calibrate_timeout = val.val.i;
} else {
ESP_LOGE(TAG, "Unhandled parameter '%s'", param_name);
/* Silently ignoring invalid params */
return ESP_OK;
}
esp_rmaker_param_update_and_report(param, val);
nvs_set_blob(g_nvs_handle, "detect_config", &g_detect_config, sizeof(radar_detect_config_t));
nvs_commit(g_nvs_handle);
return ESP_OK;
}
esp_err_t ws2812_led_init(void)
{
led_strip_config_t strip_config = {
.strip_gpio_num = WS2812_GPIO,
.max_leds = 1,
};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption
.resolution_hz = 10 * 1000 * 1000, // RMT counter clock frequency: 10MHz
.flags = {
.with_dma = false, // DMA feature is available on chips like ESP32-S3/P4
}
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
/* Set all LED off to clear all pixels */
led_strip_clear(led_strip);
return ESP_OK;
}
void app_main()
{
/* Initialize Application specific hardware drivers and set initial state */
ws2812_led_init();
button_handle_t btn_handle = iot_button_create(BUTTON_GPIO, BUTTON_ACTIVE_LOW);
app_reset_button_register(btn_handle, BUTTON_WIFI_RESET_TIMEOUT, BUTTON_FACTORY_RESET_TIMEOUT);
/* Initialize NVS. */
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);
nvs_open("wifi_radar", NVS_READWRITE, &g_nvs_handle);
size_t detect_config_size = sizeof(radar_detect_config_t);
nvs_get_blob(g_nvs_handle, "detect_config", &g_detect_config, &detect_config_size);
/* Reduced output log */
// esp_log_level_set("esp_radar", ESP_LOG_WARN);
esp_log_level_set("RADAR_DADA", ESP_LOG_WARN);
/* Initialize Wi-Fi. Note that, this should be called before esp_rmaker_node_init() */
app_wifi_init();
/* Initialize the ESP RainMaker Agent */
esp_rmaker_config_t rainmaker_cfg = {
.enable_time_sync = true,
};
esp_rmaker_node_t *node = esp_rmaker_node_init(&rainmaker_cfg, "ESP Wi-Fi CSI Device", "Wi-Fi Radar");
if (!node) {
ESP_LOGE(TAG, "Could not initialise node. Aborting!!!");
vTaskDelay(pdMS_TO_TICKS(5000));
abort();
}
/* Create a device and add the relevant parameters to it */
radar_device = esp_rmaker_device_create("Sensor Light", ESP_RMAKER_DEVICE_LIGHTBULB, NULL);
ESP_ERROR_CHECK(esp_rmaker_device_add_cb(radar_device, write_cb, NULL));
typedef struct {
const char *param_name;
uint8_t properties;
const char *ui_type;
esp_rmaker_param_val_t val;
esp_rmaker_param_val_t min;
esp_rmaker_param_val_t max;
esp_rmaker_param_val_t step;
} radar_param_t;
esp_rmaker_param_val_t invalid_val = {.type = RMAKER_VAL_TYPE_INVALID};
radar_param_t radar_param_list[] = {
{RADAR_PARAM_THRESHOLD_CALIBRATE, PROP_FLAG_READ | PROP_FLAG_WRITE, ESP_RMAKER_UI_TOGGLE, esp_rmaker_bool(g_detect_config.threshold_calibrate), invalid_val, invalid_val, invalid_val},
{RADAR_PARAM_THRESHOLD_CALIBRATE_TIMEOUT, PROP_FLAG_READ | PROP_FLAG_WRITE, ESP_RMAKER_UI_TEXT, esp_rmaker_int(g_detect_config.threshold_calibrate_timeout), esp_rmaker_int(10), esp_rmaker_int(3600), esp_rmaker_int(10)},
{RADAR_PARAM_MOVE_THRESHOLD, PROP_FLAG_READ | PROP_FLAG_WRITE, ESP_RMAKER_UI_TEXT, esp_rmaker_float(g_detect_config.move_threshold), esp_rmaker_float(0.01), esp_rmaker_float(0.1), esp_rmaker_float(0.01)},
{RADAR_PARAM_MOVE_STATUS, PROP_FLAG_READ, ESP_RMAKER_UI_TEXT, esp_rmaker_bool(false), invalid_val, invalid_val, invalid_val},
{RADAR_PARAM_MOVE_COUNT, PROP_FLAG_READ | PROP_FLAG_TIME_SERIES, ESP_RMAKER_UI_TEXT, esp_rmaker_int(0), esp_rmaker_int(0), esp_rmaker_int(100), esp_rmaker_int(1)},
{RADAR_PARAM_SOMEONE_STATUS, PROP_FLAG_READ, ESP_RMAKER_UI_TEXT, esp_rmaker_bool(false), invalid_val, invalid_val, invalid_val},
{RADAR_PARAM_SOMEONE_TIMEOUT, PROP_FLAG_READ | PROP_FLAG_WRITE, ESP_RMAKER_UI_TEXT, esp_rmaker_int(g_detect_config.someone_timeout), esp_rmaker_int(10), esp_rmaker_int(3600), esp_rmaker_int(10)},
{RADAR_PARAM_FILTER_WINDOW, PROP_FLAG_READ | PROP_FLAG_WRITE, ESP_RMAKER_UI_TEXT, esp_rmaker_int(g_detect_config.filter_window), esp_rmaker_int(1), esp_rmaker_int(16), esp_rmaker_int(1)},
{RADAR_PARAM_FILTER_COUNT, PROP_FLAG_READ | PROP_FLAG_WRITE, ESP_RMAKER_UI_TEXT, esp_rmaker_int(g_detect_config.filter_count), esp_rmaker_int(1), esp_rmaker_int(16), esp_rmaker_int(1)},
};
for (int i = 0; i < sizeof(radar_param_list) / sizeof(radar_param_list[0]); ++i) {
char radar_param_type[64] = "esp.param.";
strcat(radar_param_type, radar_param_list[i].param_name);
esp_rmaker_param_t *param = esp_rmaker_param_create(radar_param_list[i].param_name, radar_param_type,
radar_param_list[i].val, radar_param_list[i].properties);
if (radar_param_list[i].ui_type) {
esp_rmaker_param_add_ui_type(param, radar_param_list[i].ui_type);
}
if (radar_param_list[i].min.type != RMAKER_VAL_TYPE_INVALID) {
esp_rmaker_param_add_bounds(param, radar_param_list[i].min, radar_param_list[i].max, radar_param_list[i].step);
}
ESP_ERROR_CHECK(esp_rmaker_device_add_param(radar_device, param));
}
esp_rmaker_param_t *move_count_param = esp_rmaker_device_get_param_by_name(radar_device, RADAR_PARAM_MOVE_COUNT);
esp_rmaker_device_assign_primary_param(radar_device, move_count_param);
ESP_ERROR_CHECK(esp_rmaker_node_add_device(node, radar_device));
/* Enable OTA */
ESP_ERROR_CHECK(esp_rmaker_ota_enable_default());
/* Enable timezone service which will be require for setting appropriate timezone
* from the phone apps for scheduling to work correctly.
* For more information on the various ways of setting timezone, please check
* https://rainmaker.espressif.com/docs/time-service.html.
*/
esp_rmaker_timezone_service_enable();
/* Enable scheduling. */
esp_rmaker_schedule_enable();
/* Enable Scenes */
esp_rmaker_scenes_enable();
/* Start the ESP RainMaker Agent */
esp_rmaker_start();
/* Start the Wi-Fi./
* If the node is provisioned, it will start connection attempts,
* else, it will start Wi-Fi provisioning. The function will return
* after a connection has been successfully established
*/
err = app_wifi_start(POP_TYPE_NONE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not start Wifi. Aborting!!!");
vTaskDelay(pdMS_TO_TICKS(5000));
abort();
}
/**
* @brief Enable Wi-Fi Radar Detection
*/
radar_start();
ping_router_start(RADAR_PING_DATA_INTERVAL);
}

View File

@@ -0,0 +1,32 @@
## IDF Component Manager Manifest File
dependencies:
idf: '>=4.4.1'
esp-radar:">=0.3.0"
espressif/rmaker_common: 1.4.*
espressif/json_generator: ^1
espressif/json_parser: =1.0.0
espressif/esp_rainmaker:
path: components/esp_rainmaker
git: https://github.com/espressif/esp-rainmaker.git
version: ff0dd329020a52ae8cf2fb4f6800d9f8e9cc9eeb
espressif/led_strip: "^2.5.3"
espressif/qrcode:
path: components/qrcode
git: https://github.com/espressif/esp-rainmaker.git
version: ff0dd329020a52ae8cf2fb4f6800d9f8e9cc9eeb
espressif/gpio_button:
path: components/gpio_button
git: https://github.com/espressif/esp-rainmaker.git
version: ff0dd329020a52ae8cf2fb4f6800d9f8e9cc9eeb
espressif/app_wifi:
path: examples/common/app_wifi
git: https://github.com/espressif/esp-rainmaker.git
version: ff0dd329020a52ae8cf2fb4f6800d9f8e9cc9eeb
espressif/app_reset:
path: examples/common/app_reset
git: https://github.com/espressif/esp-rainmaker.git
version: ff0dd329020a52ae8cf2fb4f6800d9f8e9cc9eeb
espressif/esp_schedule:
version: ^1.2.0

View File

@@ -0,0 +1,8 @@
# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0xd000, 32K,
fctry, data, nvs, 0x15000, 16K,
log_status, data, nvs, 0x19000, 16K,
otadata, data, ota, 0x1d000, 8K,
phy_init, data, phy, 0x1f000, 4K,
ota_0, app, ota_0, 0x20000, 1832K,
1 # Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table
2 # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0xd000, 32K,
4 fctry, data, nvs, 0x15000, 16K,
5 log_status, data, nvs, 0x19000, 16K,
6 otadata, data, ota, 0x1d000, 8K,
7 phy_init, data, phy, 0x1f000, 4K,
8 ota_0, app, ota_0, 0x20000, 1832K,

View File

@@ -0,0 +1,19 @@
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_OFFSET=0x9000
CONFIG_ESP_RMAKER_USER_ID_CHECK=y
CONFIG_ESP_RMAKER_LOCAL_CTRL_ENABLE=y
CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESP_TASK_WDT_TIMEOUT_S=30
CONFIG_ESP_WIFI_CSI_ENABLED=y
# CONFIG_ESP_WIFI_AMPDU_TX_ENABLED is not set
# CONFIG_ESP_WIFI_AMPDU_RX_ENABLED is not set
# CONFIG_ESP_WIFI_IRAM_OPT is not set
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y