Skip to main content Microfire 






ESP-Now with ESPHome


A web of lines

ESP-Now

is in Espresiff's words:


a wireless communication protocol defined by Espressif, which enables the direct, quick and low-power control of smart devices, without the need of a router

The use-case here is battery-powered sensors. WiFi sensors take several seconds to start, connect, and send sensor measurements. Seconds don't sound like a long time, but it is quite a long time in the world of low-power sensors. ESP-Now doesn't need to negotiate a connection. It can just broadcast data. It seems well-suited for battery-powered sensors and would be great to use within ESPHome

.


The issue is there isn't an official component for ESP-Now yet. There are several

projects doing so, though, and this will be a write-up of yet another way to do it.


BOM

  • 2x ESP32 boards
  • any sensor for testing, I'll be using an SHT30

Architecture

Because we want our measurements to get into Home Assistant, and Home Assistant lives on WiFi, we'll need to make some sort of bridge so our ESP-Now sensors can talk to WiFi. We also need a way to present our sensors inside Home Assistant.


To accomplish both of those things, I will use an ESP32 as a bridge. The bridge will connect to our MQTT broker configured for use with Home Assistant. The bridge will also listen to ESP-Now broadcast messages. The messages will contain enough information in them to allow the bridge to simulate an MQTT-based sensor

. The advantage of simulating an MQTT sensor is it Just Works®, and doesn't require the bridge to know anything about the sensor devices.


When you include an mqtt block in the ESPHome YAML. It sends two bits of information to the broker regarding the sensors:

  • a config string that is JSON with details about the measurement, unit of measurement, type of measurement, etc.
  • a state string which is the actual sensor measurement
With those pieces of information, it creates some MQTT entries which Home Assistant uses to create a new device.


To do the same thing, our sensor ESP32 will send an ESP-Now message like this:


Each piece of information is delimited by a :.


WiFi Channels

There is some confusion that I wasn't able to sort out. Your WiFi router operates on a particular channel (some jump around). When the bridge connects to the WiFi network, it discovers the channel as part of the connection procedure. Normally you don't need to think much about it, but now we need another wireless protocol to co-exist with the WiFi connection and share the same channel.


ESP-Now also uses channels, although that is where I ran into issues. If I changed the ESP-Now channel to something other than 0 or 1, it threw errors. So either ESP-Now only works on channel 0 (not sure what that actually is) or 1, or I just missed something somewhere. I also had to change my router's WiFi settings to use channel 1. Without the router change, this won't work. If someone can sort this out, let me know on Discord

.


1.

Make sure your MQTT broker is set up for Home Assistant. The instructions can be found in the addon inside Home Assistant. You'll probably want to follow the instructions by making a new MQTT user and configuring it as an integration. Or you can use your own broker and just add it as an integration. When you are done, you'll have an MQTT box in Settings > Devices & Services.


2.

For the bridge, have a look at the ESPHome YAML below.

1
esphome:
2
  name: esp-now-mqtt-bridge
3
esp32:
4
  board: esp32dev
5
  variant: esp32
6
  framework:
7
    type: arduino
8
logger:
9

10
external_components:
11
  - source:
12
      type: git
13
      url: https://github.com/u-fire/ESPHomeComponents/
14

15
now_mqtt_bridge:
16

17
wifi:
18
  ssid: !secret wifi_ssid
19
  password: !secret wifi_password
20

21
mqtt:
22
  id: mqtt_broker
23
  broker: homeassistant.local
24
  username: mqtt
25
  password: !secret mqtt_password


Setup the mqtt for your broker. You can change the Home Assistant discovery prefix (if you changed it for some reason), and it will also be used in the MQTT bridge.


3.

For our sensor device, look at the YAML below.

1
esphome:
2
  name: sht30-espnow
3
esp32:
4
  board: esp32dev
5
  framework:
6
    type: arduino
7
logger:
8

9
# import the components
10
external_components:
11
  - source:
12
      type: git
13
      url: https://github.com/u-fire/ESPHomeComponents/
14

15
# no need for api or wifi block when using just ESP-Now
16
now_mqtt:
17

18
i2c:
19
  sda: 10
20
  scl: 20
21

22
sensor:
23
  - platform: sht3xd
24
    id: sht
25
    temperature:
26
      name: "Temperature"
27
    humidity:
28
      name: "Humidity"
29
    address: 0x44


The ESP-Now component is just the single line of `now_mqtt`. There's no need for the `api` or `wifi` block. The component works by waiting for each sensor to update its state. When that happens, it creates a line similar to the one explained above and sends it out as a broadcast message. No pairing is needed, but this also precludes encryption if that is important for you.


Make any changes for your particular sensors and upload the YAML through the Home Assistant ESPHome addon or the ESPHome command line. You'll start to see the scrolling of sensor measurements and notifications of sending ESP-Now messages. You'll also see those same messages in the bridge serial output, and if you are paying attention to your MQTT broker, you'll see new entries being added.

And most importantly, you'll also see the new sensor inside the MQTT section of Settings -> Devices and Services.


4.

But what can we do with this now, and how is it better than WiFi and MQTT?


Look at this slight modification of the above YAML.

1
esphome:
2
  name: sht30-espnow
3
esp32:
4
  board: seeed_xiao_esp32c3
5
  variant: esp32c3
6
  framework:
7
    type: arduino
8
# logger:
9

10
# import the components
11
external_components:
12
  - source:
13
      type: git
14
      url: https://github.com/u-fire/ESPHomeComponents/
15

16
now_mqtt:
17

18
i2c:
19
  sda: 10
20
  scl: 20
21

22
sensor:
23
  - platform: sht3xd
24
    id: sht
25
    temperature:
26
      name: "Temperature"
27
    humidity:
28
      name: "Humidity"
29
    address: 0x44
30

31
deep_sleep:
32
  run_duration: 100ms
33
  sleep_duration: 5min


This particular device can operate on a very small 260 mAh battery for several months. 260 is quite small, so a larger battery can easily get into the year range.


5.

The sensor also has the option to get an on_sent notification. This allows you to enter deep sleep the moment all of the sensor measurements have been sent, saving awake time.

1
...
2
globals:
3
  - id: sent
4
    type: int
5
    restore_value: no
6
    initial_value: '0'
7

8
now_mqtt:
9
  on_sent:
10
    then:
11
      - lambda: id(sent)++; 
12
      - if:
13
          condition:
14
            lambda: 'return id(sent) == 5;'
15
          then:
16
          - deep_sleep.enter:
17
              id: sleep_
18
              sleep_duration: 5m
19

20

21
deep_sleep:
22
  id: sleep_
23
...


The code creates a global variable named `sent``. Then it increases the value each time a sensor measurement is sent. If `sent`` equals 5, which in this case is the number of sensors, it goes to sleep for 5 minutes.




Fixing the channel issue


One fix for the channel issue is to use an ethernet-capable ESP32. Since it isn't using WiFi, the channel doesn't matter.


There are a handful of ESPHome-compatible boards

out.


You can find an example YAML here

using an WT32-ETH01.




Related

LoRa with ESPNow - for longer range sensors
HABridge - Arduino Library - Create a Home Assistant sensor from any hardware and send measurements with ESPNow or LoRa