- 3 min read
A few of my tech projects experience occasional hiccups and need to be soft-reset from my Linux host (e.g. Wi-Fi SSID routed through VPN, Windows gaming VM with hardware passthough). This was annoying as it meant having a machine nearby to SSH and execute a few simple commands — often just a systemctl restart foo
. Fortunately, homebridge-cmdswitch2 can easily expose arbitrary commands as lights so I would be able to easily bounce the services via my phone.
First, since Homebridge should be running as its own system user, we need to give it permissions to restart services (as root). We don’t want to grant services to all of /bin/systemctl
, so a wrapper script will be placed at /usr/local/bin/serviceswitch
to encapsulate the desired behavior. Grant the homebridge
user permission to run it with sudo:
cat /etc/sudoers.d/homebridge-cmdswitch
homebridge ALL = (root) NOPASSWD: /usr/local/bin/serviceswitch
Next, let’s create that /usr/local/bin/serviceswitch
script with service status, start and stop commands - using such a wrapper also has the benefit that complex checks consisting of several commands can be performed. Keep in mind these are now being run as root from Homebridge!
#!/bin/sh
if [ "$(id -u)" -ne 0 ];then
echo "You must run this script as root."
exit 1
fi
usage() {
error="$1"
if [ ! -z "$error" ];then
echo "Error: $error"
fi
echo "Usage: $0 [action] [service]"
}
action="$1"
service="$2"
if [ -z "$action" ] || [ -z "$service" ];then
usage
exit 1
fi
case $action in
start|stop|status) ;;
*) usage "invalid action, must be one of [start, stop, status]"; exit 1;;
esac
case $service in
vm-guests)
[ "$action" == "start" ] && (systemctl start libvirt-guests)
[ "$action" == "stop" ] && (systemctl stop libvirt-guests)
[ "$action" == "status" ] && { systemctl -q is-active libvirt-guests; exit $?; }
;;
fileserver)
[ "$action" == "start" ] && (systemctl start smb;systemctl start nmb;systemctl start netatalk)
[ "$action" == "stop" ] && (systemctl stop smb;systemctl stop nmb;systemctl stop netatalk)
[ "$action" == "status" ] && { (systemctl -q is-active smb && systemctl -q is-active nmb && systemctl -q is-active netatalk); exit $?; }
;;
web)
[ "$action" == "start" ] && (systemctl start httpd)
[ "$action" == "stop" ] && (systemctl stop httpd)
[ "$action" == "status" ] && { systemctl -q is-active httpd; exit $?; }
;;
*) usage "invalid service"; exit 1;;
esac
exit 0
Finally, here is the relevant platform section from the homebridge config:
{
"platforms": [{
"platform": "cmdSwitch2",
"name": "Command Switch",
"switches": [{
"name" : "vm-guests",
"on_cmd": "sudo /usr/local/bin/serviceswitch start vm-guests",
"off_cmd": "sudo /usr/local/bin/serviceswitch stop vm-guests",
"state_cmd": "sudo /usr/local/bin/serviceswitch status vm-guests",
"polling": false,
"interval": 5,
"timeout": 10000
},
{
"name" : "fileserver",
"on_cmd": "sudo /usr/local/bin/serviceswitch start fileserver",
"off_cmd": "sudo /usr/local/bin/serviceswitch stop fileserver",
"state_cmd": "sudo /usr/local/bin/serviceswitch status fileserver",
"polling": false,
"interval": 5,
"timeout": 10000
},
{
"name" : "web",
"on_cmd": "sudo /usr/local/bin/serviceswitch start web",
"off_cmd": "sudo /usr/local/bin/serviceswitch stop web",
"state_cmd": "sudo /usr/local/bin/serviceswitch status web",
"polling": false,
"interval": 5,
"timeout": 10000
}]
}]
}