Monitoring your Unifi AP

The template warning are there because the unifi_ap sensor doesn’t show up.

Maybe you should try with
sudo python /config/scripts/unifi.py
or
sudo python3 /config/scripts/unifi.py

I am not familiar with the supervised installation so I do not know how it tries to run the commands.

As a last resort, you may want to publish the data via mqtt.
For example, with paho.mqtt
If you need help trying this approach let me know.

Is there away specify the server type ?

I have a cloudkey that is running the same OS as that is on the Dream Machines. Seems like it is being picked up as a cloudkey/classic under “UnifiServerType” and not the new unifiOS that is on the dream machine.

It works perfectly with, GitHub - custom-components/sensor.unifigateway: High level health status of UniFi Security Gateway devices via UniFi Controller

After some tinker and playing around, managed to get it to work for me with 2 issue… Total client for ap/2.4ghz/5ghz are showing up as total for 3 ap’s and not per ap’s. Also not able to pull the guest connected to the ap’s.

Here is how I changed it: GitHub - w1tw0lf/Unifi-AP-Device-info: Unifi AP Device info via API for home assistant

PS: thank you @valvex for the inspiration

1 Like

going to give this a try, question about:
target_mac = ‘’ ## the mac address of your AP device

I have 2 ap’s how to add this?

You would basically need to have two unifi_ap.py files.

unifi_ap1.py for first ap
unifi_ap2.py for second ap

Then the sensors in configuration.yaml will need be duplicated and every unifi_ap will need to be replaced with unifi_ap1 and the duplicate section with unifi_ap2

The same for the card as well. You can replace unifi_ap1 and unifi_ap with ap names as in controller as what I did.

PS: clients and guest per ap is fixed now as well.

thanks… first I need to get the connection working :slight_smile:

For some reason can’t your code working, the original is working only some sensors are not correct.

For now i have this, need to look to get some more info out of my switch

What errors are you getting ? What controller type are you running ? Do you have the unifigateway component installed ?

Code updated and fixed. Showing correct info for everything as far as I can see, even for users of 2.4ghz and 5ghz per ap.

in short,

wifi0clients = sum(1 for _ in re.finditer(r'\b%s\b' % re.escape('wifi0'), str(clients)))
wifi0clients = sum(1 for _ in re.finditer(r'\b%s\b' % re.escape('wifi1'), str(clients)))

needs to change to

wifi0clients = devs['radio_table_stats'][0]['user-num_sta']
wifi1clients = devs['radio_table_stats'][1]['user-num_sta']

hassio_card

1 Like

With SSL on false and true

