Monitoring your Unifi AP

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?

I came up with this as an alternative if anyone is interested.

which one is the latest version?

or

GitHub - RubenDijk/homeassistant: Homeassistant stuff (this one is the linked on the top)

I’d love to get it working but I am stuck somewhere. Could you help me?
Currently I run 8 AP on a controller which is installed on a pi (Version 6.5.55), without a self-signed certificate (browser states that the certificate is not trustworthy) . My last try for the first AP was:

host = ‘Controller-IP
username = ‘Unifi-User
password = ‘Unifi-PW
version = ‘v6’
site_id = ‘default’
port = ‘8443’
verify_ssl = False
target_mac = ‘Unifi-Mac’ ## the mac address of your AP device

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

All I get is this error:

[homeassistant.components.command_line] Command failed: python3 /config/scripts/unifi_ap1.py

I also tried version v5; version unifiOS; and verify_ssl = True

Which device you running on ? Are you running a stand alone controller ? Think the port might be wrong.

I run the controller on a raspi 4, 8443 is the port I access the controller with my browser

Update: I tried Port 443 in combination with Version v5 and unifiOS as well as in combination with ssl = True and ssl= false.

no success so far.

Did you add the custom component: GitHub - custom-components/sensor.unifigateway: High level health status of UniFi Security Gateway devices via UniFi Controller ?

It needs some part of the component in order to work correctly.

Yes, this component is up and running. I’ll try more possibilities later on but for now I’ll let it be.

Thanks a lot @w1tw0lf for this project.
It’s exactly what I needed.
I’ve met some issues like some other people here.
Pay attention to setup the correct AP version !
Only 1 pending “issue” on my side.
I don’t have any icon shown. I keep eye icon in the card and on the entity as well.
Any hint on that ?
Thanks

Mind sharing a screenshot of the card ?

Here it is :
2022-02-08 08_40_07-Home – Home Assistant

For the icon, you need to customize the entity, sensor.****_ap with an entity picture. You can place the file as a *.png under /config/www

I uploaded the 5 that i have to the git page