#:########################################################################################:# # ESP-NOW Test Transmitter #:########################################################################################:# # # DEVICE: # ESP32-S3-Zero / ESP32-S3 Super Mini # # VERSION: # 1.1 - 2026-07-11 # - Removed duplicate GPIO4 binary sensor declaration. # - GPIO4 is now used only as the deep-sleep wake pin. # - Added KEEP_AWAKE handling while the wake button remains pressed. # - Uses a random press ID rather than flash-backed press counting. # - Sends each button press three times for improved reliability. # - Configured ESP-NOW to use Wi-Fi channel 5. # # WIRING: # GPIO4 ---- momentary button ---- GND # # OPERATION: # - Initial power-up or reset causes one test transmission. # - The ESP32 then enters deep sleep. # - Pressing the button pulls GPIO4 LOW and wakes the ESP32. # - The ESP32 broadcasts the same message three times. # - It waits until the button is released and returns to deep sleep. # # MESSAGE FORMAT: # REMOTE_A:BUTTON_1:123456789 # # IMPORTANT: # - The receiver must be operating on Wi-Fi channel 5. # - This transmitter intentionally has no Wi-Fi, API or OTA configuration. # - Future updates will normally be installed by USB. # #:########################################################################################:# substitutions: device_name: esp-espnow-test-transmitter1 friendly_name: "ESPNow Test Transmitter 1" remote_id: "REMOTE_A" button_id: "BUTTON_1" espnow_channel: "5" wake_pin: "4" #:########################################################################################:# # ESPHome Core #:########################################################################################:# esphome: name: ${device_name} friendly_name: ${friendly_name} on_boot: priority: -100 then: - logger.log: level: INFO format: "ESP-NOW transmitter booted." - lambda: |- id(press_id) = esp_random(); char payload_buffer[96]; snprintf( payload_buffer, sizeof(payload_buffer), "${remote_id}:${button_id}:%lu", static_cast(id(press_id)) ); id(transmit_payload) = payload_buffer; ESP_LOGI( "espnow_tx", "Prepared payload: %s", id(transmit_payload).c_str() ); - script.execute: send_espnow_press - script.wait: send_espnow_press - logger.log: level: INFO format: "Transmission sequence finished. Entering deep sleep." - delay: 250ms - deep_sleep.enter: deep_sleep_control #:########################################################################################:# # ESP32 Hardware #:########################################################################################:# esp32: variant: esp32s3 framework: type: esp-idf #:########################################################################################:# # Logging #:########################################################################################:# # # USB serial logging is useful during initial testing. # It does consume some power while the device is awake, but awake time is brief. # logger: level: DEBUG #:########################################################################################:# # ESP-NOW #:########################################################################################:# # # The transmitter is not joining Wi-Fi, so the ESP-NOW radio channel must be # configured explicitly. # espnow: channel: ${espnow_channel} #:########################################################################################:# # Globals #:########################################################################################:# globals: - id: press_id type: uint32_t restore_value: false initial_value: '0' - id: transmit_payload type: std::string restore_value: false initial_value: '""' #:########################################################################################:# # ESP-NOW Transmission Script #:########################################################################################:# script: - id: send_espnow_press mode: single then: - logger.log: level: INFO format: "Sending ESP-NOW broadcast 1 of 3." - espnow.broadcast: data: !lambda |- return std::vector( id(transmit_payload).begin(), id(transmit_payload).end() ); wait_for_sent: true continue_on_error: true on_sent: - logger.log: level: DEBUG format: "Broadcast 1 sent." on_error: - logger.log: level: WARN format: "Broadcast 1 reported an error." - delay: 50ms - logger.log: level: INFO format: "Sending ESP-NOW broadcast 2 of 3." - espnow.broadcast: data: !lambda |- return std::vector( id(transmit_payload).begin(), id(transmit_payload).end() ); wait_for_sent: true continue_on_error: true on_sent: - logger.log: level: DEBUG format: "Broadcast 2 sent." on_error: - logger.log: level: WARN format: "Broadcast 2 reported an error." - delay: 50ms - logger.log: level: INFO format: "Sending ESP-NOW broadcast 3 of 3." - espnow.broadcast: data: !lambda |- return std::vector( id(transmit_payload).begin(), id(transmit_payload).end() ); wait_for_sent: true continue_on_error: true on_sent: - logger.log: level: DEBUG format: "Broadcast 3 sent." on_error: - logger.log: level: WARN format: "Broadcast 3 reported an error." #:########################################################################################:# # Deep Sleep and Wake Button #:########################################################################################:# # # GPIO4 is pulled HIGH internally. # Pressing the button connects GPIO4 to GND and wakes the ESP32. # # KEEP_AWAKE prevents an immediate sleep/wake loop if the button is still held # when the transmission sequence finishes. # deep_sleep: id: deep_sleep_control wakeup_pin: number: GPIO${wake_pin} mode: input: true pullup: true inverted: true wakeup_pin_mode: KEEP_AWAKE