bash-5.1# python3 unifi_ap.py
/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host ‘192.168.179.202’. Adding certificate verification is strongly advised. See: Advanced Usage - urllib3 1.26.6 documentation
warnings.warn(
Traceback (most recent call last):
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 699, in urlopen
httplib_response = self._make_request(
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 445, in _make_request
six.raise_from(e, None)
File “”, line 3, in raise_from
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 440, in _make_request
httplib_response = conn.getresponse()
File “/usr/local/lib/python3.9/http/client.py”, line 1349, in getresponse
response.begin()
File “/usr/local/lib/python3.9/http/client.py”, line 316, in begin
version, status, reason = self._read_status()
File “/usr/local/lib/python3.9/http/client.py”, line 285, in _read_status
raise RemoteDisconnected(“Remote end closed connection without”
http.client.RemoteDisconnected: Remote end closed connection without response

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/usr/local/lib/python3.9/site-packages/requests/adapters.py”, line 439, in send
resp = conn.urlopen(
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 755, in urlopen
retries = retries.increment(
File “/usr/local/lib/python3.9/site-packages/urllib3/util/retry.py”, line 532, in increment
raise six.reraise(type(error), error, _stacktrace)
File “/usr/local/lib/python3.9/site-packages/urllib3/packages/six.py”, line 769, in reraise
raise value.with_traceback(tb)
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 699, in urlopen
httplib_response = self._make_request(
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 445, in _make_request
six.raise_from(e, None)
File “”, line 3, in raise_from
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 440, in _make_request
httplib_response = conn.getresponse()
File “/usr/local/lib/python3.9/http/client.py”, line 1349, in getresponse
response.begin()
File “/usr/local/lib/python3.9/http/client.py”, line 316, in begin
version, status, reason = self._read_status()
File “/usr/local/lib/python3.9/http/client.py”, line 285, in _read_status
raise RemoteDisconnected(“Remote end closed connection without”
urllib3.exceptions.ProtocolError: (‘Connection aborted.’, RemoteDisconnected(‘Remote end closed connection without response’))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/config/script/unifi_ap.py”, line 17, in
client = Controller(host, username, password, port, version,
File “/usr/local/lib/python3.9/site-packages/pyunifi/controller.py”, line 113, in init
self._login()
File “/usr/local/lib/python3.9/site-packages/pyunifi/controller.py”, line 185, in _login
response = self.session.post(
File “/usr/local/lib/python3.9/site-packages/requests/sessions.py”, line 590, in post
return self.request(‘POST’, url, data=data, json=json, **kwargs)
File “/usr/local/lib/python3.9/site-packages/requests/sessions.py”, line 542, in request
resp = self.send(prep, **send_kwargs)
File “/usr/local/lib/python3.9/site-packages/requests/sessions.py”, line 655, in send
r = adapter.send(request, **kwargs)
File “/usr/local/lib/python3.9/site-packages/requests/adapters.py”, line 498, in send
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: (‘Connection aborted.’, RemoteDisconnected(‘Remote end closed connection without response’))
bash-5.1# python3 unifi_ap.py
Traceback (most recent call last):
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 699, in urlopen
httplib_response = self._make_request(
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 382, in _make_request
self._validate_conn(conn)
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 1010, in validate_conn
conn.connect()
File “/usr/local/lib/python3.9/site-packages/urllib3/connection.py”, line 411, in connect
self.sock = ssl_wrap_socket(
File "/usr/local/lib/python3.9/site-packages/urllib3/util/ssl
.py", line 453, in ssl_wrap_socket
ssl_sock = ssl_wrap_socket_impl(sock, context, tls_in_tls)
File "/usr/local/lib/python3.9/site-packages/urllib3/util/ssl
.py", line 495, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock)
File “/usr/local/lib/python3.9/ssl.py”, line 500, in wrap_socket
return self.sslsocket_class._create(
File “/usr/local/lib/python3.9/ssl.py”, line 1040, in _create
self.do_handshake()
File “/usr/local/lib/python3.9/ssl.py”, line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1129)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/usr/local/lib/python3.9/site-packages/requests/adapters.py”, line 439, in send
resp = conn.urlopen(
File “/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py”, line 755, in urlopen
retries = retries.increment(
File “/usr/local/lib/python3.9/site-packages/urllib3/util/retry.py”, line 574, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host=‘192.168.179.202’, port=443): Max retries exceeded with url: /api/auth/login (Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1129)’)))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/config/script/unifi_ap.py”, line 17, in
client = Controller(host, username, password, port, version,
File “/usr/local/lib/python3.9/site-packages/pyunifi/controller.py”, line 113, in init
self._login()
File “/usr/local/lib/python3.9/site-packages/pyunifi/controller.py”, line 185, in _login
response = self.session.post(
File “/usr/local/lib/python3.9/site-packages/requests/sessions.py”, line 590, in post
return self.request(‘POST’, url, data=data, json=json, **kwargs)
File “/usr/local/lib/python3.9/site-packages/requests/sessions.py”, line 542, in request
resp = self.send(prep, **send_kwargs)
File “/usr/local/lib/python3.9/site-packages/requests/sessions.py”, line 655, in send
r = adapter.send(request, **kwargs)
File “/usr/local/lib/python3.9/site-packages/requests/adapters.py”, line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host=‘192.168.179.202’, port=443): Max retries exceeded with url: /api/auth/login (Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1129)’)))

also it looks like connecting to:

host=‘192.168.179.202’, port=443

but my settings are:
host = ‘192.168.179.202’
username = ‘Secret’
password = ‘Secret’
version = ‘UDMP-unifiOS’
site_id = ‘default’
port = ‘38193’

Got a feeling you not using a cloudkey or udm for controller, hence the custom port = ‘38193’.

Would suggest you look at changing the version that can be set to ‘v4’ or ‘UDMP-unifiOS’ Default value: v5.

If I look at the error it is trying to connect to port 443 and not 38193

correct not running cloudkey or UDM, running it on my Qnap nas…

port 443 and not 38193 this is what I did see also, but saw now it was changed in the error now complaining about certificates… need to dig a bit more

File “/usr/local/lib/python3.9/site-packages/requests/adapters.py”, line 227, in cert_verify
raise IOError("Could not find a suitable TLS CA certificate bundle, "
OSError: Could not find a suitable TLS CA certificate bundle, invalid path: True

Not sure about that issue. Thinking the way the qnap setups the controller is not the same as the default. You will need to look at how the api connects to the qnap instance.

Made few changes and added sensors for switches now as well. card_switch

1 Like

Have it working:

bash-5.1# python3 unifi_ap1.py 
/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.179.202'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
  warnings.warn(
{"Clients": 11, "Guests": 0, "Clients_wifi0": 8, "Clients_wifi1": 3, "Score": 94, "CPU": "32.1", "RAM": "43.9", "Uptime": "20d 2h 26m", "Score_wifi0": 99, "Score_wifi1": 83, "Activity": "4.5 Mbps", "Update": false}
bash-5.1# python3 unifi_ap2.py 
/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.179.202'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
  warnings.warn(
{"Clients": 4, "Guests": 0, "Clients_wifi0": 2, "Clients_wifi1": 2, "Score": 92, "CPU": "16.8", "RAM": "42.6", "Uptime": "20d 2h 21m", "Score_wifi0": 96, "Score_wifi1": 88, "Activity": "0.0 Mbps", "Update": false}
bash-5.1# python3 unifi_sw.py 
/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.179.202'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
  warnings.warn(
{"Model": "US8", "Activity": "5.2 Mbps", "CPU": "56.3", "RAM": "34.0", "Uptime": "20d 2h 22m", "Ports_used": 16, "Ports_user": 16, "Ports_guest": 0, "Update": false}
bash-5.1# 

Have done the following:

#### fill in your unifi controller credentials ####

host = '192.168.179.202'
username = 'Secret'
password = 'Secret'
version = 'unifiOS'
site_id = 'default'
port = '38193'
verify_ssl = False
target_mac = 'f0:9f:c2:19:52:c0' ## the mac address of your AP device

client = Controller(host=host,username=username,password=password,site_id=site_id,port=port,ssl_verify=verify_ssl)

I changed the client string, and that worked out…

Perfect. Thought that might be the issue.

1 Like

Many thanks for doing this and works great.

I have 5 APs so would have been a bit of effort to duplicate it 5 times so I made and APPDAEMON app from it, I am by no means an expert but it seems to work ok.

This will create all the sensors and update every 2 minutes as you had for all your APs specified in the target_macs field.

You will need to amend the cards to match each AP sensor names

No need for the command_line or template sensors

Don’t forget to add pyunifi to Appdaemon’s config

Not done the same for switches as not fussed about this level of detail for my switches but should be easily adaptable

EDIT: Have done it for my switches now to add POE ports power and voltage monitoring

from pyunifi.controller import Controller
import json
import re
import hassapi as hass
import datetime

class UnifiAPSW(hass.Hass):

    def initialize(self):
        self.log("Unifi AP and Switches Started")
        self.run_in(self.update_aps, 0)
        self.run_every(self.update_aps, datetime.datetime.now(), 600)
        self.run_in(self.update_switches, 0)
        self.run_every(self.update_switches, datetime.datetime.now(), 600)
        self.listen_event(self.unifi_update_event, "UNIFI_UPDATE")

    def unifi_update_event(self, UNIFI_UPDATE, data, kvargs):
        self.run_in(self.update_aps, 0)
        self.run_in(self.update_switches, 0)
 
    def update_aps(self, kwargs):
        self.log("Update APs Started")
        username = 'xxxxxxxxxxxxxxx'
        password = 'xxxxxxxxxxxx'
        target_macs = {'bedroom': 'xxxxx', 'bens_room': 'xxxxx', 'downstairs': 'xxxxx', 'garage': 'xxxxx', 'living_room': 'xxxxx'}
        for key in target_macs:
            entity = "sensor.unifi_" + key + "_ap"
            client = Controller('192.168.1.1', username, password, 443, 'UDMP-unifiOS', site_id='default', ssl_verify=False)
            stat = client.get_sysinfo()
            devs = client.get_device_stat(target_macs[key])
            #self.log(devs)
            clients = client.get_clients()
            numclients = int(devs['user-wlan-num_sta'])
            self.set_state(entity + "_clients", state = numclients, friendly_name = key.title() + " AP Clients", unit_of_measurement = "Clients")
            numguests = int(devs['guest-wlan-num_sta'])
            self.set_state(entity + "_guests", state = numguests, friendly_name = key.title() + " AP Guests", unit_of_measurement = "Guests")
            score = int(devs['satisfaction'])
            self.set_state(entity + "_score", state = score, friendly_name = key.title() + " AP Score", unit_of_measurement = "%" )
            update = devs['upgradable']
            self.set_state("binary_sensor.unifi_" + key + "_ap_update", state = update, friendly_name = key.title() + " AP Update", device_class="update" )
            cpu = float(devs['system-stats']['cpu'])
            self.set_state(entity + "_cpu", state = cpu, friendly_name = key.title() + " AP CPU", unit_of_measurement = "%")
            ram = float(devs['system-stats']['mem'])
            self.set_state(entity + "_ram", state = ram, friendly_name = key.title() + " AP RAM", unit_of_measurement = "%")
            activity = round(devs['uplink']['rx_bytes-r']/125000 + devs['uplink']['tx_bytes-r']/125000,1)
            self.set_state(entity + "_activity", state = activity, friendly_name = key.title() + " AP Activity")
            seconds = devs['uptime']
            days = seconds // 86400
            hours = (seconds - (days * 86400)) // 3600
            minutes = (seconds - (days * 86400) - (hours * 3600)) // 60
            uptime = str(days)+'d '+str(hours)+'h '+str(minutes)+'m'
            self.set_state(entity + "_uptime", state = uptime, friendly_name = key.title() + " AP Uptime")
            wifi0clients = int(devs['radio_table_stats'][0]['user-num_sta'])
            self.set_state(entity + "_2_4ghz_clients", state = wifi0clients, friendly_name = key.title() + " AP 2.4GHz Clients", unit_of_measurement = "Clients")
            wifi1clients = int(devs['radio_table_stats'][1]['user-num_sta'])
            self.set_state(entity + "_5ghz_clients", state = wifi1clients, friendly_name = key.title() + " AP 5GHz Clients", unit_of_measurement = "Clients")
            self.log(entity)
            model = devs['model']
            if model == 'UAL6':
                picture = "/local/images/unifiap62.png"
            elif model == 'U7IW':
                picture = "/local/images/unifiapiw2.png"   
            elif model == 'UHDIW':
                picture = "/local/images/unifiapiw2.png"   
            else:
                picture = "/local/images/unifiap62.png" 
            self.set_state(entity, state = numclients, attributes = {"entity_picture":picture, "Clients":numclients, "Guests":numguests, "Clients_wifi0":wifi0clients, "Clients_wifi1":wifi1clients, "Score":score, "CPU":str(cpu), "RAM":str(ram), "Uptime":uptime, "Activity":str(activity)+' Mbps', "Update":update})

    def update_switches(self, kwargs):
        self.log("Update Switches Started")
        username = 'xxxxxxxxxxx'
        password = 'xxxxxxx'
        target_macs = {'workshop_switch': xxxxxx', 'loft_switch': 'xxxxxx'}
        for key in target_macs:
            entity = "sensor.unifi_" + key
            client = Controller('192.168.1.1', username, password, 443, 'UDMP-unifiOS', site_id='default', ssl_verify=False)
            devs = client.get_device_stat(target_macs[key])
            model = devs['model']
            self.log('Switch Model: ' + model)
            for x in range(len(devs['port_table'])):
                port_poe = devs['port_table'][x]['port_poe']
                if port_poe == True:
                    port_name = devs['port_table'][x]['name']
                    poe_power = round(float(devs['port_table'][x]['poe_power']), 1)
                    poe_voltage = round(float(devs['port_table'][x]['poe_voltage']))
                    self.log(str(key) + ' Port ' + str(x+1) + ' ' + str(port_name) + ': ' + str(poe_power) + 'W' + ' ' + str(poe_voltage) + 'V')
                    self.set_state(entity + "_port" + str(x+1) + "_power", state = poe_power, attributes = {"friendly_name": port_name, "device_class": "power", "unit_of_measurement": "W", "model": model})
                    self.set_state(entity + "_port" + str(x+1) + "_voltage", state = poe_voltage, attributes = {"friendly_name": port_name, "device_class": "voltage", "unit_of_measurement": "V", "model": model})
                else:
                    self.log(str(key) + ' Port ' + str(x+1) + ": NOT POE")
2 Likes

Sorry if this has been asked before but I can’t see it in the thread. Is it possible to run this in my setup? I’m running Home Assistant OS on a Raspberry Pi4. I have no idea where to start with the Python interface installation - do I need something additional before this?

Definitely possible, I have AppDaemon running a repeating script to do exactly what you’re trying to do. Did you figure it out?

Nope - haven’t looked at it since though - got a few things going on at the moment. Can you share details of how that works?