Enable or disable a UniFi WiFi network via switch in Home Assistant

Because it doesn’t currently expose WiFi networks as switches to turn on/off. The UniFi Network integration is where I started with this expedition :slight_smile:

@thundergreen

Home Assistant OS mate.
Still struggling, can’t work out what I’m doing wrong.

I’ve tried all sorts (renaming file/ moving files, changing file paths in config, etc) - but been getting ‘not found’ error now.
image

Can view and (fail to) run the script via terminal, so permissions seem ok. I chown’ed the file to allow execution.

If you’ve got any other ideas, would be much appreciated!

Firstly, I think there may be an issue with the line-endings that’s producing the errors mentioning \r. I’ll bet you use a Windows machine and copy-based the script into something and the line-endings were converted to Windows style but the script is expecting Linux style.

Try running this from your terminal:
sed -i.bak 's/\r$//' unifi_kids_wifi.sh

This will remove the carriage return style line endings in the original file and create a backup of the unedited file as unifi_kids_wifi.sh.bak. If this works, you can remove the backup file.

I’m still not sure if you’ve solved the permission issue though. From your terminal, can you paste the output of these commands in the directory where the unifi_kids_wifi.sh file lives? (One command per line)

whoami
pwd
ls -lha

I’m on windows - yeah.

First command run, then tried to run script

Second command results:
root
/root/config
-rwxrwxrwx

Thanks for your help on this mate.

Don’t think my sed script did the trick. Let’s try downloading it instead.

The following commands should download the script from my gist and mark it executable. From the terminal again:

curl -o unifi_kids_wifi.sh https://gist.githubusercontent.com/jcconnell/0ee6c9d5b25c572863e8ffa0a144e54b/raw/c99f6ce56abdd976e464817512d7fa9b0c80df29/unifi_wifi.sh
chmod +x unifi_kids_wifi.sh

Legend. !thanks a lot. That’s sorted it.

I’m guessing that’s what other people have also had issue with.
Working on my UDM Pro.

End2End instructions for others reading this:

Create local user/password within unifi for this application.

Get wifi network ID by:

  • Navigate to your controller and sign in.
  • Navigate to Settings > Wifi Networks.
  • Click Edit next to the SSID you’d like to control.
  • Copy the ID from the end of the URL.
  • In the following example, the ID is ( 000d00c0e0b0e00d00000000 ):
    https://example:8443/manage/site/default/settings/wlans/00bd00a6e0000e9da2cde10c/edit/000d00c0e0b0e00d00000000

Download script

//Open the terminal, I'm using 'Terminal' addon within Home Assistant OS - from Supervisor
cd /root/config/

//download latest file from github, names it to "unifi_kids_wifi.sh"
curl -o unifi_kids_wifi.sh https://raw.githubusercontent.com/rjcds/ha-api/main/udm_wlan_control_ha_os.sh

//add execution permission to file
chmod +x unifi_kids_wifi.sh 

Add the following to your configuration.yaml file

switch:
  - platform: command_line
    switches:
      kids_wifi:
        command_on: '/config/unifi_kids_wifi.sh [username] [password] [https://10.0.0.1] [WLAN_ID] enable'
        command_off: '/config/unifi_kids_wifi.sh [username] [password] [https://10.0.0.1] [WLAN_ID] disable'
        command_state: '/config/unifi_kids_wifi.sh [username] [password] [https://10.0.0.1] [WLAN_ID] status'
        friendly_name: Kids WiFi

Change the details within the configuration to set username/ password/ UDM address and WLAN_ID

Restart home assistant.

You’ll now have an entity called ‘switch.kids_wifi’, that will show current state, and allow you to trigger on/ off.


Huge shout out to @jcconnell for initial development, and @rjcds for latest version working on UDM Pro (adding support for CSRF token)

FYI:
@jmmitchell81 @JeanDiv14 @Robban @mlulham

4 Likes

Sorry but i cannot follow here anymore. I have switches created by the integration. I turn off the wifi for my stepson with this switch. Whats the gain of this threat here ? you want to block your kids to acces to internet right? Just use wifi switch of the integration.

yeah, that’s correct.
Weirdly, I don’t have WiFi switches on my UniFi network integration? Only switches for PoE ports on Network Switch.

They coming through by default for you?

nope you have to configure those

just make “configure” integration and step two allows you to chose those devices you want to have network control

Oh, clients yeah I see that. I wanted to turn off whole SSID though so I don’t have to keep updating with every new device.

Thanks anyway :slight_smile:

1 Like

Great work! Keen to use a similar set-up but more specifically target devices (i.e. using unifi firewall ruling). So basically keep the Wifi for the Kids alive but disable WAN. Anybody already implemented this in a script that I can use?

Thanks!

1 Like

I have started looking into it and for test purposes I have written a python script to play with the rules through REST api.
Wondering if you ended up with anything?

I ended up running a PHP script on my webserver, works perfect and allows you to fully control unify

For more details see:
https://community.ui.com/questions/PHP-client-class-to-access-the-UniFi-controller-API-updates-and-discussion/86cff6e2-06ad-46a2-8e0d-d91004f78752?page=38

Nice job!

Is it possible to add notification when clicked on switch button?
So i know that i really clicked it?

And also, can that switch disabled for waiting to the next state?

Is enabling/disabling wifi networks still planed by you for the official integration? I couldn’t get the script running, so I’m looking forward for a simpler way with the official integration.

Yes. I just want to get further along with my refactoring first. Because the more features I add before I’m done the longer it will take

1 Like

Hi all,

I have an UDM-Pro and can’t get it to work. My personal guess is that Ubiquiti changed the API since UniFi OS 2. These are the versions I have at the moment:

UniFi OS UDM Pro: 2.4.23 (EA)
Network: 7.3.80 (EA)

