Shelly 2.5: Flash ESPHome Over The Air!

It's no secret that I'm a fan of Shelly products to automate various devices in my house. They're well built, tiny and rock solid, and best of all: compatible with ESPHome.

I flashed ESPHome onto all my Shelly 1's, but for some reason, I have issues with my Shelly 2.5 devices... Here's how I flashed ESPHome onto them over-the-air. No wires!

My problems with the Shelly 2.5

Shelly devices usually have exposed programming pins that you can use to attach a USB-to-UART adapter (through the TX and RX pins). That's how I flashed my Shelly 1 units. However, the Shelly 2.5 is problematic.

First up: the pins are smaller than regular Dupont pins (the ones you find on practically every micro-controller board). That means you have to use special adapter (which is outrageously expensive) or a stripped ethernet cable or female-to-female jumper wires.

These options are ugly and impractical. I tried using needles, which fit the holes, but I couldn't get the Shelly into download mode.

I gave up on it and used the default firmware instead. Then, weeks later, I found a workaround to flash them over-the-air. No need for me to take my Shelly's out the wall again. Cool!

Overview

Here's what we'll do:

Let's get going!

Creating an ESPHome configuration

I'll start by creating an ESPHome configuration for the Shelly 2.5. As usual, there's already one available on esphome-configs.io. I'm using the second one which includes protection against drawing too much current & over-temperature.

Here's my configuration (slightly adapted to expose 2 lights to Home Assistant):

substitutions:
devicename: shelly_25_bathroom
# Name for the relays
channel_1: Light 1
channel_2: Light 2
max_power: "2000.0" # watt
max_temp: "80.0" # °C

esphome:
name: ${devicename}
platform: ESP8266
board: esp01_1m

wifi:
ssid: !secret wifi_iot_ssid
password: !secret wifi_iot_password

# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: ${friendly_name} AP
password: !secret esphome_fallback_ap_password

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
password: !secret esphome_api_password

ota:
password: !secret esphome_api_password

i2c:
sda: GPIO12
scl: GPIO14

sensor:
- platform: ade7953
voltage:
name: ${devicename} voltage
current_a:
name: ${channel_2} current
internal: true
current_b:
name: ${channel_1} current
internal: true
active_power_a:
name: ${channel_2} power
id: power_channel_2
filters:
- multiply: 1
on_value_range:
- above: ${max_power}
then:
- switch.turn_off: shelly_relay_2
- homeassistant.service:
service: persistent_notification.create
data:
title: Message from ${devicename}
data_template:
message: Switch turned off because power exceeded ${max_power}W
active_power_b:
name: ${channel_1} power
id: power_channel_1
filters:
- multiply: -1
on_value_range:
- above: ${max_power}
then:
- switch.turn_off: shelly_relay_1
- homeassistant.service:
service: persistent_notification.create
data:
title: Message from ${devicename}
data_template:
message: Switch turned off because power exceeded ${max_power}W
update_interval: 30s

# NTC Temperature
- platform: ntc
sensor: temp_resistance_reading
name: ${devicename} temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
icon: "mdi:thermometer"
calibration:
b_constant: 3350
reference_resistance: 10kOhm
reference_temperature: 298.15K
on_value_range:
- above: ${max_temp}
then:
- switch.turn_off: shelly_relay_1
- switch.turn_off: shelly_relay_2
- homeassistant.service:
service: persistent_notification.create
data:
title: Message from ${devicename}
data_template:
message: Switch turned off because temperature exceeded ${max_temp}°C
- platform: resistance
id: temp_resistance_reading
sensor: temp_analog_reading
configuration: DOWNSTREAM
resistor: 32kOhm
- platform: adc
id: temp_analog_reading
pin: A0

status_led:
pin:
number: GPIO0
inverted: yes

output:
- platform: gpio
pin: GPIO4
id: shelly_25_relay_1
- platform: gpio
pin: GPIO15
id: shelly_25_relay_2

light:
- platform: binary
name: "${channel_1}"
output: shelly_25_relay_1
id: lightid1
- platform: binary
name: "${channel_2}"
output: shelly_25_relay_2
id: lightid2

binary_sensor:
- platform: gpio
pin:
number: GPIO13
name: "${channel_1} input"
internal: true
on_state:
then:
- light.toggle: lightid1
- platform: gpio
pin:
number: GPIO5
name: "${channel_2} input"
internal: true
on_state:
then:
- light.toggle: lightid2

# Prevent short circuit with "floating" pin!
- platform: gpio
pin: GPIO16
name: "ade7953 IRQ pin"
internal: true

I found that the maximum temperature of 70°C is a bit low. My units reach that temperature quickly with a relatively small load (about 30-50W), so I increased the limit to 80°C.

