#:########################################################################################:# # ESP-NOW Test Transmitter 1 #:########################################################################################:# # # DEVICE: # ESP32-S3-Zero / ESP32-S3 Super Mini # # VERSION: # 1.2 - 2026-07-11 # - Changed GPIO4 wake source to ESP32 EXT1 ANY_LOW. # - Added delay to allow ESP-NOW to initialise before transmission. # - Added GPIO4 input and pull-up initialisation. # - Waits for the wake button to be released before entering deep sleep. # - Logs the ESP32 wake cause. # - Sends each message three times for improved broadcast reliability. # # WIRING: # # 3.3 V # | # 10 kΩ # | # +-------- GPIO4 # | # Push button # | # GND # # OPERATION: # - Power-up or reset causes one transmission. # - The transmitter sends the same ESP-NOW message three times. # - It waits for GPIO4 to return HIGH. # - It then enters deep sleep. # - Pulling GPIO4 LOW wakes the transmitter and repeats the sequence. # # MESSAGE FORMAT: # REMOTE_A:BUTTON_1: # # IMPORTANT: # - ESP-NOW channel must match the receiver network channel. # - The receiver is currently operating on channel 5. # - This transmitter deliberately does not connect to normal Wi-Fi. # - Firmware updates are performed 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_gpio: "4" #:########################################################################################:# # ESPHome Core #:########################################################################################:# esphome: name: ${device_name} friendly_name: ${friendly_name} on_boot: priority: -100 then: - lambda: |- // Explicitly configure GPIO4 as an input with a pull-up. gpio_set_direction(GPIO_NUM_4, GPIO_MODE_INPUT); gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); const esp_sleep_wakeup_cause_t wake_cause = esp_sleep_get_wakeup_cause(); ESP_LOGI( "wake", "ESP-NOW transmitter booted. Wake cause: %d", static_cast(wake_cause) ); if (wake_cause == ESP_SLEEP_WAKEUP_EXT1) { ESP_LOGI("wake", "Wake was caused by the GPIO4 EXT1 input."); } else if (wake_cause == ESP_SLEEP_WAKEUP_UNDEFINED) { ESP_LOGI("wake", "Wake was caused by power-up or reset."); } else { ESP_LOGI( "wake", "Wake was caused by another source: %d", static_cast(wake_cause) ); } # Allow all ESPHome components, including ESP-NOW, to finish setup. - delay: 750ms - 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 completed." # Do not enter sleep while GPIO4 is still held LOW. - logger.log: level: INFO format: "Waiting for GPIO4 button release." - wait_until: condition: lambda: |- return gpio_get_level(GPIO_NUM_4) == 1; - delay: 100ms - logger.log: level: INFO format: "GPIO4 released. Entering deep sleep." - delay: 100ms - deep_sleep.enter: deep_sleep_control #:########################################################################################:# # ESP32 Hardware #:########################################################################################:# esp32: board: esp32-s3-devkitc-1 framework: type: esp-idf #:########################################################################################:# # Logging #:########################################################################################:# logger: level: DEBUG #:########################################################################################:# # ESP-NOW #:########################################################################################:# # # The transmitter does not connect to Wi-Fi, so its radio channel is set # explicitly. Both transmitter and receiver must use the same channel. # espnow: channel: ${espnow_channel} enable_on_boot: true #:########################################################################################:# # 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 submitted successfully." on_error: - logger.log: level: WARN format: "Broadcast 1 reported an error." - delay: 75ms - 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 submitted successfully." on_error: - logger.log: level: WARN format: "Broadcast 2 reported an error." - delay: 75ms - 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 submitted successfully." on_error: - logger.log: level: WARN format: "Broadcast 3 reported an error." - delay: 75ms #:########################################################################################:# # Deep Sleep and GPIO4 Wake #:########################################################################################:# # # ESP32-S3 supports EXT1 ANY_LOW wake. # # With one configured pin, ANY_LOW means: # Wake when GPIO4 is pulled LOW. # # An external 10 kΩ pull-up between GPIO4 and 3.3 V is recommended. # deep_sleep: id: deep_sleep_control esp32_ext1_wakeup: pins: - GPIO${wake_gpio} mode: ANY_LOW