Cannot Find Good ESP-NOW Config For One-Way Communication

Attempting to design (simple) indoor/outdoor temperature monitoring device. I’ve assembled two ESP32 (Dev) boards with AHT20 temperature/humidity sensors. I envision the ‘receiver’ device#1 to measure indoor temperature, receive outdoor temperature from device#2, and report/display both values. Both devices appear to be working independently as expected.
Using ESPHome to build the yaml files. Pulled (what should have been) a simple set of instructions to implement ESPNOW from ESPHome.

https://esphome.io/components/packet_transport/espnow/

It appears that my device#2 (Provider) is functioning properly. It reports temp/humidity as expected, but indicates failure to transmit data to device#1. I suspect device#1 to be configured incorrectly. Specifically, for device#1 (Consumer), packet_transport: providers: - name: The example says to use ‘Provider device name’, but this does not seem to work. Anyone got some insight on this?

It’s your code…

Care to share [properly formatted with </> forum readability please]?

Any meaningful information from the ESPHome compile and run log?

The intended ‘sending’ (outdoor) temperature monitoring device …

esphome:
name: outdoor-temp-xmtr
friendly_name: Outdoor Temp Transmitter

esp32:
board: esp32dev
framework:
type: esp-idf

Enable logging

logger:

Enable Home Assistant API

api:
encryption:
key: “Encryption Key”

ota:

  • platform: esphome
    password: “Password”

wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password

Enable fallback hotspot (captive portal) in case wifi connection fails

ap:
ssid: “Outdoor-Temp-Xmtr”
password: “sUZPXY71P557”

captive_portal:

 # Add component definitions here

i2c:
sda: GPIO21
scl: GPIO22

espnow:
peers:
“00:00:00:00:00:00” #Receiver MAC Address

packet_transport:

  • platform: espnow
    peer_address: “00:00:00:00:00:00” #Receiver MAC Address
    sensors:
    • out_temp_f

sensor:

  • platform: aht10 #Add Temperature/Humidity Sensor AHT20
    variant: AHT20
    address: 0x38
    temperature:
    filters:
    • lambda: return x * (9.0/5.0) + 32.0; #Convert temperature to degrees F
      unit_of_measurement: “°F”
      id: out_temp_f
      name: “Outdoor Temp”
      humidity:
      id: out_hmty
      name: “Outdoor Hmty”
      update_interval: 10s

font:

  • file: “gfonts://Rubik@500”
    id: font1
    size: 18
  • file: “gfonts://Rubik@500”
    id: font2
    size: 20

display:

  • platform: ssd1306_i2c
    model: SSD1306_128X64
    address: 0x3C
    lambda: |-
    it.printf(0, 10, id(font1), “Outdoor Temp %.1f °F”, id(out_temp_f).state);
    it.printf(0, 40, id(font1), “Outdoor Hmty %.1f RH”, id(out_hmty).state);
The intended 'receiving' (indoor) temperature monitoring device ...

esphome:
name: indoor-temp-rcvr
friendly_name: indoor-temp-rcvr

esp32:
board: esp32dev
framework:
type: esp-idf

Enable logging

logger:

Enable Home Assistant API

api:
encryption:
key: “Encryption Key”

ota:

  • platform: esphome
    password: “Password”

wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password

Enable fallback hotspot (captive portal) in case wifi connection fails

ap:
ssid: “Indoor-Temp-Rcvr”
password: “wjxcXprF05aB”

captive_portal:

Add component definitions here

i2c:
sda: GPIO21
scl: GPIO22

espnow:
peers:
- “00:00:00:00:00:00” #Sender MAC Address

packet_transport:

  • platform: espnow
    providers:
    • name: outdoor-temp-xmtr

sensor:

  • platform: aht10 #Add Temperature/Humidity Sensor AHT20
    variant: AHT20
    address: 0x38
    temperature:
    filters:
    - lambda: return x * (9.0/5.0) + 32.0; #Convert temperature to degrees F
    unit_of_measurement: “°F”
    id: in_temp_f
    name: “Indoor Temp”
    humidity:
    id: in_hmty
    name: “Indoor Hmty”
    update_interval: 10s
  • platform: packet_transport
    provider: outdoor-temp-xmtr
    id: remote_temp
    remote_id: out_temp_f
    name: “Remote Outdoor Temperature”

font:

  • file: “gfonts://Rubik@500”
    id: font1
    size: 18
  • file: “gfonts://Rubik@500”
    id: font2
    size: 20

#display:

- platform: ssd1306_i2c

model: SSD1306_128X64

address: 0x3C

