Disclaimer: Most of this blog post has become obsolete since the Home Assistant Unifi Network integration now supports POE port control as a switch. Passthrough switching is not yet part of this, so below still the original post.
In a previous post I wrote about my journey in making our home as energy efficient as possible. This blog post is another step in keeping guard on what’s consuming power, while you might not be using it: POE based WiFi access points.
Because working from home has become an adopted way of working, having good WiFi at home is a prerequisite for me. That’s why I have multiple access points:
- One in our livingroom;
- One in the home office;
- One upstairs to cover the top floor;
- And even one in the garden to work outside.
But a lot of the time, these device are actually doing nothing! One could suffice to keep the stuff running with a little bit less performance.
That’s why I wanted to have a script that is able selectively shutdown access points on request, and enable them easily when I want the best WiFi experience. But I also want to automate this, so when we are not at home, the not necessary access points shutdown.
In come the capabilities of my Unifi hardware. I can just stop the power over ethernet (poe) on my Unifi switch. But unfortunately that’s not enough. I also have one access point which facilitates a poe passthrough strategy. And also that one I want to independently control.
This means I have to control 2 different devices to setup the correct port state, and on top of that, the Unifi provided API doesn’t allow overriding the configuration of a single port at the time. With these 2 caveats in mind I managed to craft the following script to deal with these challenges.
#!/bin/bash
if [ $# -lt 3 ]; then
echo "Usage : $0 port-nr state device"
exit
fi
if [ "$3" = "uap" ]; then
MAC=ma:co:fu:ap
else
MAC=ma:co:fu:sw
fi
DEVICE=/tmp/device-$3.json
COOKIE=/tmp/cookie.txt
PORTS=/tmp/ports-$3.json
ID=0
if [ ! -f "$COOKIE" ]; then
curl -X POST --insecure -H "Content-Type: application/json" -d '{
"username": "user",
"password": "password",
"remember": true
}' -c $COOKIE -o /dev/null -s https://ip-cloudkey:port/api/login
fi
if [ ! -f "$DEVICE" ]; then
curl -X GET --insecure -b $COOKIE -s https://ip-cloudkey:port/api/s/default/stat/device/$MAC > $DEVICE
fi
if [ -f "$DEVICE" ]; then
cat $DEVICE | jq "{port_overrides: .data[].port_overrides}" > $PORTS
ID=$(cat $DEVICE | jq -r '.data[]._id')
fi
if [ -f "$PORTS" ]; then
tmpfile=$(mktemp); cp $PORTS "$tmpfile" && jq --argjson PORT "$1" --arg MODE "$2" '.port_overrides[] |= (select(.port_idx==$PORT) |= (.poe_mode = $MODE))' "$tmpfile" > $PORTS && r
m -f "$tmpfile"
fi
sleep $((RANDOM % 10))
if [ -f "$DEVICE" ] && [ -f "$PORTS" ]; then
curl -X PUT --insecure -H "Content-Type: application/json" -b $COOKIE -d @$PORTS -o /dev/null -s https://ip-cloudkey:port/api/s/default/rest/device/$ID
fi
rm -f $DEVICE
rm -f $PORTS
rm -f $COOKIE
So what does this script then do step by step
- It first validates the input, to test the arguments and understand which device we want to control
- Then it logs in the the Cloud Key using a user with admin privileges
- The script downloads the state of the selected device, or skips if the file still exists
- It extracts the ID & port overrides section of the device
- If the port overrides file exits, it does an in place edit of the file to set the new state of the port
- A very important random sleep, which allows me the call the script multiple times at once and because the in place editing of the port overrides file merge all the requested changes
- Send the changes to the identified device. Possibly multiple times, but if there is no change, the call will be silently ignored.
Expose POE switch in HomeKit?
I’m using Home Assistant to control my home. 2 integrations allow me to control the Access Points as switches in HomeKit.
- HomeKit HA integration
- HA default command line switching
This looks like this in the configuration.yml
switch:
- platform: command_line
switches:
office_poe:
friendly_name: Wifi Office
command_on: "/bin/bash /config/script/poe-toggle.sh 6 auto usw"
command_off: "/bin/bash /config/script/poe-toggle.sh 6 off usw"
command_state: "/bin/bash /config/script/poe-state.sh 6 usw"
value_template: '{{ value == "auto" }}'
outside_poe:
friendly_name: Wifi Outside
command_on: "/bin/bash /config/script/poe-toggle.sh 1 passthrough uap"
command_off: "/bin/bash /config/script/poe-toggle.sh 1 off uap"
command_state: "/bin/bash /config/script/poe-state.sh 1 uap"
value_template: '{{ value == "passthrough" }}'
With this configuration in place in Home Assistant you can expose the Access Points as switches in HomeKit, allowing you to toggle a Wifi Access Point on or off or add them to any form of automation you have in mind.
Now when we leave the house, or go to bed, only one access points remains on which saves 25 watts of energy consumption!
Resources
- Bash script source code on gist.github.com