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:

  • Create an ESPHome configuration for the Shelly 2.5 and compile a firmware
  • Use a special firmware to update the Shelly to Tasmota over-the-air
  • Use Tasmota to flash the ESPHome firmware

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

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:

  • Shelly 1
  • Shelly 1PM
  • Shelly Plug S
  • Shelly 2
  • Shelly 2.5
  • Shelly RGBW2
  • Shelly EM

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.

Posted on