lambda: |-

it.printf(0, 10, id(font1), “In Temp %.1f °F”, id(in_temp_f).state);

it.printf(0, 40, id(font1), “In Hmty %.1f RH”, id(in_hmty).state);

</> did not seem to function as intended.

triple back-tic ```
all by itself at the beginning of the line is how you do a multi-line quote of your code and another after it

outdoor-temp-xmtr file appears to validate, compile, and upload without incident. Below see partial results of log showing reporting of temperature and relative humidity, and Send failure.

[19:27:56.944][C][espnow:133]:   Version: v2
[19:27:56.944][C][espnow:133]:   Wi-Fi channel: 10
[19:27:56.947][C][espnow:139]:   Wi-Fi enabled: YES
[19:28:04.875][W][espnow.transport:054]: Send failed: 1
[19:28:04.937][S][sensor]: 'Outdoor Temp' >> 72.65 °F
[19:28:04.937][S][sensor]: 'Outdoor Hmty' >> 54.49 %
[19:28:07.603][W][espnow.transport:054]: Send failed: 1
[19:28:14.872][W][espnow.transport:054]: Send failed: 1
[19:28:14.935][S][sensor]: 'Outdoor Temp' >> 72.68 °F
[19:28:14.936][S][sensor]: 'Outdoor Hmty' >> 54.38 %
[19:28:22.605][W][espnow.transport:054]: Send failed: 1
[19:28:24.936][S][sensor]: 'Outdoor Temp' >> 72.68 °F
[19:28:24.937][S][sensor]: 'Outdoor Hmty' >> 54.28 %

indoor-temp-rcvr (reciever) file does not validate! Error returned below…

tINFO ESPHome 2026.4.1
INFO Reading configuration /config/indoor-temp-rcvr.yaml...
Failed config

sensor.packet_transport: [source /config/indoor-temp-rcvr.yaml:62]
  
  Must provide internal: config when using name:.
  platform: packet_transport
  provider: outdoor-temp-xmtr
  id: remote_temp
  remote_id: out_temp_f
  name: Remote Outdoor Temperature

Thanks Neel,
That’s what I attempted. Backfired on me the first time. Crazy. Second transmission appears to have worked.

On review, it appears that my files (submitted above) do not accurately reflect line indents critical to the yaml file. Below, please find a second attempt to post these (using </>) appropriately.
File for the Outdoor (intended as ‘Sending’) device…

esphome:
  name: outdoor-temp-xmtr
  friendly_name: Outdoor Temp Transmitter

esp32:
  board: esp32dev
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "Encryption Key"

ota:
  - platform: esphome
    password: "Password"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Outdoor-Temp-Xmtr"
    password: "sUZPXY71P557"

captive_portal:
    
     # Add component definitions here

i2c:
  sda: GPIO21
  scl: GPIO22

espnow:
  peers:
    "00:00:00:00:00:00"  #Receiver MAC Address

packet_transport:
  - platform: espnow
    peer_address: "00:00:00:00:00:00"  #Receiver MAC Address
    sensors: 
      - out_temp_f
              
sensor:
  - platform: aht10  #Add Temperature/Humidity Sensor AHT20
    variant: AHT20
    address: 0x38
    temperature:
      filters:
      - lambda: return x * (9.0/5.0) + 32.0;  #Convert temperature to degrees F
      unit_of_measurement: "°F"  
      id: out_temp_f
      name: "Outdoor Temp"
    humidity:
      id: out_hmty
      name: "Outdoor Hmty"
    update_interval: 10s

font:
  - file: "gfonts://Rubik@500"
    id: font1
    size: 18
  - file: "gfonts://Rubik@500"
    id: font2
    size: 20

display:
  - platform: ssd1306_i2c
    model: SSD1306_128X64
    address: 0x3C
    lambda: |-
      it.printf(0, 10, id(font1), "Outdoor Temp %.1f °F", id(out_temp_f).state);
      it.printf(0, 40, id(font1), "Outdoor Hmty %.1f RH", id(out_hmty).state);

File for the Indoor (intended as ‘Receiving’) device…

esphome:
  name: indoor-temp-rcvr
  friendly_name: indoor-temp-rcvr

esp32:
  board: esp32dev
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "Encryption Key"

ota:
  - platform: esphome
    password: "Password"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Indoor-Temp-Rcvr"
    password: "wjxcXprF05aB"

captive_portal:

 # Add component definitions here

i2c:
  sda: GPIO21
  scl: GPIO22

espnow:
  peers: 
    - "00:00:00:00:00:00"  #Sender MAC Address

packet_transport:
  - platform: espnow
    providers:
      - name: outdoor-temp-xmtr 
 
sensor:
  - platform: aht10  #Add Temperature/Humidity Sensor AHT20
    variant: AHT20
    address: 0x38
    temperature:
      filters:
        - lambda: return x * (9.0/5.0) + 32.0;  #Convert temperature to degrees F
      unit_of_measurement: "°F"  
      id: in_temp_f
      name: "Indoor Temp"
    humidity:
      id: in_hmty
      name: "Indoor Hmty"
    update_interval: 10s
  - platform: packet_transport
    provider: outdoor-temp-xmtr
    id: remote_temp
    remote_id: out_temp_f
    name: "Remote Outdoor Temperature"

font:
  - file: "gfonts://Rubik@500"
    id: font1
    size: 18
  - file: "gfonts://Rubik@500"
    id: font2
    size: 20

#display:
#  - platform: ssd1306_i2c
#    model: SSD1306_128X64
#    address: 0x3C
#    lambda: |- 
#      it.printf(0, 10, id(font1), "In Temp %.1f °F", id(in_temp_f).state);
#      it.printf(0, 40, id(font1), "In Hmty %.1f RH", id(in_hmty).state);  

Add the internal: true (or false) after name like compiler and docs suggested.

I don’t think that’s a valid config, peers should be a list:

espnow:
  peers:
    - "00:00:00:00:00:00"

The 00:00:... is replaced by the actual MAC address of the receiver, right?

Right. Actual MAC address used.

Only seeking a one-way transmission. So, only one receiver in the list. Correct?

Let’s first take a step back.

You wrote that you were having validation errors with the receiver file, are those solved already? Because if your transmitter is sending to a receiver that’s not running, it is to be expected to get errors on the transmitter.

As for setup, from what I remember:

  • both transmitter and receiver have to declare each other as peer in the top-level espnow: configuration (using peers);
  • the transmitter should also set the peer_address in the ESP-NOW packet transport configuration;

You can simply use broadcast, just set auto_add_peer: true in the receiving side and omit peers: from both configs.

The advantages of using directed addressing are less than you might think. I have just raised a PR to update the docs somewhat - see the Broadcasting section in https://deploy-preview-6547--esphome.netlify.app/components/espnow/

1 Like

Gents, thanks for the responses. Since I’m relatively low on the ‘learning-curve’, ‘Take a step back’ is excellent advice. My attempt to learn basic setup and communication protocols got me a bit tangled up. I think perhaps a ‘divide and conquer’ strategy may work better.
Currently, I have two ESP32 (Dev) equipped with AHT20 temperature sensors running (on my bench) as (#1) ‘Indoor’ and (#2) ‘Outdoor’. And, I have a single ssd1306 (128X64) display that works correctly with either device.
What I envision is my transmission of the outdoor temperature value from my ‘Outdoor’ (#2) device to my ‘Indoor’ (#1) device. And, my ‘Indoor’ (#1) device to display both the recorded indoor temperature and the transmitted outdoor temperature.
Before attempting to ‘blend’ my operational devices with ESPNOW communication protocol, I think it might be simpler (learning-curve-wise) to set aside my working operational code, and focus on simplified code for the ESPNOW communication protocol. Once that is working to my satisfaction, I can move forward to combining both operational components.
Any additional recommendations you have are appreciated. Meanwhile, I’ll come back to this string when I have an experimental sketch to work through.

OK, Planning on getting to better understanding of ESPNOW in a couple of steps.
STEP #1: Compile code on ‘Outdoor’ ESP32 to display simple text to my ssd1306.
STEP #2: Compile code to transmit ‘simple text’ from ‘Outdoor’ ESP32 to ‘Indoor’ ESP32.
Below please find a tentative sketch for STEP #1. There is nothing displayed when this is run. I suspect that although I have defined text_sensor: id:, I have not populated it; i.e., there is nothing to display. How do I populate my defined id: my_text_id?

     # Add component definitions here

i2c:
  sda: GPIO21
  scl: GPIO22

text_sensor:
  - platform: template
    name: "Display Text"
    id: my_text_id
    update_interval: 10s
 
font:
  - file: "gfonts://Rubik@500"
    id: font1
    size: 18

display:
  - platform: ssd1306_i2c
    model: SSD1306_128X64
    id: my_display
    address: 0x3C
    lambda: |-
      it.printf(0, 10, id(font1), "%s", id(my_text_id).state.c_str());

Update: added lambda: return value to populate id:, I believe this completes STEP #1. Boy, do I have a lot to learn.