Automating Home Server Shutdowns During Power Cuts

- Hariharan

There are frequent power cuts where I live which make it difficult to run a home server with a decent uptime. I do have a UPS, but it doesn’t have any smart features. Whenever there is a power cut, I have to manually shut down my home server. This is only possible when I am home because I have completely locked down SSH access.

I could get a smart UPS but those are very expensive. I just needed a way to detect power cuts and send a shutdown signal to the server. This felt doable using a smart socket and Home Assistant.

How it works

I run Home Assistant on a Raspberry Pi 4 which is connected to the UPS. I don’t have to worry about the power draw on a Pi 4, I can keep it running for a long time even on UPS.

I have connected the UPS to the wall socket using a smart socket. The smart socket goes offline whenever there is a power cut. This can be detected on Home Assistant which sends a shutdown signal to the server using a webhook.

Architecture

Choosing a Smart Socket

I wanted a smart socket that could be operated fully locally especially for this use-case when the internet connection could be affected during power cuts. Zigbee and ZWave devices looked interesting but there are very few options in India. They also need a hub which adds to the cost. Most WiFI smart sockets I found needed an internet connection. Eventually, I came across Philips Wiz Socket. It uses Wiz Connected platform which seemed to support local communication and was natively supported in Home Assistant. I decided to give it a shot.

Source: indiamart.com

Setting up the socket was fairly simple. There is a Wiz app that communicates with the socket over Bluetooth for the initial setup. Here we configure the WiFi credentials. Once the socket is connected, you can simply add it to Home Assistant using its IP. This socket also has a very useful power sensor.

Home Assistant Dashboard

Since this was my first “smart” device, I created a separate IoT WiFi network with proper firewall configurations to disable the internet and LAN access from this network.

Power Requirements

My primary server has a Ryzen 3600 and an old GT710 GPU. I also have a Raspberry Pi 4 that runs networking stuff like DNS and Traefik and also Home Assistant. The services on the Pi 4 are fairly critical and need to be running even during power cuts.

The PC and the Pi can draw about 80 Watts when idle. My current UPS can supply 1000VA (600W). It has 2 12V 7Ah batteries. With the power factor of 0.6 that’s roughly 12*7*2*0.6 = 100.8Wh. The total runtime would be about 1.26 hours (100.8Wh/80W). So I should ideally shut down the server in about 30 minutes after a power cut so that I don’t completely drain the UPS and have enough power to keep the Pi running.

Server Setup

To create the webhook server, I used a tool called webhook. It is available in the official Debian repos.

hooks.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
- id: shutdown
  execute-command: "/home/server/shutdown.sh"
  response-message: "shutdown started"
  trigger-rule:
    match:
      type: value
      value: <insert_token_here>
      parameter:
        source: url
        name: token

This config creates a webhook that can be triggered by calling /hooks/shutdown?token=<insert_token_here>. On a successful trigger, it runs the command specified which is a bash script.

shutdown.sh
1
2
3
4
5
6
7
#!/bin/bash

# Optional notification using gotify
curl -X POST "http://gotify_api_endpoint" -F "title=Automatic Shutdown" -F "message=Shutting down. Command received over webhook."

sudo shutdown -h now

This script sends a notification using Gotify and shuts down the server. I run Gotify on the Raspberry Pi.

To start this server on boot, I created a basic systemd service.

shutdown-webhook.service
1
2
3
4
5
6
7
8
[Unit]
Description=webhook service that can shutdown the server

[Service]
ExecStart=webhook -hooks /home/server/hooks.yml -verbose

[Install]
WantedBy=multi-user.target

Home Assistant Automation

The Home Assistant automation should be triggered when the smart socket goes from on to unavailable for 30 minutes.

shutdown-automation.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
alias: Shutdown Automation
description: ""
trigger:
  - platform: state
    entity_id:
      - switch.wiz_socket_2760b8
    from: "on"
    to: unavailable
    for:
      hours: 0
      minutes: 30
      seconds: 0
condition: []
action:
  - service: rest_command.shutdown_command
    data: {}
    response_variable: shutdown_response
  - service: notify.mobile_app_pixel_7
    data:
      title: Automatic Shutdown
      message: "{{ shutdown_response }}"
mode: single
Home Assistant Automation
This automation calls the shutdown webhook and sends a notification to my phone.

We need a rest service to call the webhook. This can be added using the Home Assistant configuration.yml.

1
2
3
rest_command:
  shutdown_command:
    url: "http://<webhook_address>/hooks/shutdown?token=<insert_token_here>"

Conclusion

I have already had 3 power cuts since I implemented this. One of them was above 30 mins and this worked great! I want to expand on this by adding automated restarts using wake-on-LAN. I couldn’t quite get it to work yet. Once it does, this could be a complete solution.