I’ve managed to implement the fallback using the amazing ping sensor, which is an external component by trombik. I use it to regularly ping Home Assistant from the ESP. The sensor exposes two values: latency and packet loss. When flipping the wall switch, I simply check if the packet loss is 100%. If it is, something must be amiss and it falls back to the relay instead.
It’s not a pretty solution and there are some downsides, but it works well enough for me. I can tweak the number of pings and the interval. More pings take more time but make false positives less likely. If I set the interval too short, I’m pinging a lot, which can become a problem if I have many devices doing this, though I don’t expect to run into this.
Shelly 1L config with fallback mode
substitutions:
device_name: kitchen
# Basic Config
esphome:
name: ${device_name}
platform: ESP8266
board: esp01_1m
libraries:
- ESP8266WiFi
- https://github.com/akaJes/AsyncPing#95ac7e4
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: ${device_name}
password: !secret wifi_password
logger:
api:
ota:
web_server:
port: 80
external_components:
- source: github://trombik/esphome-component-ping
components: [ ping ]
#==============================================================
switch:
- platform: gpio
pin: GPIO5
id: shelly_1l_relay
restore_mode: ALWAYS_ON
binary_sensor:
- platform: gpio
name: ${device_name} Input
pin:
number: GPIO4
# small delay to prevent debouncing
filters:
- delayed_on_off: 50ms
on_state:
then:
- if:
condition:
and:
- wifi.connected:
- api.connected:
- switch.is_on: shelly_1l_relay
- lambda: return id(packet_loss).state < 100;
# toggle smart light if wifi and api are connected and relay is on
then:
# - switch.toggle: shelly_1l_relay
- logger.log:
format: "Packet loss '%.1f'"
args: [ 'id(packet_loss).state' ]
- homeassistant.service:
service: light.toggle
data:
entity_id: light.kitchen_lights
# else, toggle relay
else:
- switch.toggle: shelly_1l_relay
id: button
sensor:
- platform: ping
# IP address of Home Assistant
ip_address: 192.168.178.22
# number of packets to send
num_attempts: 5
# the timeout. however, this is not what you usually expect from `ping`
# implementation: the timeout is also the interval to send packets. if you
# set this value to 10 sec, and the network is fine (no packet loss), then
# the component sends a packet at 10 sec interval, and the total time to
# finish would be 10 sec * num_attempts = 10 * 17 = 170 sec.
timeout: 1sec
loss:
# the name to be shown.
id: packet_loss
name: Packet loss
latency:
# the name to be shown.
id: latency
name: Latency
# this should be 3 as the value is float, unit is sec, and the raw
# values are in ms.
accuracy_decimals: 3
# the interval for checking the sensors. defaults to 60s.
update_interval: 10s
status_led:
pin: GPIO0
Note that ping
depends on two additional libraries, which are included in the first block.
To make the fallback mode complete, I’ve configured my Zigbee smart bulbs to turn on by default after loss of power. This ensures that if a bulb is ‘soft off’ (powered, but shut off by HA) and a problem occurs, I can take the power off using the wall switch (utilizing the Shelly in fallback mode) and then on again, which will turn the light on (since that’s the default).
I’m pretty confident this will enable me to use my lights as long as I have power Let me know if this was useful to any of you!