ESPhome device no longer connecting after update

Hi all,

I’m a bit lost here. I have just updated the configuration on my shelly 2pm. With respect to the previous working configuration, I have added the following:

#bluetooth
bluetooth_proxy:

# BLE tracker setup
esp32_ble_tracker:

- platform: wifi_signal
    name: ${node_name} WiFi Signal
    update_interval: 180s
    entity_category: 'diagnostic'

text_sensor:

#   # Expose ESPHome version as sensor.
  - platform: version
    name: ${node_name} ESPHome Version
    entity_category: 'diagnostic'
#   # Expose WiFi information as sensors.
  - platform: wifi_info
    ip_address:
      name: ${node_name} IP
      entity_category: 'diagnostic'
    ssid:
      name: ${node_name} SSID
      entity_category: 'diagnostic'

Now the device will no longer connect to the network, Nor does it respond to the button presses on the physical device. Since the device is mounted inside a very tight wall socket, I’m not very keen of taking it out every time this happens, so I was hoping to get some understanding of why this has seemingly ‘bricked’ the device.

Full configuration:

# change yaml name: https://esphome.io/changelog/2022.5.0.html

substitutions:
  IP: 192.168.178.24
  node_name: "shelly-plus-2pm"
  output_name_1: "${node_name} Output 1"
  output_name_2: "${node_name} Output 2"
  input_name_1: "${node_name} Input 1"
  input_name_2: "${node_name} Input 2"
  friendly_name_short: "sprinkler"
  max_temp: "70.0"

# For Single Core ESP32
esphome:
  name: ${node_name}
  comment: "${IP}: Control Lighting / sprinklers terras"
  platformio_options:
    board_build.f_cpu: 160000000L

esp32:
  board: esp32doit-devkit-v1
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_FREERTOS_UNICORE: y
      CONFIG_ESP32_DEFAULT_CPU_FREQ_160: y
      CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "160"


logger:

# Enable Home Assistant API
api:
  encryption:
    key: !secret encryption_key
  services:
      - service: start_sprinkler
        variables:
          duration: int
        then:
          - globals.set:
              id: glbl_timeout_length_ticks
              value: !lambda 'return duration;'
          - logger.log:
              format: "service called for %d seconds, arming status is: %d"
              args: [ 'id(glbl_timeout_length_ticks)', 'id(glbl_timeout_armed)' ]
          - if:
              condition:
                # If the countdown timer is armed
                lambda: 'return id(glbl_timeout_armed);'
              then:
                - switch.turn_on: sprinkler_1
              else:
                - logger.log:
                    format: "service called for %d seconds, arming status is: %d"
                    args: [ 'id(glbl_timeout_length_ticks)', 'id(glbl_timeout_armed)' ]

ota:
  password: "****"

wifi:
  networks:
    -  ssid: !secret wifi_ssid3
       password: !secret wifi_password3
    -  ssid: !secret wifi_ssid2
       password: !secret wifi_password2
    -  ssid: !secret wifi_ssid
       password: !secret wifi_password
  
  # Optional manual IP
  manual_ip:
    static_ip: ${IP}
    gateway: 192.168.178.1
    subnet: 255.255.255.0
  #use_address: 192.168.178.236 #old adress for OTA upload 

#bluetooth
bluetooth_proxy:

# BLE tracker setup
#esp32_ble_tracker:


#define functionality
i2c: #not used?
  sda: GPIO26
  scl: GPIO25

output:
  - platform: gpio
    id: "relay_output_1"
    pin: GPIO12
  - platform: gpio
    id: "relay_output_2" #sprinkler
    pin: GPIO13

