Shelly Plus Plug S - ESPHOME

My have them inside contact holes…

It is one screw, and it is placed in the hole for “ground”. You’ll need a narrow and long screwdriver for it.

I’ll be trying the pinout flash soon, cause my new ESPHome firmware gets uploaded but the plug is not booting with the new firmware version 🥲

Hmm… this solution did not work for me.
First I tried to migrate via the software way. Migrated from Shelly Software to tasmota is easy. But I was not able to migrate from tasmota to ESPHome. Tried it the hole day along.
So I decided to open this thing and but the needles on it. I flashed with esptools on a raspberry. (tig's Blog)

The software said that the bin file is copied correct. But the plug is dead. I tried a second one. Also dead.

**daniel@raspberrypi**:**~ $** esptool.py --port /dev/ttyS0 write_flash 0x0000 ~/shelly-plus-plug-s-3.bin
esptool.py v4.6.2
Serial port /dev/ttyS0
Connecting...
Failed to get PID of a device on /dev/ttyS0, using standard reset sequence.
Detecting chip type... Unsupported detection protocol, switching and trying again...
Connecting...
Failed to get PID of a device on /dev/ttyS0, using standard reset sequence.
Detecting chip type... ESP32
Chip is ESP32-U4WDH (revision v3.1)
Features: WiFi, BT, Dual Core, 240MHz, Embedded Flash, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: b0:b2:1c:0f:9a:80
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x000d9fff...
Compressed 892336 bytes to 589471...
Wrote 892336 bytes (589471 compressed) at 0x00000000 in 53.5 seconds (effective 133.5 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
**daniel@raspberrypi**:**~ $**

No reaction if I put 3,3 Volt and Ground directly on the pins. No reaction if I put in the wall outlet.
Oh no, I killed my two plugs. :frowning:

Any ideas? Maybe it is better to buy the ATHOM plugs with pre flashed ESPHome?

Found the solution in this thread: Guide for flashing ESPHome firmware with esptools on Linux

If the firmware file doesn’t end on “-factory.bin” it is likely not the modern version. If you flash the legacy version, the ESP will get stuck in a boot loop. I guess the difference between modern and legacy is, that legacy comes without a bootloader, but I never really checked that.

So I get out the needles again an do all the procedure from beginn till the end - with success! The first plug is now on ESPHome. :slight_smile:

3 Likes

Weird,
had the opposite experience.
Flashed the tasmota and then the esphome in modern format, however I always received an error. As soon as I used the legacy one everything worked. All via GUI.
In between I also “bricked” one, which I had to revive via TTL and the only way I could achieve it was with the legacy esphome one I built and esphome-flasher. Was not able to flash via web.esphome.io and modern format.

BTW: was anyonoe able to use bluetooth proxy already? Gave it a try, after I found out that this needs to be flashed via TTL, however the plug seems to be stuck in a boot loop now.

Okay, that’s really weird. But good that it works now. :slight_smile:

I do not setup the proxy function now but I will do this to in the near future. I use this plug to monitor the washing machine. The goal is to get a device that holds the full intelligence and reports only the actual status as a text sensor to Home Assistant. My ESPHome software is now fully functional but the last thing to perfection is to connect a (bluetooth) door sensor directly to this plug.

Therefore I have to setup the bluetooth integration in the future. But first I have to find a native working bluetooth door sensor. The Xiaomi is not such a thing. Maybe the Shelly Blu will work.

So you already implemented and flashed esphome including the bluetooth part?
If so, mind sharing the bluetooth parts you used?
The unsuccesfull part I used to try was:

esp32_ble_tracker:
  scan_parameters:
    active: false

bluetooth_proxy:
  active: true

The needle setup looks pretty similar to mine here XD.
Will probably give the bluetooth part another try at the weekend.

Flashed the bluetooth component yesterday. The device is online but I am not able to check if the bluetooth works.

I used the exact same configuration as you posted, but disabled the web proxy in addition.

Flashed via OTA. Two things I found to be aware off:

  1. it is not the bluetooth component that require the flashing via wires, it is the change of the framework instead. Because the framework is the same as at my first flashing, I flashed this time via OTA.
  2. Disable webserver because there is a risk to run out of memory.

After flashing there was no new entity or device like “bt proxy” or so. My Shelly BLU Door is not delivered yet. Therefore I am not sure if it works fine but the software is installed. :slight_smile:

Ressources: Bluetooth Proxy — ESPHome

The ESP32 Platform component should be configured to use the esp-idfframework, as the arduino framework uses significantly more memory and performs poorly with the Bluetooth proxy enabled. When switching fromarduino to esp-idf, make sure to update the device with a serial cable as the partition table is different between the two frameworks as OTA Update Component updates will not change the partition table.

Good luck!

Thanks, no idea how I missed the part that says that only switching type needs the TTL flash…

However I just tested my second working shelly plus plug via ota flash (was esp-idf) and now it is “dead”:

No clue what is going on. I just added the parts I mentioned before and flashed . Without the BT part it worked.
Config is now like this. Maybe you can spot a differenc to your

substitutions:
  device_name: "shelly-plus-plug-s-black1"
  friendly_name: shelly-plus-plug-s-black1
  channel_1: Relay
  max_power: "1500" # 2000
  max_temp: "65.0" # 70.0
  # Higher value gives lower watt readout.
  current_res: "0.001"
  # Lower value gives lower voltage readout.
  voltage_div: "1830"


esphome:
  name: ${device_name}
  friendly_name: ${friendly_name}
  on_boot:
    - delay: 10s
    - lambda: !lambda |-
        id(rgb_ready) = true;
    - script.execute: set_rgb

esp32:
  board: esp32doit-devkit-v1
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "XXXXX"

ota:
  password: "XXXXX"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  use_address: 10.0.100.27
  domain: .xxxxx.lan

  # Enable fallback hotspot in case wifi connection fails
  ap:
    ssid: ${device_name}

esp32_ble_tracker:
  scan_parameters:
    active: false

bluetooth_proxy:
  active: true

time:
  - platform: homeassistant
    id: my_time

globals:
  - id: rgb_ready
    type: bool
    restore_value: false
    initial_value: 'false'
  - id: total_energy
    type: float
    restore_value: true
    initial_value: '0.0'


    #### only needed for RGB LED to set up a while after boot. Not available with esp-idf framework #####

script:
  - id: set_rgb
    mode: queued
    then:
      - if:
          condition:
            lambda: 'return id(rgb_ready);'
          then:
            - if:
                condition:
                  lambda: 'return id(relay).state;'
                then:
                  - if:
                      condition:
                        lambda: 'return id(ring_on).remote_values.is_on();'
                      then:
                        - light.turn_on:
                            id: rgb_light1
                            brightness: !lambda |-
                              return id(ring_on).remote_values.get_brightness();
                            red: !lambda |-
                              return id(ring_on).remote_values.get_red();
                            green: !lambda |-
                              return id(ring_on).remote_values.get_green();
                            blue: !lambda |-
                              return id(ring_on).remote_values.get_blue();
                        - light.turn_on:
                            id: rgb_light2
                            brightness: !lambda |-
                              return id(ring_on).remote_values.get_brightness();
                            red: !lambda |-
                              return id(ring_on).remote_values.get_red();
                            green: !lambda |-
                              return id(ring_on).remote_values.get_green();
                            blue: !lambda |-
                              return id(ring_on).remote_values.get_blue();
                      else:
                        - light.turn_off: rgb_light1
                        - light.turn_off: rgb_light2
                else:
                  - if:
                      condition:
                        lambda: 'return id(ring_off).remote_values.is_on();'
                      then:
                        - light.turn_on:
                            id: rgb_light1
                            brightness: !lambda |-
                              return id(ring_off).remote_values.get_brightness();
                            red: !lambda |-
                              return id(ring_off).remote_values.get_red();
                            green: !lambda |-
                              return id(ring_off).remote_values.get_green();
                            blue: !lambda |-
                              return id(ring_off).remote_values.get_blue();
                        - light.turn_on:
                            id: rgb_light2
                            brightness: !lambda |-
                              return id(ring_off).remote_values.get_brightness();
                            red: !lambda |-
                              return id(ring_off).remote_values.get_red();
                            green: !lambda |-
                              return id(ring_off).remote_values.get_green();
                            blue: !lambda |-
                              return id(ring_off).remote_values.get_blue();
                      else:
                        - light.turn_off: rgb_light1
                        - light.turn_off: rgb_light2

output:
  - platform: template
    id: r_out_on
    type: float
    write_action:
      - lambda: |-
  - platform: template
    id: g_out_on
    type: float
    write_action:
      - lambda: |-
  - platform: template
    id: b_out_on
    type: float
    write_action:
      - lambda: |-
  - platform: template
    id: r_out_off
    type: float
    write_action:
      - lambda: |-
  - platform: template
    id: g_out_off
    type: float
    write_action:
      - lambda: |-
  - platform: template
    id: b_out_off
    type: float
    write_action:
      - lambda: |-

light:
  - platform: rgb
    id: ring_on
    name: "${channel_1} Ring when On"
    icon: "mdi:circle-outline"
    default_transition_length: 0s
    red: r_out_on
    green: g_out_on
    blue: b_out_on
    restore_mode: RESTORE_DEFAULT_OFF
    entity_category: config
    on_state:
      - delay: 50ms
      - script.execute: set_rgb
  - platform: rgb
    id: ring_off
    name: "${channel_1} Ring when Off"
    icon: "mdi:circle-outline"
    default_transition_length: 0s
    red: r_out_off
    green: g_out_off
    blue: b_out_off
    restore_mode: RESTORE_DEFAULT_OFF
    entity_category: config
    on_state:
      - delay: 50ms
      - script.execute: set_rgb

  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    rmt_channel: 0
    chipset: ws2812
    pin: GPIO25
    num_leds: 2
    id: rgb_light1
    internal: true
    default_transition_length: 700ms
    restore_mode: ALWAYS_OFF
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    rmt_channel: 1
    chipset: ws2812
    pin: GPIO26
    num_leds: 2
    id: rgb_light2
    internal: true
    default_transition_length: 700ms
    restore_mode: ALWAYS_OFF

binary_sensor:
  - platform: gpio
    id: "push_button"
    internal: true
    pin:
      number: GPIO9
      inverted: yes
      mode:
        input: true
        pullup: true
    on_click:
      then:
        - if:
            condition:
              switch.is_off: button_lock
            then:
              - switch.toggle: relay
    filters:
      - delayed_on_off: 5ms

switch:
  - platform: gpio
    pin: GPIO4
    id: relay
    name: "${channel_1}"
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - script.execute: set_rgb
    on_turn_off:
      - script.execute: set_rgb
  - platform: template
    entity_category: 'config'
    name: "Button lock"
    id: button_lock
    optimistic: true
    restore_mode: ALWAYS_OFF

sensor:
  - platform: ntc
    sensor: temp_resistance_reading
    name: "${device_name} Temperature"
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    icon: "mdi:thermometer"
    entity_category: 'diagnostic'
    calibration:
      b_constant: 3350
      reference_temperature: 298.15K
      reference_resistance: 10kOhm
    on_value_range:
      - above: ${max_temp}
        then:
          - switch.turn_off: "relay"
          - homeassistant.service:
              service: persistent_notification.create
              data:
                title: Message from ${device_name}
              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: 10kOhm
  - platform: adc
    id: temp_analog_reading
    pin: GPIO33
    attenuation: 11db
    update_interval: 10s

  - platform: hlw8012
    model: BL0937
    sel_pin:
      number: GPIO19
      inverted: true
    cf_pin: GPIO10
    cf1_pin: GPIO22
    current_resistor: ${current_res}
    voltage_divider: ${voltage_div}
    change_mode_every: 1
    update_interval: 5s
    current:
      id: current
      unit_of_measurement: A
      accuracy_decimals: 3
      internal: true
      name: "${channel_1} current"
    voltage:
      id: voltage
      unit_of_measurement: V
      accuracy_decimals: 1
      internal: false
      name: "${channel_1} voltage"
    power:
      name: "${channel_1} power"
      unit_of_measurement: W
      id: power
      icon: mdi:flash-outline
      force_update: true
      on_value_range:
        - above: ${max_power}
          then:
            - switch.turn_off: relay
            - homeassistant.service:
                service: persistent_notification.create
                data:
                  title: Message from ${device_name}
                data_template:
                  message: Switch turned off because power exceeded ${max_power}W

  - platform: total_daily_energy
    name: "${channel_1} energy"
    power_id: power
    state_class: total_increasing
    unit_of_measurement: kWh
    filters:
      # Multiplication factor from W to kW is 0.001
      - multiply: 0.001
      - lambda: !lambda |-
          static auto last_state = x;
          if (x < last_state) { // x was reset
            id(total_energy) += last_state;
            ESP_LOGI("main", "Energy channel 1 was reset: %f", id(total_energy));
          }
          last_state = x;
          return id(total_energy) + x;

THX

Sorry, I can’t spot any difference in the important areas. :frowning:

There is a new version V2 without screw, I have no idea to open it for flashing it via serial cable: (


thanks for looking.

Will probably flash again without the bt parts

Yeah, the V2 don’t have a screw.

Might try it with a small drill, as I “bricked” mine.

You can still do the initial flash via converting to tasmota first, as mentioned above. So as long as you don’t brick it, there is no need to serial flash it.

How can I find out these values for bl0937? ( I have one plug by local bytes that I forgot to make note of the values before converting to esphome and now I can’t get super precise measurements)

  # Higher value gives lower watt readout
  current_res: "0.001"
  # Lower value gives lower voltage readout
  voltage_div: "1830"

I flashed Tasmota with GitHub - tasmota/mgos32-to-tasmota32: ESP32 Mongoose OS to Tasmota32 OTA Firmware Updates for Shelly and repartitioned to make one big app partition. Is it possible to flash ESPHome by using Tasmota web gui? Can I just build firmware and flash it in Tasmota gui?

1 Like

No, not possible, since the partition scheme used is the Tasmota safeboot scheme. This partition scheme has only one OTA slot, the other slot used for the OTA updating is a factory partition slot fashed with a special (very small) Tasmota version just made doing the update job. So the partition scheme is totally different to the one used for esphome.
For OTA flashing esphome a convert Shelly to esphome update firmware needs to be written in Mongoose SDK. This tool has to do the repartitioning from Shelly scheme to esphome scheme and writes a new bootloader. The Shelly bootloader allows only signed firmwares.
Tasmota does this all right after boot when Autoconfig feature menu in Tasmota is used. The Autoconfig downloads a new bootloader and the Berry runtime Code to flash The new bootloader and writes the Tasmota Partition scheme. Without the Repl Berry included in Tasmota this tool would have not been possible with Tasmota.

Shelly raised the secure. The new convert tool is only compatible with Tasmota

But if I flashed Tasmota bootloader, it will accept all firmwares, not signed only? If yes, then I could flash ESPHome if partition scheme was ESPHome compatible?

Has anyone flashed to Tasmota the UK version of this plug lately? It’s labelled “Shelly Plus Plug UK (type G)”. I flashed one back in May using http://ota.tasmota.com/tasmota32/shelly/mgos32-to-tasmota32-PlusPlugUK.zip, but that appears to be deleted and the tasmota release site doesn’t seem to list it (or anything else for Shelly) and https://github.com/tasmota/mgos32-to-tasmota32 seems to have dropped support for it.

Edit: I’ve had a fix added to mgos32-to-tasmota32 so this now works, and then I uploaded a “legacy” esphome image and it worked, and was found by HA. I then tried to add this to the working yaml:

esp32_ble_tracker:
  scan_parameters:
    active: false

bluetooth_proxy:
  active: true

and the device is now seemingly bricked. It was my understanding that this should be fine unless I was changing frameworks, but in this case I didn’t - it was IDF for both.

Did you convert to tasmota safeboot partition scheme? Since this will be incompatible with esphome.