Is there anyway who has this working with these versions?

For what reason is Ubiuiti not publishing the capablity to pause and resume wifi networks via API? They publish quit a lot about the API but not this specific one. I can’t think for what reason they keep it secret.

I’ve tried to discover a way myself by using the developer mode but haven’t succeed yet.

Hello,

I have the UDM and the shell script was also not working for me. So I went on to investigate this:

  • UDM/UDM-pro (and possibly UDR, etc) expect a csrf token with the following requests after logging in. This is part of the token/cookie you get, but you need to extract it and send it along with the subsequent requests. I learned this from my own investigation and from the PHP Client class mentioned here in the thread.
  • The API endpoints are different. I found some useful information at this location: https://ubntwiki.com/products/software/unifi-controller/api

I then adjusted the script to this:

#!/bin/bash

unifi_username=USERNAME
unifi_password='PASSWORD'
unifi_controller=<your_endpoint>
wifi_id=<wifi_id>
cookie=/tmp/cookie
site_id=<site_id>

curl_cmd="curl -s -S --cookie ${cookie} --cookie-jar ${cookie} --insecure "

unifi_login() {
 # authenticate against unifi controller
 # Mute response by adding > /dev/null
 ${curl_cmd} -H "Content-Type: application/json" -X POST -d "{\"password\":\"$unifi_password\",\"username\":\"$unifi_username\"}" $unifi_controller/api/auth/login > /dev/null
}

unifi_logout() {
 # logout
 ${curl_cmd} $unifi_controller/logout
}

enable_wifi() {
 # enables guest wifi network
 # Mute response by adding > /dev/null
 ${curl_cmd} -H 'x-csrf-token: '$1 "$unifi_controller"'/proxy/network/api/s/default/rest/wlanconf/'"$wifi_id" -X PUT --data-binary '{"_id":"'"$site_id"'","enabled":true}' --compressed > /dev/null
}

disable_wifi() {
 # enables guest wifi network
 # Mute response by adding > /dev/null
 ${curl_cmd} -H 'x-csrf-token: '$1 "$unifi_controller"'/proxy/network/api/s/default/rest/wlanconf/'"$wifi_id" -X PUT --data-binary '{"_id":"'"$site_id"'","enabled":false}' --compressed > /dev/null
}

list_wifi() {
 # List available wifi networks
 ${curl_cmd} "$unifi_controller"'/proxy/network/api/s/default/rest/wlanconf' -X GET --compressed
}

check_status() {
 # checks wifi network status
 # Mute response by adding > /dev/null
 response=$(${curl_cmd} "$unifi_controller"'/proxy/network/api/s/default/rest/wlanconf/'"$wifi_id" --compressed)
 status=$(echo $response | jq ".data[0].enabled")
 if [ "$status" == "true" ]; then
 exit 0
 elif [ "$status" == "false" ]; then
 exit 1
 else
 echo exit -1
 fi
}

csrf_token() {
  token=$( cat ${cookie} | grep TOKEN | awk -F'\t' '{print $7}' | awk -F'.' '{print $2}' |  sed 's/$/====/' | fold -w 4 | sed '$ d' | tr -d '\n' | base64 -d | jq -r '.csrfToken')
  echo $token
}

unifi_login
token=$(csrf_token)
if [ "$1" == "enable" ]; then
 echo "Enabling WiFi."
 enable_wifi $token
elif [ "$1" == "disable" ]; then
 echo "Disabling WiFi."
 disable_wifi $token
elif [ "$1" == "status" ]; then
 check_status
elif [ "$1" == "list"]; then
  list_wifi
else
 echo "Must include command line parameter [enable|disable|status]."
fi
unifi_logout

The following line for extracting the csrfToken looks somewhat daunting; I just mixed something together very quickly, but hey, it works for now.

  token=$( cat ${cookie} | grep TOKEN | awk -F'\t' '{print $7}' | awk -F'.' '{print $2}' |  sed 's/$/====/' | fold -w 4 | sed '$ d' | tr -d '\n' | base64 -d | jq -r '.csrfToken')

Let me quickly explain what happens here:

  • cat ${cookie} : read the cookie-file and cat this to the next step
  • grep TOKEN: only keep the line containing ‘TOKEN’ (works for now, because there is only one line containing TOKEN)
  • awk -F'\t' '{print $7}': split the line at the tab (\t) characters. The cookie containing the csrfToken is the 7th element
  • awk -F'.' '{print $2}': the cookie is base64-encoded and contains dots for delimiting the different parts of the cookie. We split the remainder at the dots and keep the second part. We now have a B64-encoded JSON, but we can’t decode just yet. I have found that the base64-program included in the HomeAssistant docker image expects something with a length that is a multiple of 4. We have to pad the string with some extra =-characters to get a string with a length that is a multiple of 4. See linux - base64 -d decodes, but says invalid input - Unix & Linux Stack Exchange
  • sed 's/$/====/': add 4 = to the end of the string
  • fold -w 4: split the string into multiple parts after every 4 character (essentially adding a newline)
  • sed '$ d': delete the last part - this can be 1, 2, 3 or 4 characters, but thus ensuring that the remainder is a multiple of 4
  • tr -d '\n': remove the newline characters
  • base64 -d: decode the b64-encoded string
  • jq -r '.csrftoken': extract the csrfToken from the JSON and give it back as raw text

With some fiddling it now works for me. Maybe you still have to adjust the script to meet your needs, but now you know what you are looking for.

The script can also be made a little bit more intelligent. In the PHP script there is a check (for the http response code when logging in) to determine of it is unifi_os or not. And so on.

Just hope this helps other people.

1 Like

Quick (possibly stupid) question: What is the site_id, and how do I find it?

1 Like