switch:
  - platform: output
    id: "relay_1"
    name: "${output_name_1}"
    output: "relay_output_1"

  - platform: output
    id: sprinkler_1
    output: relay_output_2

    # Resume last state on boot if possible. Else, off
    restore_mode: RESTORE_DEFAULT_OFF

    # Wire in the count down timer automation if enabled
    on_turn_on: #always do this when the 'sprinkler' is switched on
      then:
        - script.execute: _timer_tick
        - logger.log:
            level: DEBUG
            format: "sprinkler turned on, countdown timer started"

    # This can be called by the natural end of the timer OR manually through any other source.
    # Regardless of the source, we just need to stop the ticking if it's running.
    on_turn_off:
      then:
        - if:
            condition:
              lambda: 'return id(_timer_tick).is_running();'
            then:
              - script.execute: on_timer_stop

            else:
              - logger.log:
                  level: DEBUG
                  format: "sprinkler turned off, countdown timer not armed"


  # UI toggle for the arm/disarm of the auto-off/timeout functionality
  - name: "${friendly_name_short} Automation Arm"
    platform: template
    id: sw_timeout_arm
    device_class: "switch"
    entity_category: "config"

    lambda: |-
      if (id(glbl_timeout_armed)) {
        return true;
      } else {
        return false;
      }      
    turn_on_action:
      then:
        # Update the global to store the new state
        # If the sprinkler is already on, also start the timer
        - lambda: |-
            id(glbl_timeout_armed) = true;

            auto TAG = "template.Timeout Automation.turn_on_action";
            if ( id(sprinkler_1).state ) {
              id(_timer_tick).execute();
            } else {
              ESP_LOGD(TAG, "Timeout Automation ARMED, sprinkler NOT on. Nothing to do!");
            }            
    turn_off_action:
      then:
        # Update the global and stop the ticking timer if needed
        - lambda: |-
            // Set the global to OFF, it will be checked next time the _tick fires if the on_timer_stop doesn't
            // kill the ticking
            id(glbl_timeout_armed) = false;
            id(on_timer_stop).execute();  

# Give the user a graphical control over the timeout
# See: https://esphome.io/components/number/template.html
number:
  - name: "${friendly_name_short} Timeout"
    id: timeout_length
    platform: template
    entity_category: "config"
    # TODO: maybe it's a better UX to do this in minutes and do the conversion in esphome
    unit_of_measurement: seconds
    mode: box
    min_value: 2
    max_value: 21600
    step: 1

    lambda: |-
            return (int) id(glbl_timeout_length_ticks);

    set_action:
      then:
        - globals.set:
            id: glbl_timeout_length_ticks
            value: !lambda |-
              // TODO: we're relying on HA to pass an integer; perhaps we should do atoi() and catch any exceptions
              return (int) x;

binary_sensor:
  # Button on device
  - platform: gpio
    name: "${node_name} Button"
    pin:
      number: GPIO4
      inverted: yes
      mode:
        input: true
        pullup: true
    internal: true
  # Input 1
  - platform: gpio
    name: "${input_name_1}"
    pin: GPIO5
    filters:
      - delayed_on_off: 50ms
    on_press:
      then:
        - switch.toggle: relay_1
    on_release:
      then:
        - switch.toggle: relay_1
    internal: false
  # Input 2 (sprinkler)
  - platform: gpio
    name: "${input_name_2}"
    pin: GPIO18
    filters:
      - delayed_on_off: 50ms
    on_state: #when state is changed (since a toggle switch is used)
      then:
        - if:
            # if the output is on
            condition:
              switch.is_on: sprinkler_1
            then:
              - switch.turn_off: sprinkler_1
              - switch.turn_off: sw_timeout_arm #disable the sw_timeout_arm
              - globals.set: # reset the state of the timer (set _glbl_timeout_ticks to glbl_timeout_length_ticks),
                  id: _glbl_timeout_ticks
                  value: !lambda "return id(glbl_timeout_length_ticks);"
              - logger.log:
                  level: DEBUG
                  format: "Button1 pressed, output switched off. sw_timeout_arm disabled"
            else:
              - switch.turn_on: sprinkler_1 #logic if sprinkler is allowed to be turned on is contained within the sprinkler
              - logger.log:
                  level: DEBUG
                  format: "Button1 pressed, output was off before, is now turned on."
    internal: false


sensor:
  # Power Sensor
  - platform: ade7953
    irq_pin: GPIO27
    voltage:
      name: "${node_name} Voltage"
    current_a:
      name: "${output_name_2} Current"
    active_power_a:
      name: "${output_name_2} Power"
      id: power_channel_2
      filters:
        - multiply: -1
    current_b:
      name: "${output_name_1} Current"
    active_power_b:
      name: "${output_name_1} Power"
      id: power_channel_1
    update_interval: 10s


  # Internal NTC Temperature sensor
  - platform: ntc
    sensor: temp_resistance_reading
    name: "${node_name} Temperature"
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    icon: "mdi:thermometer"
    entity_category: 'diagnostic'
    calibration:
      b_constant: 3350
      reference_resistance: 4.7kOhm
      reference_temperature: 298.15K
    on_value_range:
      - above: ${max_temp}
        then:
          - homeassistant.event:
              event: esphome.overheat
              data:
                title: "${node_name} has overheated."

  # Required for NTC sensor
  - platform: resistance
    id: temp_resistance_reading
    sensor: temp_analog_reading
    configuration: DOWNSTREAM
    resistor: 5.6kOhm

  # Required for NTC sensor
  - platform: adc
    id: temp_analog_reading
    pin: GPIO35
    attenuation: 11db
    update_interval: 10s

  # WiFi Signal sensor.
  - platform: wifi_signal
    name: ${node_name} WiFi Signal
    update_interval: 180s
    entity_category: 'diagnostic'

