/* * 面向 ESP32 的 ESP-NOW 示例 * 无需 Wi-Fi 路由器的点对点无线通信和广播 * * ESP-IDF 内置的原生协议 */ #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_wifi.h" #include "esp_now.h" #include "esp_log.h" #include "nvs_flash.h" static const char *TAG = "esp_now_demo"; // 数据包中发送的数据结构 typedef struct { uint32_t sensor_id; float temperatura; float umidade; uint32_t tempo_ms; } __attribute__((packed)) dados_pacote_t; // 广播 MAC 地址(发送给附近所有 ESP-NOW 节点) static const uint8_t broadcast_mac[ESP_NOW_ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* 发送数据包时执行的回调 */ static void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) { ESP_LOGI(TAG, "Send complete: %s", status == ESP_NOW_SEND_SUCCESS ? "SUCCESS (ACK)" : "FAILURE"); } /* 接收其他 ESP32 数据包时执行的回调 */ static void on_data_recv(const esp_now_recv_info_t *recv_info, const uint8_t *data, int len) { if (len == sizeof(dados_pacote_t)) { dados_pacote_t *pct = (dados_pacote_t *)data; ESP_LOGI(TAG, "Packet received from [%02X:%02X:%02X:%02X:%02X:%02X]: Sensor #%ld | Temp: %.1f C | Humidity: %.1f %%", recv_info->src_addr[0], recv_info->src_addr[1], recv_info->src_addr[2], recv_info->src_addr[3], recv_info->src_addr[4], recv_info->src_addr[5], pct->sensor_id, pct->temperatura, pct->umidade); } } void app_main(void) { // 以 Station 模式初始化 NVS 和 Wi-Fi nvs_flash_init(); esp_netif_init(); esp_event_loop_create_default(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(&cfg); esp_wifi_set_mode(WIFI_MODE_STA); esp_wifi_start(); // 初始化 ESP-NOW 协议 ESP_ERROR_CHECK(esp_now_init()); esp_now_register_send_cb(on_data_sent); esp_now_register_recv_cb(on_data_recv); // 注册广播对端 esp_now_peer_info_t peer_info = { .channel = 1, .ifidx = WIFI_IF_STA, .encrypt = false, }; memcpy(peer_info.peer_addr, broadcast_mac, ESP_NOW_ETH_ALEN); ESP_ERROR_CHECK(esp_now_add_peer(&peer_info)); ESP_LOGI(TAG, "ESP-NOW ready! Sending telemetry every 3 seconds..."); dados_pacote_t telemetria = { .sensor_id = 101, .temperatura = 24.8f, .umidade = 58.2f, }; while (1) { telemetria.tempo_ms = esp_log_timestamp(); telemetria.temperatura += ((float)(rand() % 10) - 5.0f) / 10.0f; esp_err_t res = esp_now_send(broadcast_mac, (uint8_t *)&telemetria, sizeof(telemetria)); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to send ESP-NOW packet: %d", res); } vTaskDelay(pdMS_TO_TICKS(3000)); } }