From 5b7a9d39d24a6d30e86a2675876e93f7362c8930 Mon Sep 17 00:00:00 2001 From: ESPHome Device Builder Date: Sat, 11 Jul 2026 17:18:06 +1200 Subject: [PATCH] Add esp-espnow_test_receiver.yaml --- esphome/esp-espnow_test_receiver.yaml | 229 ++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 esphome/esp-espnow_test_receiver.yaml diff --git a/esphome/esp-espnow_test_receiver.yaml b/esphome/esp-espnow_test_receiver.yaml new file mode 100644 index 0000000..68aa12b --- /dev/null +++ b/esphome/esp-espnow_test_receiver.yaml @@ -0,0 +1,229 @@ +#:########################################################################################:# +# ESP-NOW Test Receiver +#:########################################################################################:# +# +# DEVICE: +# ESP32 DevKit V1 / ESP-WROOM-32 +# +# VERSION: +# 1.0 - 2026-07-11 +# - Initial ESP-NOW receiver test build. +# - Receives broadcast packets from ESP32-S3-Zero transmitter. +# - Publishes last sender MAC, payload, RSSI, received count and duplicate count. +# - Creates a short Home Assistant event pulse for each unique press_id. +# +# NOTES: +# - This device is the powered receiver. +# - The transmitter should send the same packet 2-3 times for reliability. +# - This receiver de-duplicates repeated packets using the full payload string. +# - Expected test payload format from transmitter: +# REMOTE_A:BUTTON_1:123 +# +#:########################################################################################:# + +substitutions: + device_name: espnow_test_receiver + friendly_name: "ESPNow Test Receiver" + area: "Test Bench" + +packages: + network: !include common/network_common_dhcp.yaml + +esphome: + name: ${device_name} + friendly_name: ${friendly_name} + area: ${area} + +esp32: + board: esp32dev + framework: + type: arduino + +#:########################################################################################:# +# ESP-NOW Receiver +#:########################################################################################:# +# +# Do not set channel here while using Wi-Fi. +# The receiver's ESP-NOW channel follows the connected Wi-Fi channel. +# + +espnow: + auto_add_peer: true + + on_broadcast: + - then: + - lambda: |- + char src_mac[18]; + snprintf(src_mac, sizeof(src_mac), "%02X:%02X:%02X:%02X:%02X:%02X", + info.src_addr[0], info.src_addr[1], info.src_addr[2], + info.src_addr[3], info.src_addr[4], info.src_addr[5]); + + std::string payload(reinterpret_cast(data), size); + int rssi = info.rx_ctrl ? info.rx_ctrl->rssi : 0; + + id(last_sender_mac).publish_state(src_mac); + id(last_payload).publish_state(payload); + id(last_rssi).publish_state(rssi); + + id(received_count) += 1; + id(received_count_sensor).publish_state(id(received_count)); + + ESP_LOGI("espnow_rx", "ESP-NOW broadcast from %s, RSSI %d dBm, payload: %s", + src_mac, rssi, payload.c_str()); + + // Test payload format: + // REMOTE_A:BUTTON_1:123 + // + // For now, use the whole payload as the duplicate key. + // This means the 2nd and 3rd repeated sends from one button press are ignored. + if (payload == id(last_unique_payload)) { + id(duplicate_count) += 1; + id(duplicate_count_sensor).publish_state(id(duplicate_count)); + id(packet_is_unique) = false; + + ESP_LOGD("espnow_rx", "Duplicate ESP-NOW payload ignored: %s", payload.c_str()); + return; + } + + id(last_unique_payload) = payload; + id(packet_is_unique) = true; + + // Split simple colon-delimited payload for HA visibility. + size_t first_colon = payload.find(':'); + size_t second_colon = payload.find(':', first_colon + 1); + + if (first_colon != std::string::npos && second_colon != std::string::npos) { + std::string remote_id = payload.substr(0, first_colon); + std::string button_id = payload.substr(first_colon + 1, second_colon - first_colon - 1); + std::string press_id = payload.substr(second_colon + 1); + + id(last_remote_id).publish_state(remote_id); + id(last_button_id).publish_state(button_id); + id(last_press_id).publish_state(press_id); + + ESP_LOGI("espnow_rx", "Unique press: remote=%s button=%s press_id=%s", + remote_id.c_str(), button_id.c_str(), press_id.c_str()); + } else { + id(last_remote_id).publish_state("unknown"); + id(last_button_id).publish_state("unknown"); + id(last_press_id).publish_state("unknown"); + + ESP_LOGW("espnow_rx", "Payload did not match expected format: %s", payload.c_str()); + } + + - if: + condition: + lambda: |- + return id(packet_is_unique); + then: + - binary_sensor.template.publish: + id: espnow_unique_press_event + state: ON + - script.execute: clear_unique_press_event + +#:########################################################################################:# +# Globals +#:########################################################################################:# + +globals: + - id: received_count + type: int + restore_value: true + initial_value: '0' + + - id: duplicate_count + type: int + restore_value: true + initial_value: '0' + + - id: last_unique_payload + type: std::string + restore_value: true + initial_value: '""' + + - id: packet_is_unique + type: bool + restore_value: false + initial_value: 'false' + +#:########################################################################################:# +# Scripts +#:########################################################################################:# + +script: + - id: clear_unique_press_event + mode: restart + then: + - delay: 500ms + - binary_sensor.template.publish: + id: espnow_unique_press_event + state: OFF + +#:########################################################################################:# +# Home Assistant Entities +#:########################################################################################:# + +text_sensor: + - platform: template + name: "Last Sender MAC" + id: last_sender_mac + icon: mdi:access-point-network + + - platform: template + name: "Last Payload" + id: last_payload + icon: mdi:message-text + + - platform: template + name: "Last Remote ID" + id: last_remote_id + icon: mdi:remote + + - platform: template + name: "Last Button ID" + id: last_button_id + icon: mdi:gesture-tap-button + + - platform: template + name: "Last Press ID" + id: last_press_id + icon: mdi:identifier + +sensor: + - platform: template + name: "Last RSSI" + id: last_rssi + unit_of_measurement: "dBm" + accuracy_decimals: 0 + icon: mdi:wifi-strength-2 + + - platform: template + name: "Received Count" + id: received_count_sensor + accuracy_decimals: 0 + icon: mdi:counter + + - platform: template + name: "Duplicate Count" + id: duplicate_count_sensor + accuracy_decimals: 0 + icon: mdi:counter + +binary_sensor: + - platform: template + name: "Unique Press Event" + id: espnow_unique_press_event + icon: mdi:gesture-tap-button + +button: + - platform: template + name: "Reset ESP-NOW Test Counts" + icon: mdi:counter + on_press: + then: + - lambda: |- + id(received_count) = 0; + id(duplicate_count) = 0; + id(last_unique_payload) = ""; + id(received_count_sensor).publish_state(0); + id(duplicate_count_sensor).publish_state(0); \ No newline at end of file