# Text sensors with general information.
text_sensor:
#   # Expose ESPHome version as sensor.
  - platform: version
    name: ${node_name} ESPHome Version
    entity_category: 'diagnostic'
#   # Expose WiFi information as sensors.
  - platform: wifi_info
    ip_address:
      name: ${node_name} IP
      entity_category: 'diagnostic'
    ssid:
      name: ${node_name} SSID
      entity_category: 'diagnostic'

globals:
  # For the auto-off automation
  - id: glbl_timeout_armed
    type: bool
    restore_value: yes
    initial_value: "true"

  - id: glbl_timeout_length_ticks
    type: int
    restore_value: yes
    # 5 min * 60 seconds = 300
    initial_value: "300"

  # We ALSO need to keep track of the number of 'ticks'
  # add _prefix to indicate 'internal'
  - id: _glbl_timeout_ticks
    type: int
    restore_value: no
    initial_value: "0"

script:
    # End meaning the natural conclusion of the timer. Do whatever we're supposed to do when the timer fires off
  - id: on_timer_end
    mode: single
    then:
      - switch.turn_off: sprinkler_1
      - logger.log: "on_timer_end: output should be off!"

    # Stop meaning the pre-mature ending of the timer
  - id: on_timer_stop
    # Do not start a new run. Issue a warning.
    mode: single
    then:
        # For now, just clean up the globals and stop the ticking.
        # This hook could be used to do so much more, though.
        ##
      - lambda: |-
          auto TAG = "script.on_timer_stop";

          id(_timer_tick).stop();
          id(_glbl_timeout_ticks) = 0;
          ESP_LOGD(TAG, "_timer_tick now stopped and _glbl_timeout_ticks is %d", id(_glbl_timeout_ticks));          

  - id: _timer_tick
    # Start a new run after previous runs completes. This will happen until timer.stop() is called on us
    ##
    mode: queued
    then:
      # A single 'tick' is 1 second long
      - delay: 1s
      - lambda: |-
          auto TAG = "lambda._timer_tick";

          // First, update the number of ticks
          id(_glbl_timeout_ticks) += 1;

          // Then check if we have timed out
          if (id(_glbl_timeout_ticks) >= id(glbl_timeout_length_ticks) ) {

            // If we have timed out, run the script to handle the timer expiration
            // It's cleaner to call out to a script rather than put all the "what no?" code in here!
            id(on_timer_end).execute();

            ESP_LOGD(TAG, "_glbl_timeout_ticks is >= glbl_timeout_length_ticks  %d >= %d ", id(_glbl_timeout_ticks), id(glbl_timeout_length_ticks) );

            // And then re-set the internal counter
            id(_glbl_timeout_ticks) = 0;

            // And finally, stop the ticking timer
            id(_timer_tick).stop();
            ESP_LOGD(TAG, "_timer_tick now stopped!");

          } else {

            ESP_LOGD(TAG, "_glbl_timeout_ticks is < glbl_timeout_length_ticks  %d < %d ", id(_glbl_timeout_ticks), id(glbl_timeout_length_ticks) );

            // make sure we run again.. unless we're not supposed to
            if( id(glbl_timeout_armed) ) {
              id(_timer_tick).execute();
            }

          }

Make sure you have correctly entered the Wi-Fi network credentials (SSID and password) in the secrets (wifi_ssid, wifi_password, wifi_ssid2, wifi_password2, wifi_ssid3, wifi_password3). Also, it is sometimes preferable to flash a different code before reflashing this code

It is sometimes preferable to flash a different code first and then reflash this code

PS: try this code: Arrosage automatique - Automatic Sprinkler - #6 by Socrate

really cool piece of code you shared! but unfortunately I don’t have the physical option to add in sensors and multiple watering zones. I only have a single output from the shelly device I can use to trigger a valve. The electrical routing in my house only has a single electricity line near the water supply. It is routed to a single wall socket on the inside of the house. I’m happy i was able to even fit a Shelly plus 2pm in there.

The SSID and passwords where indeed provided in the secrets yaml.

Merci pour ce retour,
il vous suffit juste de supprimer dans le code les éléments en trop

Socrate

Pretty positive it’s your BT Proxy and BLE Tracker lines. I recently got a Shelly 1 Plus specifically to use this functionality, but anytime I added BT Proxy it caused it to stop connecting to WiFi and I had to serially flash to recover. Spent hours with every permutation of things I could think of and never got it to work. Ended up returning them, unfortunately…