I'm using the ESPHome add-on for Home Assistant. To compile the firmware, head over to your configuration, click the 3 dots and click "Compile".

After compilation, click "Download binary" to get the .bin file:

Flash intermediate firmware

Next up: flashing Tasmota onto the Shelly over-the-air.

I'm using an open-source tool called mg2x which converts the Shelly from running Mongoose OS to Tasmota. It supports the following models:

Start by finding the IP address of your Shelly device. I did this through my router, but you can also use the Shelly's native firmware.

Once you have that, navigate to this URL:

http://SHELLY_IP_ADDRESS/ota?url=http://dl.dasker.eu/firmware/mg2tasmota-Shelly25.zip

Pay attention: the URL depends on your Shelly device. The above is valid for the Shelly 2.5. Check the mg2x README for a list of alternative URLs for other Shelly devices.

You should see the following JSON document as response:

{
"status": "updating",
"has_update": false,
"new_version": "20200812-091015/v1.8.0@8acf41b0",
"old_version": "20200601-122849/v1.7.0@d7961837"
}

The Shelly will now download the intermediate firmware, which in turn will download and flash Tasmota. This took about 2 minutes.

Configure Tasmota

Next up, we have to configure Tasmota. Make sure your computer is physically near the Shelly and scan for WiFi networks. There should be a tasmota-XXXXX network. Connect to it.

In my case, macOS showed a popup with Tasmota's captive portal. If this doesn't happen on your computer, navigate to the Shelly 2.5 directly: http://192.168.4.1

Fill in your WiFi network name (SSID) and password. Then, scroll down and click "Save".

The Shelly will now attempt to connect to your WiFi network. Make sure you do the same on your computer.

Browse to the IP address of your Shelly and you should see the default Tasmota page. No point in configuring the module. We're going to ESPHome!

Before we can upload ESPHome, we have to disable Tasmota's firmware check. By default, it only allows you to flash other Tasmota builds (that's a safety feature).

To do that, go to "Console" and type in this command, followed by return:

SetOption78 1

Tasmota will confirm the change:

Now we can flash our ESPHome firmware.

Go back to the main screen and click on "Firmware Upgrade". Upload your ESPHome firmware and click "Start upgrade".

ESPHome is now being flashed. This process takes about a minute.

After a short wait, head over to your Home Assistant installation and check your notifications. My device was automatically discovered:

Click "Configure" and follow the onboarding process of Home Assistant. Easy!

All the necessary entities should now have been created in Home Assistant. Here are my living room lights as an example:

Problem: no energy monitoring

As you can see from the screenshot above, the energy monitoring doesn't work, even though the ADE7953 power sensor, is correctly configured.

In the logs I could see that ESPHome detected no i2c devices, and even threw NACK errors when trying to talk to the sensor:

[15:35:58][C][i2c:028]: I2C Bus:
[15:35:58][C][i2c:029]:   SDA Pin: GPIO12
[15:35:58][C][i2c:030]:   SCL Pin: GPIO14
[15:35:58][C][i2c:031]:   Frequency: 50000 Hz
[15:35:58][I][i2c:033]: Scanning i2c bus for active devices...
[15:35:58][I][i2c:049]: Found no i2c devices!

[15:40:39][W][i2c:070]: Received NACK on transmit of address 0x38
[15:40:39][W][i2c:070]: Received NACK on transmit of address 0x38
[15:40:39][W][i2c:070]: Received NACK on transmit of address 0x38
[15:40:39][W][i2c:070]: Received NACK on transmit of address 0x38
[15:40:39][W][i2c:070]: Received NACK on transmit of address 0x38

I tried power-cycling the Shelly with the Restart Switch in ESPHome, to no avail. I then submitted a bug report on GitHub.

It seems like the power sensor is going in a sleep mode and can't be woken up.

Ultimately, someone suggested to properly power-cycle the Shelly. I installed mine behind a light switch and I didn't want to open that up again. So instead, I toggled my circuit breaker off and on:

Sure enough, the Shelly now reports the correct power stats for each relay, along with the voltage it receives.

I hope you found this tutorial helpful. Let me know in the comments if you run into issues or you have suggestions.

Problem: potential short-circuit & fire hazard

You might have noticed that I create a "useless" binary sensor in the configuration file:

binary_sensor:
- platform: gpio
pin: GPIO16
name: "ade7953 IRQ pin"
internal: true

This is very important. Please do not remove it! It configures the IRQ pin of the energy monitoring chip in the Shelly. Without it, your device will heat up significantly!

Thanks to GuestGregor for pointing this out!

Posted on

You May Also Enjoy

Subscribe to my newsletter

Monthly newsletter with cool stuff I found on the internet (related to science, technology, biology, and other nerdy things)! Check out past editions.