Introduction
Running various services at home can be a great convenience, but it’s incredibly frustrating when the network goes down and you’re not there to restart everything. I’ve considered using my Home Assistant instance to reboot my modem, but I’m uncertain about its effectiveness since it heavily relies on a stable internet connection.
While there are commercial solutions like the WattBox that perform well, they can be quite expensive. As an alternative, ESPHome is an excellent open-source solution that allows you to flash hardware running either the ESP32 or ESP8266 microcontrollers with completely open-source software. I’ve used ESPHome for some personal projects like my Light-Up picture frame and to replace commercial devices like the Sonoff S31.
ESPHome Scripting
Previously, I’ve only used ESPHome as firmware to connect devices to Home Assistant, but it’s capable of so much more. In this guide, I will show you how to create an ESPHome script that automatically restarts your modem when the network signal drops.
What’s really cool about this project is that you can upload it onto a $9 Sonoff S31 Smart Switch and it’ll be able to reboot your modem, router or even Home Assistant instance.
Here’s what this ESPHome script does:
-
Monitor packet loss: The script continuously monitors packet loss by sending ICMP (ping) requests to a designated target, such as a well-known DNS server like 8.8.8.8.
-
Determine the need for a restart: If the script detects a certain number of consecutive packet losses (e.g., 3 minutes in a row), it determines that a modem restart is necessary.
-
Control the Relay inside the Sonoff S31: The script runs on a Sonoff S31 smart plug and it can turn the plug off, and then on again to restart the modem.
-
Implement a 15 minute pause: At most this script will restart your modem once every 15 minutes. This should give it enough time to reconnect to the internet. It also holds off on restarting within the first 15 minutes of its own boot up process so it gives everything time to stabilize.
Setting Up the ESPHome Script
To set up the ESPHome auto-restart script, follow these steps:
-
First, install the install ESPHome addon on your Home Assistant instance.
-
Flash the Sonoff S31 with ESPHome using this guide.
-
Create a new ESPHome configuration file (e.g., sonoff_s31.yaml
) for the Sonoff S31 and customize it with the auto-restart script provided below.
-
Let Home Assistant do the hard work of compiling your script and uploading it to the device.
-
Configure the Sonoff S31 in Home Assistant, you’ll be able to see the report of the ping time and packet loss there, but it should handle it’s reboot process without Home Assistant running.
With the ESPHome auto-restart script in place, you can now enjoy a more reliable and stable internet connection without worrying about manual restarts.
# Basic Config
esphome:
name: sonoff-cable-modem
platform: ESP8266
board: esp01_1m
libraries:
- ESP8266WiFi
- https://github.com/akaJes/AsyncPing#95ac7e4
external_components:
- source:
type: git
url: https://github.com/trombik/esphome-component-ping
ref: main
wifi:
ssid: xxxxxxxxxxxxxxxxxxx
password: xxxxxxxxxxxxxxxxxxx
ap:
ssid: "Sonoff5" # in case it can't connect and you need to reprogram it
password: "xxxxxxxxxxxxxxxxxxx"
logger:
baud_rate: 0 # (UART logging interferes with cse7766)
# Enable Home Assistant API
api:
encryption:
key: "xxxxxxxxxxxxxxxxxxx"
ota:
password: "xxxxxxxxxxxxxxxxxxx"
# Device Specific Config
uart:
rx_pin: RX
baud_rate: 4800
binary_sensor:
- platform: gpio
pin:
number: GPIO0
mode: INPUT_PULLUP
inverted: True
name: "Sonoff Cable Modem Button"
on_press:
- script.execute: power_cycle_relay
- platform: status
name: "Sonoff Cable Modem Status"
sensor:
- platform: wifi_signal
name: "Sonoff Cable Modem WiFi Signal"
update_interval: 60s
- platform: cse7766
current:
name: "Sonoff Cable Modem Current"
accuracy_decimals: 1
voltage:
name: "Sonoff Cable Modem Voltage"
accuracy_decimals: 1
power:
name: "Sonoff Cable Modem Power"
accuracy_decimals: 1
- platform: ping
ip_address: 8.8.8.8
id: ping_response
num_attempts: 1
timeout: 1sec
loss:
name: "Packet Loss to Internet"
id: loss
latency:
name: "Latency to Internet"
accuracy_decimals: 3
update_interval: 30s
switch:
- platform: gpio
name: "Sonoff Cable Modem Relay"
pin: GPIO12
id: relay
restore_mode: ALWAYS_ON
status_led:
pin: GPIO13
globals:
- id: last_power_cycle
type: time_t
restore_value: no
initial_value: '0'
- id: packet_loss_count
type: int
restore_value: no
initial_value: '0'
# Ping time (in seconds)
interval:
- interval: 60s
then:
- script.execute: ping_check
# Script for checking packet loss
script:
- id: ping_check
then:
- if:
condition:
# Condition checks if packet loss has occurred
lambda: 'return id(loss).state > 0;'
then:
# If packet loss has occurred, increment packet_loss_count
- lambda: |-
id(packet_loss_count) += 1;
// If there are 3 consecutive packet losses, reset the count and execute power_cycle_relay script
if (id(packet_loss_count) >= 3) {
id(packet_loss_count) = 0;
id(power_cycle_relay).execute();
}
else:
# If there's no packet loss, reset the packet_loss_count
- lambda: |-
id(packet_loss_count) = 0;
# Script for power cycling the relay
- id: power_cycle_relay
then:
- lambda: |-
time_t now = id(esphome_time).now().timestamp;
// Do not power cycle during the first 15 minutes after boot
if (now < 900) {
ESP_LOGD("power_cycle_relay", "Skipping power cycle during the first 15 minutes after boot");
return;
}
// Do not power cycle if the last power cycle was less than 15 minutes ago
if ((now - id(last_power_cycle)) < 900) {
ESP_LOGD("power_cycle_relay", "Skipping power cycle since it's been less than 15 minutes since the last one");
return;
}
// Update the last power cycle timestamp and execute the power cycle
id(last_power_cycle) = now;
ESP_LOGD("power_cycle_relay", "Power cycling the relay due to button press or packet loss.");
id(relay).turn_off();
- delay: 5s
- lambda: |-
id(relay).turn_on();
time:
- platform: sntp
id: esphome_time
servers:
- 0.pool.ntp.org