custom-components / sensor.unifigateway

High level health status of UniFi Security Gateway devices via UniFi Controller
127 stars 41 forks source link

Update for sensor fails after a couple hours #59

Open myopenflixr opened 7 months ago

myopenflixr commented 7 months ago

I am having an error that seemed to start on Home Assistant 2023.11. After a couple hours of restarting Home Assistant, the sensors fail and stop updating. The only FIX is to restart Home Assistant to get the sensor data back. But, it stops working and throws errors again after a couple hours.

Here's two entries in the Logs showing the errors.

Any help would be greatly appreciated!

Logger: homeassistant.helpers.entity
Source: helpers/entity.py:696
First occurred: 12:38:35 PM (12 occurrences)
Last logged: 12:44:05 PM

Update for sensor.unifi_gateway_firmware_upgradable fails
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 696, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 959, in async_device_update
    await hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/util/__init__.py", line 190, in wrapper
    result = method(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/unifigateway/sensor.py", line 166, in update
    if devices.get('upgradable'):
       ^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
Logger: homeassistant.helpers.entity
Source: helpers/entity.py:696
First occurred: 12:38:35 PM (60 occurrences)
Last logged: 12:44:05 PM

Update for sensor.unifi_gateway_www fails
Update for sensor.unifi_gateway_wan fails
Update for sensor.unifi_gateway_wlan fails
Update for sensor.unifi_gateway_lan fails
Update for sensor.unifi_gateway_vpn fails
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 696, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 959, in async_device_update
    await hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/util/__init__.py", line 190, in wrapper
    result = method(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/unifigateway/sensor.py", line 178, in update
    if sub['subsystem'] == self._sensor:
       ~~~^^^^^^^^^^^^^
TypeError: string indices must be integers, not 'str'
SeeThisIsMe commented 6 months ago

I'm having exactly the same issue as well.

ykuijs commented 6 months ago

Same here! Works fine for a few hours and then starts failing until the next reboot.

Tamsy commented 6 months ago

Experiencing the same issue. Seems to be connected to the latest UniFi OS 3.2. Started here after having upgraded the UniFi Cloud Key.

Logger: homeassistant.helpers.entity
Source: helpers/entity.py:698
First occurred: 20:06:37 (32 occurrences)
Last logged: 20:22:07
Update for sensor.unifi_gateway_firmware_upgradable fails

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 698, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 961, in async_device_update
    await hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/util/__init__.py", line 190, in wrapper
    result = method(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/unifigateway/sensor.py", line 162, in update
    if devices.get('upgradable'):
       ^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
Logger: homeassistant.helpers.entity
Source: helpers/entity.py:698
First occurred: 20:06:37 (32 occurrences)
Last logged: 20:22:07

Update for sensor.unifi_gateway_alerts fails
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 698, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 961, in async_device_update
    await hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/util/__init__.py", line 190, in wrapper
    result = method(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/unifigateway/sensor.py", line 145, in update
    if not alert['archived']:
           ~~~~~^^^^^^^^^^^^
TypeError: string indices must be integers, not 'str'
Logger: homeassistant.helpers.entity
Source: helpers/entity.py:698
First occurred: 20:06:37 (128 occurrences)
Last logged: 20:22:07

Update for sensor.unifi_gateway_www fails
Update for sensor.unifi_gateway_wan fails
Update for sensor.unifi_gateway_wlan fails
Update for sensor.unifi_gateway_lan fails
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 698, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 961, in async_device_update
    await hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/util/__init__.py", line 190, in wrapper
    result = method(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/unifigateway/sensor.py", line 174, in update
    if sub['subsystem'] == self._sensor:
       ~~~^^^^^^^^^^^^^
TypeError: string indices must be integers, not 'str'
haroldboom commented 6 months ago

I have the same issue, if anyone finds a fix please let me know

martinkwright commented 6 months ago

Same here. Only option is to reload. Frustrating, given I have automation hung off this.

Tamsy commented 6 months ago

Seem to work again as it should with HA 2024.1.1. In case it stops again I will report here.

Addendum: I wrote too soon. The issue started again :(

DocEvel commented 6 months ago

Same here. After a reload it works for a couple of hours and then fails again.

canedje commented 6 months ago

same here.

Logger: homeassistant.helpers.entity
Source: helpers/entity.py:894
First occurred: 08:51:25 (1 occurrences)
Last logged: 08:51:25

Update for sensor.unifi_gateway_firmware_upgradable fails
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 894, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1214, in async_device_update
    await hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/util/__init__.py", line 190, in wrapper
    result = method(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/unifigateway/sensor.py", line 162, in update
    if devices.get('upgradable'):
       ^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
bobbinz commented 5 months ago

I also have this issue

canedje commented 5 months ago

last update was about 3 years. So I do not expect anything. A pitty

haroldboom commented 5 months ago

I guess it’s time to remove it?

Tamsy commented 5 months ago

I guess it’s time to remove it?

Sadly it pretty much looks like this useful tool has turned into abandonedware.

coldburn89 commented 5 months ago

Why is not anyone else taking over? Can't imagine some devs are not into this as ubiquiti is very popular! Same issue here. Only thing that helps is to reset the Template sensors or reboot HA

coldburn89 commented 5 months ago

I guess it’s time to remove it?

Sadly it pretty much looks like this useful tool has turned into abandonedware.

What about this one? https://github.com/zvldz/unifi_status/tree/master/custom_components/unifi_status

Looks like someone took over but its also not updated for 2 years

haroldboom commented 5 months ago

Why is not anyone else taking over? Can't imagine some devs are not into this as ubiquiti is very popular! Same issue here. Only thing that helps is to reset the Template sensors or reboot HA

I tried resetting the template sensors but it instantly fails for me. Yeah I wish I had the skills to take it over, it works so well

haroldboom commented 5 months ago

I guess it’s time to remove it?

Sadly it pretty much looks like this useful tool has turned into abandonedware.

What about this one? https://github.com/zvldz/unifi_status/tree/master/custom_components/unifi_status

Looks like someone took over but its also not updated for 2 years

Tried it and no good. I even tried removing code that I didn’t use like firmware and vpn but it still crashes.

Maybe @zvldz could fix it if anyone can get hold of them?

coldburn89 commented 5 months ago

I guess it’s time to remove it?

Sadly it pretty much looks like this useful tool has turned into abandonedware.

What about this one? https://github.com/zvldz/unifi_status/tree/master/custom_components/unifi_status Looks like someone took over but its also not updated for 2 years

Tried it and no good. I even tried removing code that I didn’t use like firmware and vpn but it still crashes.

Maybe @zvldz could fix it if anyone can get hold of them?

Since the new update today it's completely broken and the sensors doesn't work anymore. 😢

SeeThisIsMe commented 5 months ago

I managed to replace all the functionality I was using this for via other means quite easily. I get bits of information now for my dream machine SE instead using the official integration (status, uptime, external IP, and a few others) and a graph for bandwidth usage via SNMP.

Depending on what people used this for, you may be able to do the same without too much difficulty.

haroldboom commented 5 months ago

I tried SNMP but I couldn’t get CPU usage and also when it updated it wiped off my SNMP install. This is on the UDM-Pro

On Sat, 10 Feb 2024 at 11:51, SeeThisIsMe @.***> wrote:

I managed to replace all the functionality I was using this for via other means quite easily. I get bits of information now for my dream machine SE instead using the official integration (status, uptime, external IP, and a few others) and a graph for bandwidth usage via SNMP.

Depending on what people used this for, you may be able to do the same without too much difficulty.

— Reply to this email directly, view it on GitHub https://github.com/custom-components/sensor.unifigateway/issues/59#issuecomment-1936779870, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKH2FP66NCR2FFMEBTAS4PDYS2777AVCNFSM6AAAAABAE6EHR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZWG43TSOBXGA . You are receiving this because you are subscribed to this thread.Message ID: @.*** com>

coldburn89 commented 5 months ago

I managed to replace all the functionality I was using this for via other means quite easily. I get bits of information now for my dream machine SE instead using the official integration (status, uptime, external IP, and a few others) and a graph for bandwidth usage via SNMP.

Depending on what people used this for, you may be able to do the same without too much difficulty.

Do you mind sharing? I think alot of people will find that useful.

ykuijs commented 4 months ago

@SeeThisIsMe It would be really great if you could share the steps you took to get it to work. That will benefit many more of us.

johntdyer commented 4 months ago

Here is my "fix"... please note that this script grew organically over time as I moved features from the other plugins to my unified script ( pun intended ) ...

Disclosure: not once have I gone back over the code to refactor, clean up, or optimize!!

#!/usr/local/bin/python

from datetime import timedelta
import json, yaml, requests
from datetime import datetime
import requests,time
from re import sub
import sys

resp={}
resp['data']={}

def parse_uptime(uptime):
  seconds = 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'
  return uptime

controller_url = 'https://xxxxx.xxxxx.xxxxx'
username = 'xxxx'
password = 'xxxx'
site = 'default'  # The site ID, 'default' for most installations

login_url = f'{controller_url}/api/auth/login'
login_data = {
    'username': username,
    'password': password
}

session = requests.Session()
response = session.post(login_url, json=login_data, verify=True)
response.raise_for_status()

def snake_case(s):
  return '_'.join(
    sub('([A-Z][a-z]+)', r' \1',
    sub('([A-Z]+)', r' \1',
    s.replace('-', ' '))).split()).lower()

rules_url = 'https://xxxx.xxxx.xxxx/proxy/network/api/s/default/stat/device'

response = session.get(rules_url, verify=False)
response.raise_for_status()
rules = response.json()
sysinfo_url = 'https://xxxx.xxxx.xxxx/proxy/network/api/s/default/stat/sysinfo'

response = session.get(sysinfo_url, verify=False)
response.raise_for_status()
version = response.json()

health_url = 'https://xxxx.xxxx.xxx/proxy/network/api/s/default/stat/health'

response = session.get(health_url, verify=False)
response.raise_for_status()
health_data = response.json()

# keys = health_data['data'][0].keys()
# a = {k: set(d[k] for d in health_data['data']) for k in keys}
# print(json.dumps(health_data, indent = 1))
#
for h in health_data['data']:

  match h['subsystem']:
    case 'www':
      # print(json.dumps(h, indent = 1))
      resp['data'].update({
        "health_" + h['subsystem'] + ".status": h['status'],
        "health_" + h['subsystem'] + ".tx_bytes-r": h['tx_bytes-r'],
        "health_" + h['subsystem'] + ".rx_bytes-r": h['rx_bytes-r'],
        "health_" + h['subsystem'] + ".latency": h['latency'],
        "health_" + h['subsystem'] + ".uptime": h['uptime'],
        "health_" + h['subsystem'] + ".drops": h['drops'],
        "health_" + h['subsystem'] + ".xput_up": h['xput_up'],
        "health_" + h['subsystem'] + ".xput_down": h['xput_down'],
        "health_" + h['subsystem'] + ".speedtest_status": h['speedtest_status'],
        "health_" + h['subsystem'] + ".speedtest_lastrun": h['speedtest_lastrun'],
        "health_" + h['subsystem'] + ".speedtest_ping": h['speedtest_ping'],
        "health_" + h['subsystem'] + ".uptime": h['uptime']

      })

    case 'vpn':
      resp['data'].update({
        "health_" + h['subsystem'] + ".status": h['status'],
      })
      # test
    case 'wlan':
      resp['data'].update({
        "health_" + h['subsystem'] + ".num_user": h['num_user'],
        "health_" + h['subsystem'] + ".num_guest": h['num_guest'],
        "health_" + h['subsystem'] + ".num_iot": h['num_iot'],
        "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
        "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r'],
        "health_" + h['subsystem'] + ".status": h['status'],
        "health_" + h['subsystem'] + ".num_ap": h['num_ap']
      })

    case 'lan':
      resp['data'].update({
        "health_" + h['subsystem'] + ".status": h['status'],
        "health_" + h['subsystem'] + ".num_user": h['num_user'],
        "health_" + h['subsystem'] + ".num_iot": h['num_iot'],
        "health_" + h['subsystem'] + ".num_sw": h['num_sw'],
        "health_" + h['subsystem'] + ".num_adopted": h['num_adopted']
      })

      # test
    case 'wan':
      # print(h['subsystem'])
      # print(json.dumps(h, indent = 1))
      resp['data'].update({
        "health_" + h['subsystem'] + ".status": h['status'],
        "health_" + h['subsystem'] + ".isp_organization": h['isp_organization'],
        "health_" + h['subsystem'] + ".isp_name": h['isp_name'],
        "health_" + h['subsystem'] + ".gw_version": h['gw_version'],
        "health_" + h['subsystem'] + ".num_sta": h['num_sta'],
        "health_" + h['subsystem'] + ".cpu": h['gw_system-stats']['cpu'],
        "health_" + h['subsystem'] + ".mem": h['gw_system-stats']['mem'],
        "health_" + h['subsystem'] + ".uptime": h['gw_system-stats']['uptime'],
        "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
        "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r']
      })

    case _:
      print("else")

# uptime_stats = "https://xxxxx.xxx.xxxx/proxy/network/api/s/default/stat/stats"
#

# response_stats = session.get(uptime_stats, verify=False)
# response_stats.raise_for_status()
# data = response_stats.json()["data"][0]
# # # print(version)
# json.dumps(print(resp['data']))
# print(json.dumps(resp['data'], indent = 1))
# print(json.dumps({
#     "cpu": data["system-stats"]["cpu"],
#     "cpu_temp": round(data["temperatures"][1]["value"], 1),
#     "system_temp": round(data["temperatures"][0]["value"], 1),
#     "memory": data["system-stats"]["mem"],
#     "disk": round(data["storage"][1]["used"] / data["storage"][1]["size"] * 100, 1),
#     "internet": data["wan1"]["up"],
#     "uptime": datetime.fromtimestamp(data["startup_timestamp"]).isoformat(),
#     "availability": data["uptime_stats"]["WAN"]["availability"],
#     "average_latency": data["uptime_stats"]["WAN"]["latency_average"],
#     "down": data["uplink"]["rx_rate"] / 1000000,
#     "up": data["uplink"]["tx_rate"] / 1000000,
#     "version": data["displayable_version"],
#     "last_wan_ip": data["last_wan_ip"]
# }))
# sys.exit(2)

resp["version"]=version['data'][0]['version']
# # Find the rule to update
for client_data in rules['data']:

  ## If switch is offline ignore
  if client_data['state'] == 0:
    continue

  name=snake_case(client_data['name'])
  # print(client_data)
  # resp[name]={}

# # print(version)
  # json.dumps(print(client_data))

  internet = None
  speedtest_status = None
  # print("client_data['model'] %s",client_data['model'] )
  if client_data['model'] == "UDMPRO":
    speedtest_status = client_data['uplink']['speedtest_status'] == "Success"
    internet = client_data['uplink']['up']
    # if 'uplink' in client_data.keys():
    #   if client_data['uplink']['uplink_source'] == 'legacy':
    #     internet = client_data['uplink']['up']
    #   else:
    #     internet = client_data['internet']
    #     print("client_data['model'] %s",client_data['model'] )
    # elif 'internet' in client_data.keys():
    #   internet = client_data['internet']
    #   print("client_data['model'] %s",client_data['model'] )
  cpu=0
  ram=0
  try:
    if client_data['system-stats'] and client_data['system-stats'] != {} and len(client_data['system-stats'].keys()) != 0:
      try:
        cpu = float(client_data['system-stats']['cpu'])
      except:
        cpu = 0.0
      try:
        ram = float(client_data['system-stats']['mem'])
      except:
        ram = 0
  except:
    print("An exception occurred")
    print(json.dumps(client_data, indent = 1))
    print("------")

  activity = round(client_data['uplink']['rx_bytes-r']/125000 + client_data['uplink']['tx_bytes-r']/125000,1)
  uptime = parse_uptime(client_data['uptime'])
  update = int(client_data['upgradable'])
  model_type = client_data['model']

  # print(type)

  if client_data['is_access_point']:
      wifi0clients = client_data['radio_table_stats'][0]['user-num_sta']
      wifi1clients = client_data['radio_table_stats'][1]['user-num_sta']
      wifi0score = client_data['radio_table_stats'][0]['satisfaction']
      wifi1score = client_data['radio_table_stats'][1]['satisfaction']
      numclients = client_data['user-wlan-num_sta']
      numguests = client_data['guest-wlan-num_sta']
      score = client_data['satisfaction']

      # raise ValueError('Some error')
      resp['data'].update ({
          name+".Clients":numclients,
          name+".Guests":numguests,
          name+".Clients_wifi0":wifi0clients ,
          name+".Clients_wifi1":wifi1clients ,
          name+".Score":score,
          name+".CPU": cpu,
          name+".RAM":ram,
          name+".Uptime":uptime,
          name+".Score_wifi0":wifi0score ,
          name+".Score_wifi1":wifi1score ,
          name+".Activity":str(activity)+' Mbps',
          name+".Update":update,
      })

  else:
    cpu_temp = None
    board_temp = None
    wan_drops = None
    wan_latency = None
    if 'temperatures' in client_data.keys() and  client_data['temperatures']!={}:
      for t in client_data['temperatures']:
        if t['type'] == "cpu" : cpu_temp = t['value']
        if t['type'] == "board" : board_temp = t['value']

    # json.dumps(print(client_data))
    # print(json.dumps(client_data, indent = 1))

    storage_used = None
    storage_size = None
    if 'storage' in client_data.keys() and  client_data['storage']!=[]:
      for t in client_data['storage']:

        if t['mount_point'] == "/persistent":
          storage_size = t['size']
          storage_used = t['used']

    availability=None
    latency_average=None
    uplink_ip=None

    if 'uptime_stats' in client_data.keys() and  client_data['uptime_stats']!={}:
        for t in client_data['uptime_stats']['WAN']['alerting_monitors']:
          if t['target'] == "1.1.1.1":
            latency_average = t['latency_average']
            availability = t['availability']

    if 'uplink' in client_data.keys() and client_data['uplink']!={} and 'comment' in client_data['uplink'].keys():

        # json.dumps(print(client_data['uplink']))
        # print(json.dumps(client_data['uplink'], indent = 1))
        if client_data['uplink']['comment'] == "WAN":
          wan_latency = client_data['uplink']['latency']
          wan_drops = client_data['uplink']['drops']
          uplink_ip = client_data['uplink']['ip']

# uplink

        # print(t)
            # print(json.dumps(client_data, indent = 1))
    # if 'speedtest-status' in client_data.keys() and client_data['speedtest-status'] is not None:
    #   print("---")
    #   # print(client_data['speedtest-status'])
    #   # json.dumps(print(client_data))
    #   print(json.dumps(client_data['uplink'], indent = 1))

    #   print("---")
    # internet = client_data['internet']
    usedports = client_data['num_sta']
    userports = client_data['user-num_sta']
    guestports = client_data['guest-num_sta']

    resp['data'].update({
      name+".Activity":str(activity)+' Mbps',
      name+".CPU":cpu,
      name+".RAM":ram,
      name+".Uptime":uptime,
      name+".Ports_used":usedports,
      name+".Ports_user":userports,
      name+".Ports_guest":guestports,
      name+".Update":update,
      name+".Model": model_type
    })

    if 'speedtest_ping' in client_data['uplink'].keys() and client_data['uplink']['speedtest_ping'] is not None:

      resp['data'].update({
        name+".Speedtest_ping": client_data['uplink']['speedtest_ping'],
        name+".Speedtest_up":   client_data['uplink']['xput_up'],
        name+".Speedtest_down": client_data['uplink']['xput_down']
      })
    if storage_used is not None:
      resp['data'].update({
        name+".StorageUsed": storage_used,
        name+".StorageSize": storage_size
      })
    if internet is not None:
      resp['data'].update({
        name+".Internet": internet
      })
    if speedtest_status is not None:
      resp['data'].update({
        name+".SpeedTestPass": speedtest_status
      })
    if cpu_temp is not None:
      resp['data'].update({
        name+".CPUTemp":cpu_temp,
        name+".BoardTemp":board_temp
      })

    if wan_drops is not None:
      resp['data'].update({
        name+".WanDrops":wan_drops,
        name+".WanLatency":wan_latency
      })

    if latency_average is not None:
      resp['data'].update({
        name+".LatencyAvg":latency_average,
        name+".WanAvailability":availability
      })

    if uplink_ip is not None:
      resp['data'].update({
        name+".UplinkIP":uplink_ip
      })

# print(resp)
# formatted_json = json.dumps(resp, sort_keys=True, indent=4)
# colorful_json = highlight(formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter())
# print(colorful_json)
json_formatted_str = json.dumps(resp, indent=2)
print(json_formatted_str)
# Log out of the UniFi Controller
logout_url = f'{controller_url}/api/auth/logout'
session.post(logout_url, verify=False)

sys.exit(0)

Here is my ha config

command_line:

  - sensor:
      name: udmpro_disk_usage
      command: !secret udmpro_disk_usage
      scan_interval: 3600

  - sensor:
      command: '/config/scripts/unifi_combined2.py'
      command_timeout: 180
      name: unifi_stats
      value_template: '{{value_json.version}}' 
      scan_interval: 300
      json_attributes:
        - data

template:
  binary_sensor:
    - name: Unifi UDM Pro Internet Up
      unique_id: unifi_udmpro_internet_up
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.Internet'] }}

  sensor:
    ## Unifi AP Basement
    - name: Unifi AP Basement Guests
      unique_id: unifi_ap_basement_guests
      state: >
          {{ state_attr('sensor.unifi_stats','data')['basement_ap.Guests'] }}

    - name: Unifi AP Basement Activity
      unique_id: unifi_ap_basement_activity
      unit_of_measurement: 'Mbps'
      state: >
          {{ state_attr('sensor.unifi_stats','data')['basement_ap.Activity'].split(' ')[0] | float(0) }}

    - name: Unifi AP Basement RAM
      unique_id: unifi_ap_basement_ram
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.RAM'] | float(0) }}

    - name: Unifi AP Basement CPU
      unique_id: unifi_ap_basement_cpu
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.CPU'] | float(0) }}

    - name: Unifi AP Basement Score
      unique_id: unifi_ap_basement_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.Score'] }}

    - name: Unifi AP Basement 2.4gHz Score
      unique_id: unifi_ap_basement_2ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.Score_wifi0'] | default(0) }}

    - name: Unifi AP Basement 5gHz Score
      unique_id: unifi_ap_basement_5ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.Score_wifi1'] | default(0) }}

    - name: Unifi AP Basement 2.4gHz Clients
      unique_id: unifi_ap_basement_2ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi0']  | default(0) }}

    - name: Unifi AP Basement 5gHz Clients
      unique_id: unifi_ap_basement_5ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi1'] | default(0) }}

    - name: Unifi AP Basement Total Clients
      unique_id: unifi_ap_basement_total_clients
      state: >
        {{ state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi1']  | default(0) }}

    - name: Unifi AP Basement Updates
      unique_id: unifi_ap_basement_update
      state: >
        {% if state_attr('sensor.unifi_stats', 'data')['basement_ap.Update'] == 0 %}
          No
        {% else %}
          Available
        {% endif %}

    ### Unifi AP Outside
    - name: Unifi AP Outside Guests
      unique_id: unifi_ap_outside_guests
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Guests'] }}

    - name: Unifi AP Outside Activity
      unique_id: unifi_ap_outside_activity
      unit_of_measurement: 'Mbps'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Activity'].split(' ')[0] | float(0) }}

    - name: Unifi AP Outside RAM
      unique_id: unifi_ap_outside_ram
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.RAM'] | float(0) }}

    - name: Unifi AP Outside CPU
      unique_id: unifi_ap_outside_cpu
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.CPU'] | float(0) }}

    - name: Unifi AP Outside Score
      unique_id: unifi_ap_outside_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Score'] }}

    - name: Unifi AP Outside 2.4gHz Score
      unique_id: unifi_ap_outside_2ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Score_wifi0'] | default(0) }}

    - name: Unifi AP Outside 5gHz Score
      unique_id: unifi_ap_outside_5ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Score_wifi1'] | default(0) }}

    - name: Unifi AP Outside 2.4gHz Clients
      unique_id: unifi_ap_outside_2ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi0']  | default(0) }}

    - name: Unifi AP Outside 5gHz Clients
      unique_id: unifi_ap_outside_5ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi1'] | default(0) }}

    - name: Unifi AP Outside total Clients
      unique_id: unifi_ap_outside_total_clients
      state: >
        {{ state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi1']  | default(0) }}

    - name: Unifi AP Outside Updates
      unique_id: unifi_ap_outside_update
      state: >
        {% if state_attr('sensor.unifi_stats', 'data')['outside_ap.Update'] == 0 %}
          No
        {% else %}
          Available
        {% endif %}

    # Unifi AP Upstairs
    - name: Unifi AP Upstairs Guests
      unique_id: unifi_ap_upstairs_guests
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Guests'] }}

    - name: Unifi AP Upstairs Activity
      unique_id: unifi_ap_upstairs_activity
      unit_of_measurement: 'Mbps'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Activity'].split(' ')[0] | float(0) }}

    - name: Unifi AP Upstairs RAM
      unique_id: unifi_ap_upstairs_ram
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.RAM'] | float(0) }}

    - name: Unifi AP Upstairs CPU
      unique_id: unifi_ap_upstairs_cpu
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.CPU'] | float(0) }}

    - name: Unifi AP Upstairs Score
      unique_id: unifi_ap_upstairs_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Score'] }}

    - name: Unifi AP Upstairs 2.4gHz Score
      unique_id: unifi_ap_upstairs_2ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Score_wifi0'] | default(0) }}

    - name: Unifi AP Upstairs 5gHz Score
      unique_id: unifi_ap_upstairs_5ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Score_wifi1'] | default(0) }}

    - name: Unifi AP Upstairs 2.4gHz Clients
      unique_id: unifi_ap_upstairs_2ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi0']  | default(0) }}

    - name: Unifi AP Upstairs 5gHz Clients
      unique_id: unifi_ap_upstairs_5ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi1'] | default(0) }}

    - name: Unifi AP Upstairs total Clients
      unique_id: unifi_ap_upstairs_total_clients
      state: >
        {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi1']  | default(0) }}

    - name: Unifi AP Upstairs Updates
      unique_id: unifi_ap_upstairs_update
      state: >
        {% if state_attr('sensor.unifi_stats', 'data')['upstairs_ap.Update'] == 0 %}
          No
        {% else %}
          Available
        {% endif %}

    ### Unifi UDM Pro
    - name: Unifi UDM Pro Ports Used
      unique_id: unifi_udmpro_ports_used
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.Ports_used'] }}

    - name: Unifi UDM Pro Ports User
      unique_id: unifi_udmpro_guests
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.Ports_user'] }}

    - name: Unifi UDM Pro Ports Guest
      unique_id: unifi_udmpro_ports_guests
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.Ports_guest'] | default(0)}}

    - name: Unifi UDM Pro Activity
      unique_id: unifi_udmpro_activity
      unit_of_measurement: 'Mbps'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.Activity'].split(' ')[0] | float(0) }}

    - name: Unifi UDM Pro RAM
      unique_id: unifi_udmpro_ram
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.RAM'] | float(0) }}

    - name: Unifi UDM Pro CPU
      unique_id: unifi_udmpro_cpu
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.CPU'] | float(0) }}

    - name: Unifi UDM Pro CPU Temp
      unique_id: unifi_udmpro_cpu_temp
      unit_of_measurement: 'c'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.CPUTemp'] | default(0) }}

    - name: Unifi UDM Pro Board Temp
      unique_id: unifi_udmpro_board_temp
      unit_of_measurement: 'c'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.BoardTemp'] | default(0) }}

    - name: Unifi UDM Pro Updates
      unique_id: unifi_udmpro_update
      state: >
        {% if state_attr('sensor.unifi_stats', 'data')['udmpro.Update'] == 0 %}
          No
        {% else %}
          Available
        {% endif %}

    - name: Unifi UDM Pro Speedtest Ping
      unique_id: unifi_udmpro_speed_test_ping
      state: >
        {{state_attr('sensor.unifi_stats','data')['udmpro.Speedtest_ping']}}

    - name: Unifi UDM Pro Speedtest up
      unique_id: unifi_udmpro_speed_test_up
      state: >
        {{state_attr('sensor.unifi_stats','data')['udmpro.Speedtest_up']}}

    - name: Unifi UDM Pro Speedtest Down
      unique_id: unifi_udmpro_speed_test_down
      state: >
        {{state_attr('sensor.unifi_stats','data')['udmpro.Speedtest_down']}}

    # Unifi AP Garage
    - name: Unifi AP Garage Guests
      unique_id: unifi_ap_garage_guests
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Guests'] }}

    - name: Unifi AP Garage Activity
      unique_id: unifi_ap_garage_activity
      unit_of_measurement: 'Mbps'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Activity'].split(' ')[0] | float(0) }}

    - name: Unifi AP Garage RAM
      unique_id: unifi_ap_garage_ram
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.RAM'] | float(0) }}

    - name: Unifi AP Garage CPU
      unique_id: unifi_ap_garage_cpu
      unit_of_measurement: '%'
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.CPU'] | float(0) }}

    - name: Unifi AP Garage Score
      unique_id: unifi_ap_garage_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Score'] }}

    - name: Unifi AP Garage 2.4gHz Score
      unique_id: unifi_ap_garage_2ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Score_wifi0'] | default(0) }}

    - name: Unifi AP Garage 5gHz Score
      unique_id: unifi_ap_garage_5ghz_score
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Score_wifi1'] | default(0) }}

    - name: Unifi AP Garage 2.4gHz Clients
      unique_id: unifi_ap_garage_2ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi0']  | default(0) }}

    - name: Unifi AP Garage 5gHz Clients
      unique_id: unifi_ap_garage_5ghz_wifi_devices
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi1'] | default(0) }}

    - name: Unifi AP Garage total Clients
      unique_id: unifi_ap_garage_total_clients
      state: >
        {{ state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi1']  | default(0) }}

    - name: Unifi AP Garage Updates
      unique_id: unifi_ap_garage_update
      state: >
        {% if state_attr('sensor.unifi_stats', 'data')['garage_ap.Update'] == 0 %}
          No
        {% else %}
          Available
        {% endif %}

    - name: "UDM CPU"
      unique_id: unifi_gateway_wan_cpu
      unit_of_measurement: "%"
      state: >
        {{ state_attr('sensor.unifi_stats','data')['health_wan.cpu'] }}

    - name: "UDM Memory"
      unique_id: unifi_gateway_wan_mem
      unit_of_measurement: "%"
      state: >
       {{ state_attr('sensor.unifi_stats','data')['health_wan.mem'] }}

    - name: "WAN IP"
      unique_id: unifi_gateway_wan_ip
      state: >
        {{ state_attr('sensor.unifi_stats','data')['udmpro.UplinkIP'] }}

    - name: "WAN Download"
      unique_id: unifi_gateway_wan_download
      unit_of_measurement: Kbps
      icon: "mdi:progress-download"
      state: >
        {{ (state_attr('sensor.unifi_stats','data')['health_wan.rx_bytes'] / 1024 )| int }}

    - name: "USG Uptime"
      unique_id: unifi_gateway_wan_uptime
      state: >-
        {%- set time = state_attr('sensor.unifi_stats','data')['health_wan.uptime'] | int %}
        {%- set minutes = ((time % 3600) // 60) %}
        {%- set minutes = '{}min'.format(minutes) if minutes > 0 else '' %}
        {%- set hours = ((time % 86400) // 3600) %}
        {%- set hours = '{}hr '.format(hours) if hours > 0 else '' %}
        {%- set days = (time // 86400) %}
        {%- set days = '{}d '.format(days) if days > 0 else '' %}
        {{ 'Less than 1 min' if time < 60 else days + hours + minutes }}

    - name: "USG Firmware Version"
      unique_id: unifi_gateway_firmware_version
      icon: "mdi:database-plus"
      state: >-
        {{ state_attr('sensor.unifi_stats','data')['health_wan.gw_version'] }}

    - name: "USG Speedtest Download"
      unique_id: unifi_gateway_www_xput_down
      unit_of_measurement: Mbps
      icon: "mdi:progress-download"
      state: >-
        {{ state_attr('sensor.unifi_stats','data')['health_www.xput_down'] }}

    - name: "USG Speedtest Upload"
      unique_id: unifi_gateway_www_xput_up
      unit_of_measurement: Mbps
      icon: "mdi:progress-upload"
      state: >-
        {{ state_attr('sensor.unifi_stats','data')['health_www.xput_up'] }}

    - name: "USG Speedtest Ping"
      unique_id: unifi_gateway_www_speedtest_ping
      unit_of_measurement: ms
      icon: "mdi:progress-clock"
      state: >-
        {{ state_attr('sensor.unifi_stats','data')['health_www.speedtest_ping'] }}

    - name: "Internet Uptime"
      unique_id: unifi_gateway_www_uptime
      state: >
        {%- set time = state_attr('sensor.unifi_stats','data')['health_www.uptime'] | int %}
        {%- set minutes = ((time % 3600) // 60) %}
        {%- set minutes = '{}min'.format(minutes) if minutes > 0 else '' %}
        {%- set hours = ((time % 86400) // 3600) %}
        {%- set hours = '{}hr '.format(hours) if hours > 0 else '' %}
        {%- set days = (time // 86400) %}
        {%- set days = '{}d '.format(days) if days > 0 else '' %}
        {{ 'Less than 1 min' if time < 60 else days + hours + minutes }}

    - name: "Unifi Wlan Users"
      unique_id: unifi_gateway_wlan_num_user
      icon: "mdi:account-multiple"
      state: >
        {{ state_attr('sensor.unifi_stats','data')['health_lan.num_user'] }}

    - name: "Unifi Users Lan"
      unique_id: unifi_gateway_lan_num_user
      icon: "mdi:account-multiple"
      state: >
        {{ state_attr('sensor.unifi_stats','data')['health_lan.num_user'] }}

    - name: "UDM-Firmware Version"
      unique_id: unifi_gateway_firmware
      state: >
        {{ state_attr('sensor.unifi_stats','version') }}
      icon: mdi:counter

hope its helpful to someone

coldburn89 commented 4 months ago

Thank you very much!! How did you implement this? The configuration.yaml part is clear, but the python script is not listed like:

On Mon, 12 Feb 2024 at 14:10, John Dyer @.***> wrote:

Here is my "fix"... please note that this script grew organically over time as I moved features from the other plugins to mine... not once have I gone back over the code to refactor, clean up, or optimize!!

!/usr/local/bin/python

from datetime import timedeltaimport json, yaml, requestsfrom datetime import datetimeimport requests,timefrom re import subimport sys resp={}resp['data']={}

def parse_uptime(uptime): seconds = 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' return uptime controller_url = 'https://xxxxx.xxxxx.xxxxx'username = 'xxxx'password = 'xxxx'site = 'default' # The site ID, 'default' for most installations

login_url = f'{controller_url}/api/auth/login'login_data = { 'username': username, 'password': password } session = requests.Session()response = session.post(login_url, json=login_data, verify=True)response.raise_for_status() def snakecase(s): return ''.join( sub('([A-Z][a-z]+)', r' \1', sub('([A-Z]+)', r' \1', s.replace('-', ' '))).split()).lower()

rules_url = 'https://xxxx.xxxx.xxxx/proxy/network/api/s/default/stat/device' response = session.get(rules_url, verify=False)response.raise_for_status()rules = response.json()sysinfo_url = 'https://xxxx.xxxx.xxxx/proxy/network/api/s/default/stat/sysinfo' response = session.get(sysinfo_url, verify=False)response.raise_for_status()version = response.json()

health_url = 'https://xxxx.xxxx.xxx/proxy/network/api/s/default/stat/health' response = session.get(health_url, verify=False)response.raise_for_status()health_data = response.json()

keys = health_data['data'][0].keys()# a = {k: set(d[k] for d in health_data['data']) for k in keys}# print(json.dumps(health_data, indent = 1))#for h in health_data['data']:

match h['subsystem']: case 'www':

print(json.dumps(h, indent = 1))

  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".tx_bytes-r": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes-r": h['rx_bytes-r'],
    "health_" + h['subsystem'] + ".latency": h['latency'],
    "health_" + h['subsystem'] + ".uptime": h['uptime'],
    "health_" + h['subsystem'] + ".drops": h['drops'],
    "health_" + h['subsystem'] + ".xput_up": h['xput_up'],
    "health_" + h['subsystem'] + ".xput_down": h['xput_down'],
    "health_" + h['subsystem'] + ".speedtest_status": h['speedtest_status'],
    "health_" + h['subsystem'] + ".speedtest_lastrun": h['speedtest_lastrun'],
    "health_" + h['subsystem'] + ".speedtest_ping": h['speedtest_ping'],
    "health_" + h['subsystem'] + ".uptime": h['uptime']

  })

case 'vpn':
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
  })
  # test
case 'wlan':
  resp['data'].update({
    "health_" + h['subsystem'] + ".num_user": h['num_user'],
    "health_" + h['subsystem'] + ".num_guest": h['num_guest'],
    "health_" + h['subsystem'] + ".num_iot": h['num_iot'],
    "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r'],
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".num_ap": h['num_ap']
  })

case 'lan':
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".num_user": h['num_user'],
    "health_" + h['subsystem'] + ".num_iot": h['num_iot'],
    "health_" + h['subsystem'] + ".num_sw": h['num_sw'],
    "health_" + h['subsystem'] + ".num_adopted": h['num_adopted']
  })

  # test
case 'wan':
  # print(h['subsystem'])
  # print(json.dumps(h, indent = 1))
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".isp_organization": h['isp_organization'],
    "health_" + h['subsystem'] + ".isp_name": h['isp_name'],
    "health_" + h['subsystem'] + ".gw_version": h['gw_version'],
    "health_" + h['subsystem'] + ".num_sta": h['num_sta'],
    "health_" + h['subsystem'] + ".cpu": h['gw_system-stats']['cpu'],
    "health_" + h['subsystem'] + ".mem": h['gw_system-stats']['mem'],
    "health_" + h['subsystem'] + ".uptime": h['gw_system-stats']['uptime'],
    "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r']
  })

case _:
  print("else")

uptime_stats = "https://xxxxx.xxx.xxxx/proxy/network/api/s/default/stat/stats"

response_stats = session.get(uptime_stats, verify=False)# response_stats.raise_for_status()# data = response_stats.json()["data"][0]# # # print(version)# json.dumps(print(resp['data']))# print(json.dumps(resp['data'], indent = 1))# print(json.dumps({# "cpu": data["system-stats"]["cpu"],# "cpu_temp": round(data["temperatures"][1]["value"], 1),# "system_temp": round(data["temperatures"][0]["value"], 1),# "memory": data["system-stats"]["mem"],# "disk": round(data["storage"][1]["used"] / data["storage"][1]["size"] * 100, 1),# "internet": data["wan1"]["up"],# "uptime": datetime.fromtimestamp(data["startup_timestamp"]).isoformat(),# "availability": data["uptime_stats"]["WAN"]["availability"],# "average_latency": data["uptime_stats"]["WAN"]["latency_average"],# "down": data["uplink"]["rx_rate"] / 1000000,# "up": data["uplink"]["tx_rate"] / 1000000,# "version": data["displayable_version"],# "last_wan_ip": data["last_wan_ip"]# }))# sys.exit(2)

resp["version"]=version['data'][0]['version']# # Find the rule to updatefor client_data in rules['data']:

If switch is offline ignore

if client_data['state'] == 0: continue

name=snake_case(client_data['name'])

print(client_data)

resp[name]={}

print(version)

json.dumps(print(client_data))

internet = None speedtest_status = None

print("client_data['model'] %s",client_data['model'] )

if client_data['model'] == "UDMPRO": speedtest_status = client_data['uplink']['speedtest_status'] == "Success" internet = client_data['uplink']['up']

if 'uplink' in client_data.keys():

#   if client_data['uplink']['uplink_source'] == 'legacy':
#     internet = client_data['uplink']['up']
#   else:
#     internet = client_data['internet']
#     print("client_data['model'] %s",client_data['model'] )
# elif 'internet' in client_data.keys():
#   internet = client_data['internet']
#   print("client_data['model'] %s",client_data['model'] )

cpu=0 ram=0 try: if client_data['system-stats'] and client_data['system-stats'] != {} and len(client_data['system-stats'].keys()) != 0: try: cpu = float(client_data['system-stats']['cpu']) except: cpu = 0.0 try: ram = float(client_data['system-stats']['mem']) except: ram = 0 except: print("An exception occurred") print(json.dumps(client_data, indent = 1)) print("------")

activity = round(client_data['uplink']['rx_bytes-r']/125000 + client_data['uplink']['tx_bytes-r']/125000,1) uptime = parse_uptime(client_data['uptime']) update = int(client_data['upgradable']) model_type = client_data['model']

print(type)

if client_data['is_access_point']: wifi0clients = client_data['radio_table_stats'][0]['user-num_sta'] wifi1clients = client_data['radio_table_stats'][1]['user-num_sta'] wifi0score = client_data['radio_table_stats'][0]['satisfaction'] wifi1score = client_data['radio_table_stats'][1]['satisfaction'] numclients = client_data['user-wlan-num_sta'] numguests = client_data['guest-wlan-num_sta'] score = client_data['satisfaction']

  # raise ValueError('Some error')
  resp['data'].update ({
      name+".Clients":numclients,
      name+".Guests":numguests,
      name+".Clients_wifi0":wifi0clients ,
      name+".Clients_wifi1":wifi1clients ,
      name+".Score":score,
      name+".CPU": cpu,
      name+".RAM":ram,
      name+".Uptime":uptime,
      name+".Score_wifi0":wifi0score ,
      name+".Score_wifi1":wifi1score ,
      name+".Activity":str(activity)+' Mbps',
      name+".Update":update,
  })

else: cpu_temp = None board_temp = None wan_drops = None wan_latency = None if 'temperatures' in client_data.keys() and client_data['temperatures']!={}: for t in client_data['temperatures']: if t['type'] == "cpu" : cpu_temp = t['value'] if t['type'] == "board" : board_temp = t['value']

# json.dumps(print(client_data))
# print(json.dumps(client_data, indent = 1))

storage_used = None
storage_size = None
if 'storage' in client_data.keys() and  client_data['storage']!=[]:
  for t in client_data['storage']:

    if t['mount_point'] == "/persistent":
      storage_size = t['size']
      storage_used = t['used']

availability=None
latency_average=None
uplink_ip=None

if 'uptime_stats' in client_data.keys() and  client_data['uptime_stats']!={}:
    for t in client_data['uptime_stats']['WAN']['alerting_monitors']:
      if t['target'] == "1.1.1.1":
        latency_average = t['latency_average']
        availability = t['availability']

if 'uplink' in client_data.keys() and client_data['uplink']!={} and 'comment' in client_data['uplink'].keys():

    # json.dumps(print(client_data['uplink']))
    # print(json.dumps(client_data['uplink'], indent = 1))
    if client_data['uplink']['comment'] == "WAN":
      wan_latency = client_data['uplink']['latency']
      wan_drops = client_data['uplink']['drops']
      uplink_ip = client_data['uplink']['ip']

uplink

    # print(t)
        # print(json.dumps(client_data, indent = 1))
# if 'speedtest-status' in client_data.keys() and client_data['speedtest-status'] is not None:
#   print("---")
#   # print(client_data['speedtest-status'])
#   # json.dumps(print(client_data))
#   print(json.dumps(client_data['uplink'], indent = 1))

#   print("---")
# internet = client_data['internet']
usedports = client_data['num_sta']
userports = client_data['user-num_sta']
guestports = client_data['guest-num_sta']

resp['data'].update({
  name+".Activity":str(activity)+' Mbps',
  name+".CPU":cpu,
  name+".RAM":ram,
  name+".Uptime":uptime,
  name+".Ports_used":usedports,
  name+".Ports_user":userports,
  name+".Ports_guest":guestports,
  name+".Update":update,
  name+".Model": model_type
})

if 'speedtest_ping' in client_data['uplink'].keys() and client_data['uplink']['speedtest_ping'] is not None:

  resp['data'].update({
    name+".Speedtest_ping": client_data['uplink']['speedtest_ping'],
    name+".Speedtest_up":   client_data['uplink']['xput_up'],
    name+".Speedtest_down": client_data['uplink']['xput_down']
  })
if storage_used is not None:
  resp['data'].update({
    name+".StorageUsed": storage_used,
    name+".StorageSize": storage_size
  })
if internet is not None:
  resp['data'].update({
    name+".Internet": internet
  })
if speedtest_status is not None:
  resp['data'].update({
    name+".SpeedTestPass": speedtest_status
  })
if cpu_temp is not None:
  resp['data'].update({
    name+".CPUTemp":cpu_temp,
    name+".BoardTemp":board_temp
  })

if wan_drops is not None:
  resp['data'].update({
    name+".WanDrops":wan_drops,
    name+".WanLatency":wan_latency
  })

if latency_average is not None:
  resp['data'].update({
    name+".LatencyAvg":latency_average,
    name+".WanAvailability":availability
  })

if uplink_ip is not None:
  resp['data'].update({
    name+".UplinkIP":uplink_ip
  })

print(resp)# formatted_json = json.dumps(resp, sort_keys=True, indent=4)# colorful_json = highlight(formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter())# print(colorful_json)json_formatted_str = json.dumps(resp, indent=2)print(json_formatted_str)# Log out of the UniFi Controllerlogout_url = f'{controller_url}/api/auth/logout'session.post(logout_url, verify=False)

sys.exit(0)

Here is my ha config

  • sensor: command: '/config/scripts/unifi_combined2.py' command_timeout: 180 name: unifi_stats value_template: '{{value_json.version}}' scan_interval: 300 json_attributes:
    • data

template: binary_sensor:

  • name: Unifi UDM Pro Internet Up unique_id: unifi_udmpro_internet_up state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.Internet'] }}

    sensor:

    Unifi AP Basement

  • name: Unifi AP Basement Guests unique_id: unifi_ap_basement_guests state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Guests'] }}

  • name: Unifi AP Basement Activity unique_id: unifi_ap_basement_activity unit_of_measurement: 'Mbps' state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Activity'].split(' ')[0] | float(0) }}

  • name: Unifi AP Basement RAM unique_id: unifi_ap_basement_ram unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.RAM'] | float(0) }}

  • name: Unifi AP Basement CPU unique_id: unifi_ap_basement_cpu unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.CPU'] | float(0) }}

  • name: Unifi AP Basement Score unique_id: unifi_ap_basement_score state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Score'] }}

  • name: Unifi AP Basement 2.4gHz Score unique_id: unifi_ap_basement_2ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Score_wifi0'] | default(0) }}

  • name: Unifi AP Basement 5gHz Score unique_id: unifi_ap_basement_5ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Score_wifi1'] | default(0) }}

  • name: Unifi AP Basement 2.4gHz Clients unique_id: unifi_ap_basement_2ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi0'] | default(0) }}

  • name: Unifi AP Basement 5gHz Clients unique_id: unifi_ap_basement_5ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Basement Total Clients unique_id: unifi_ap_basement_total_clients state: > {{ state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['basement_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Basement Updates unique_id: unifi_ap_basement_update state: > {% if state_attr('sensor.unifi_stats', 'data')['basement_ap.Update'] == 0 %} No {% else %} Available {% endif %}

    Unifi AP Outside

  • name: Unifi AP Outside Guests unique_id: unifi_ap_outside_guests state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Guests'] }}

  • name: Unifi AP Outside Activity unique_id: unifi_ap_outside_activity unit_of_measurement: 'Mbps' state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Activity'].split(' ')[0] | float(0) }}

  • name: Unifi AP Outside RAM unique_id: unifi_ap_outside_ram unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.RAM'] | float(0) }}

  • name: Unifi AP Outside CPU unique_id: unifi_ap_outside_cpu unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.CPU'] | float(0) }}

  • name: Unifi AP Outside Score unique_id: unifi_ap_outside_score state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Score'] }}

  • name: Unifi AP Outside 2.4gHz Score unique_id: unifi_ap_outside_2ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Score_wifi0'] | default(0) }}

  • name: Unifi AP Outside 5gHz Score unique_id: unifi_ap_outside_5ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Score_wifi1'] | default(0) }}

  • name: Unifi AP Outside 2.4gHz Clients unique_id: unifi_ap_outside_2ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi0'] | default(0) }}

  • name: Unifi AP Outside 5gHz Clients unique_id: unifi_ap_outside_5ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Outside total Clients unique_id: unifi_ap_outside_total_clients state: > {{ state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['outside_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Outside Updates unique_id: unifi_ap_outside_update state: > {% if state_attr('sensor.unifi_stats', 'data')['outside_ap.Update'] == 0 %} No {% else %} Available {% endif %}

    Unifi AP Upstairs

  • name: Unifi AP Upstairs Guests unique_id: unifi_ap_upstairs_guests state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Guests'] }}

  • name: Unifi AP Upstairs Activity unique_id: unifi_ap_upstairs_activity unit_of_measurement: 'Mbps' state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Activity'].split(' ')[0] | float(0) }}

  • name: Unifi AP Upstairs RAM unique_id: unifi_ap_upstairs_ram unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.RAM'] | float(0) }}

  • name: Unifi AP Upstairs CPU unique_id: unifi_ap_upstairs_cpu unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.CPU'] | float(0) }}

  • name: Unifi AP Upstairs Score unique_id: unifi_ap_upstairs_score state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Score'] }}

  • name: Unifi AP Upstairs 2.4gHz Score unique_id: unifi_ap_upstairs_2ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Score_wifi0'] | default(0) }}

  • name: Unifi AP Upstairs 5gHz Score unique_id: unifi_ap_upstairs_5ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Score_wifi1'] | default(0) }}

  • name: Unifi AP Upstairs 2.4gHz Clients unique_id: unifi_ap_upstairs_2ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi0'] | default(0) }}

  • name: Unifi AP Upstairs 5gHz Clients unique_id: unifi_ap_upstairs_5ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Upstairs total Clients unique_id: unifi_ap_upstairs_total_clients state: > {{ state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['upstairs_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Upstairs Updates unique_id: unifi_ap_upstairs_update state: > {% if state_attr('sensor.unifi_stats', 'data')['upstairs_ap.Update'] == 0 %} No {% else %} Available {% endif %}

    Unifi UDM Pro

  • name: Unifi UDM Pro Ports Used unique_id: unifi_udmpro_ports_used state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.Ports_used'] }}

  • name: Unifi UDM Pro Ports User unique_id: unifi_udmpro_guests state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.Ports_user'] }}

  • name: Unifi UDM Pro Ports Guest unique_id: unifi_udmpro_ports_guests state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.Ports_guest'] | default(0)}}

  • name: Unifi UDM Pro Activity unique_id: unifi_udmpro_activity unit_of_measurement: 'Mbps' state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.Activity'].split(' ')[0] | float(0) }}

  • name: Unifi UDM Pro RAM unique_id: unifi_udmpro_ram unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.RAM'] | float(0) }}

  • name: Unifi UDM Pro CPU unique_id: unifi_udmpro_cpu unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.CPU'] | float(0) }}

  • name: Unifi UDM Pro CPU Temp unique_id: unifi_udmpro_cpu_temp unit_of_measurement: 'c' state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.CPUTemp'] | default(0) }}

  • name: Unifi UDM Pro Board Temp unique_id: unifi_udmpro_board_temp unit_of_measurement: 'c' state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.BoardTemp'] | default(0) }}

  • name: Unifi UDM Pro Updates unique_id: unifi_udmpro_update state: > {% if state_attr('sensor.unifi_stats', 'data')['udmpro.Update'] == 0 %} No {% else %} Available {% endif %}

  • name: Unifi UDM Pro Speedtest Ping unique_id: unifi_udmpro_speed_test_ping state: > {{state_attr('sensor.unifi_stats','data')['udmpro.Speedtest_ping']}}

  • name: Unifi UDM Pro Speedtest up unique_id: unifi_udmpro_speed_test_up state: > {{state_attr('sensor.unifi_stats','data')['udmpro.Speedtest_up']}}

  • name: Unifi UDM Pro Speedtest Down unique_id: unifi_udmpro_speed_test_down state: > {{state_attr('sensor.unifi_stats','data')['udmpro.Speedtest_down']}}

    Unifi AP Garage

  • name: Unifi AP Garage Guests unique_id: unifi_ap_garage_guests state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Guests'] }}

  • name: Unifi AP Garage Activity unique_id: unifi_ap_garage_activity unit_of_measurement: 'Mbps' state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Activity'].split(' ')[0] | float(0) }}

  • name: Unifi AP Garage RAM unique_id: unifi_ap_garage_ram unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.RAM'] | float(0) }}

  • name: Unifi AP Garage CPU unique_id: unifi_ap_garage_cpu unit_of_measurement: '%' state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.CPU'] | float(0) }}

  • name: Unifi AP Garage Score unique_id: unifi_ap_garage_score state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Score'] }}

  • name: Unifi AP Garage 2.4gHz Score unique_id: unifi_ap_garage_2ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Score_wifi0'] | default(0) }}

  • name: Unifi AP Garage 5gHz Score unique_id: unifi_ap_garage_5ghz_score state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Score_wifi1'] | default(0) }}

  • name: Unifi AP Garage 2.4gHz Clients unique_id: unifi_ap_garage_2ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi0'] | default(0) }}

  • name: Unifi AP Garage 5gHz Clients unique_id: unifi_ap_garage_5ghz_wifi_devices state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Garage total Clients unique_id: unifi_ap_garage_total_clients state: > {{ state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi0'] + state_attr('sensor.unifi_stats','data')['garage_ap.Clients_wifi1'] | default(0) }}

  • name: Unifi AP Garage Updates unique_id: unifi_ap_garage_update state: > {% if state_attr('sensor.unifi_stats', 'data')['garage_ap.Update'] == 0 %} No {% else %} Available {% endif %}

  • name: "UDM CPU" unique_id: unifi_gateway_wan_cpu unit_of_measurement: "%" state: > {{ state_attr('sensor.unifi_stats','data')['health_wan.cpu'] }}

  • name: "UDM Memory" unique_id: unifi_gateway_wan_mem unit_of_measurement: "%" state: > {{ state_attr('sensor.unifi_stats','data')['health_wan.mem'] }}

  • name: "WAN IP" unique_id: unifi_gateway_wan_ip state: > {{ state_attr('sensor.unifi_stats','data')['udmpro.UplinkIP'] }}

  • name: "WAN Download" unique_id: unifi_gateway_wan_download unit_of_measurement: Kbps icon: "mdi:progress-download" state: > {{ (state_attr('sensor.unifi_stats','data')['health_wan.rx_bytes'] / 1024 )| int }}

  • name: "USG Uptime" unique_id: unifi_gateway_wan_uptime state: >- {%- set time = state_attr('sensor.unifi_stats','data')['health_wan.uptime'] | int %} {%- set minutes = ((time % 3600) // 60) %} {%- set minutes = '{}min'.format(minutes) if minutes > 0 else '' %} {%- set hours = ((time % 86400) // 3600) %} {%- set hours = '{}hr '.format(hours) if hours > 0 else '' %} {%- set days = (time // 86400) %} {%- set days = '{}d '.format(days) if days > 0 else '' %} {{ 'Less than 1 min' if time < 60 else days + hours + minutes }}

  • name: "USG Firmware Version" unique_id: unifi_gateway_firmware_version icon: "mdi:database-plus" state: >- {{ state_attr('sensor.unifi_stats','data')['health_wan.gw_version'] }}

  • name: "USG Speedtest Download" unique_id: unifi_gateway_www_xput_down unit_of_measurement: Mbps icon: "mdi:progress-download" state: >- {{ state_attr('sensor.unifi_stats','data')['health_www.xput_down'] }}

  • name: "USG Speedtest Upload" unique_id: unifi_gateway_www_xput_up unit_of_measurement: Mbps icon: "mdi:progress-upload" state: >- {{ state_attr('sensor.unifi_stats','data')['health_www.xput_up'] }}

  • name: "USG Speedtest Ping" unique_id: unifi_gateway_www_speedtest_ping unit_of_measurement: ms icon: "mdi:progress-clock" state: >- {{ state_attr('sensor.unifi_stats','data')['health_www.speedtest_ping'] }}

  • name: "Internet Uptime" unique_id: unifi_gateway_www_uptime state: > {%- set time = state_attr('sensor.unifi_stats','data')['health_www.uptime'] | int %} {%- set minutes = ((time % 3600) // 60) %} {%- set minutes = '{}min'.format(minutes) if minutes > 0 else '' %} {%- set hours = ((time % 86400) // 3600) %} {%- set hours = '{}hr '.format(hours) if hours > 0 else '' %} {%- set days = (time // 86400) %} {%- set days = '{}d '.format(days) if days > 0 else '' %} {{ 'Less than 1 min' if time < 60 else days + hours + minutes }}

  • name: "Unifi Wlan Users" unique_id: unifi_gateway_wlan_num_user icon: "mdi:account-multiple" state: > {{ state_attr('sensor.unifi_stats','data')['health_lan.num_user'] }}

  • name: "Unifi Users Lan" unique_id: unifi_gateway_lan_num_user icon: "mdi:account-multiple" state: > {{ state_attr('sensor.unifi_stats','data')['health_lan.num_user'] }}

  • name: "UDM-Firmware Version" unique_id: unifi_gateway_firmware state: > {{ state_attr('sensor.unifi_stats','version') }} icon: mdi:counter

hope its helpful to someone

— Reply to this email directly, view it on GitHub https://github.com/custom-components/sensor.unifigateway/issues/59#issuecomment-1938652085, or unsubscribe https://github.com/notifications/unsubscribe-auth/AYS5HXJRTOXGLDJYPXDIOQLYTIIDHAVCNFSM6AAAAABAE6EHR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZYGY2TEMBYGU . You are receiving this because you commented.Message ID: @.***>

johntdyer commented 4 months ago

I dont really like inline python so I put my scripts into a script folder and execute them from the command_line sensor w/ the full path

coldburn89 commented 4 months ago

I dont really like inline python so I put my scripts into a script folder and execute them from the command_line sensor w/ the full path

Do you mind sharing that part of the command_line?

johntdyer commented 4 months ago

I did.... So try these steps

  1. Take the python code and paste that into /config/scripts/unifi_combined.py
  2. chmod +x /config/scripts/unifi_combined.py
  3. Add the following to your configuration.yaml
command_line:

  - sensor:
      command: '/config/scripts/unifi_combined.py'
      command_timeout: 180
      name: unifi_stats
      value_template: '{{value_json.version}}' 
      scan_interval: 300
      json_attributes:
        - data
  1. run the command_line.reload service from developer tools
  2. Goto entities and look for sensor.unifi_stats

Hope that helps

coldburn89 commented 4 months ago

is the "chmod +x /config/scripts/unifi_combined.py" really needed? And also how do I do this? via SSH?

On Mon, 12 Feb 2024 at 18:28, John Dyer @.***> wrote:

I did.... So try these steps

  1. Take the python code and paste that into /config/scripts/unifi_combined.py
  2. chmod +x /config/scripts/unifi_combined.py
  3. Add the following to your configuration.yaml

command_line:

  • sensor: command: '/config/scripts/unifi_combined.py' command_timeout: 180 name: unifi_stats value_template: '{{value_json.version}}' scan_interval: 300 json_attributes:
    • data

— Reply to this email directly, view it on GitHub https://github.com/custom-components/sensor.unifigateway/issues/59#issuecomment-1939200163, or unsubscribe https://github.com/notifications/unsubscribe-auth/AYS5HXIDJM3D34CEW6PDFYTYTJGLPAVCNFSM6AAAAABAE6EHR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZZGIYDAMJWGM . You are receiving this because you commented.Message ID: @.***>

johntdyer commented 4 months ago

oh yea, its all via SSH... sorry, guess I assumed you were using ssh

coldburn89 commented 4 months ago

when loading the command_line (i copied your script) i get the following error. Do you know what happend? Do i need to install python or something?

Logger: homeassistant.components.command_line.utils Source: components/command_line/utils.py:54 Integration: Command Line (documentation, issues) First occurred: 19:19:58 (3 occurrences) Last logged: 19:21:58

Command failed (with return code 1): /config/scripts/unifi_combined.py Command failed (with return code 1): python3 /config/scripts/unifi_ap.py

On Mon, 12 Feb 2024 at 18:43, John Dyer @.***> wrote:

oh yea, its all via SSH... sorry, guess I assumed you were using ssh

— Reply to this email directly, view it on GitHub https://github.com/custom-components/sensor.unifigateway/issues/59#issuecomment-1939224956, or unsubscribe https://github.com/notifications/unsubscribe-auth/AYS5HXPQ4BI6PTQA6HEIYLTYTJIEXAVCNFSM6AAAAABAE6EHR6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZZGIZDIOJVGY . You are receiving this because you commented.Message ID: @.***>

johntdyer commented 4 months ago

Can you drop to ssh shell and run

python3 /config/scripts/unifi_ap.py
python3 /config/scripts/unifi_combined.py

I would like to see the error

coldburn89 commented 4 months ago

python

Also tried with pyscript (custom component)

johntdyer commented 4 months ago

oh FFS.... seems like you dont have some packages installed via your custom components that I do have... ok we can work around this..... We're going to make a stub component that just installs that package and nothing else.... Total hack but should work

mkdir /config/custom_components/hello_world
cd /config/custom_components/hello_world
wget https://gist.githubusercontent.com/johntdyer/4d1cf4692241e6a7ac299e64f2657efe/raw/21e870f2ff190ce44598a1f8b65bcdfbfd704ca9/__init__.py
wget https://gist.githubusercontent.com/johntdyer/4d1cf4692241e6a7ac299e64f2657efe/raw/21e870f2ff190ce44598a1f8b65bcdfbfd704ca9/manifest.json

Then restart and try again, if it doesnt work please attach the startup logs to your response

PlayFaster commented 4 months ago

Hi

@johntdyer - big big thanks for sharing your solution and helping to make it work for others. The additional info this has, beyond the official Unifi integration is very useful!

I've been follwoing along today and am seeing similiar errors. I have added the py script, and the command line sensor. The good news is that this IS logging into my Unifi (UDM-Pro) system, I can see the login in the Unifi logs. The sensor remains "Unknown" however, and the only issue in the logs is ...

2024-02-12 21:15:02.767 ERROR (SyncWorker_5) [homeassistant.components.command_line.utils] Command failed (with return code 1): /config/scripts/unifi_combined.py 2024-02-12 21:15:02.767 WARNING (MainThread) [homeassistant.components.command_line] Empty reply found when expecting JSON data

Let me know if I can provide any additional info and thanks again!

johntdyer commented 4 months ago

@PlayFaster yea, this is what all that jsondump() commented out code is about.... need to run the script yourself in terminal and get the exact line its failing then see if you can dump that value and see whats missing that it expects.... the are seemingly an inasane amount of nuances between versions and models as to what is returned, even basic stuff like uptime is different amongst versions .... honestly this is probably why the author of this said to hell with it.... Unifi kinda sucks in that they dont even publish an api , its all reverse engineered

PlayFaster commented 4 months ago

Hi @johntdyer . Understood and thanks. I'll start going thru the script and see what works for me and doesn't..

martinkwright commented 4 months ago

trying to follow along and have made progress. Thanks so much for trying to help us out @johntdyer .

Feeling like I have everything in place but I am getting an error of ModuleNotFoundError: No module named 'request' when trying to run the script.

Ran your wget's as well so not sure whats up with the request module.

johntdyer commented 4 months ago

can you try pip3 install request ?

martinkwright commented 4 months ago

ERROR: Could not find a version that satisfies the requirement request (from versions: none) ERROR: No matching distribution found for request

Just kidding... was missing an (s) in requests.

pip3 install requests

martinkwright commented 4 months ago

A step forward, but now SSL errors attempting to connect.

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate

PlayFaster commented 4 months ago

Hi Folks. This now works for me. Again, a BIG thanks to @johntdyer for this.

For reference, in case its of use to anyone, here's what I needed to change (including fixing some of my own misinterpretations!) ...

 (1) If you're not using an SSL cert, change verify=True to verify=False in Line 35 

I made two changes because I thought I should. I should NOT have, these were ...

 (2) Script Line 22: controller_url = 'https://xxxxx.xxxxx.xxxxx' 
      Even if you're not using a certificate, don't change the https to http! 

 (3) Put your username and password into Lines 23 and 24. Do NOT put them into lines 30 and 31 again! 

Note: Once I used @johntdyer WGET commands, I did not need to load any further modules, such as "requests" etc. All worked, once I made the above mods.

Happy network monitoring to all. Remember, "it's a hobby, not an obsession" (?)

martinkwright commented 4 months ago

thanks so much @johntdyer and @PlayFaster. Up and running.

coldburn89 commented 4 months ago

Hi Folks. This now works for me. Again, a BIG thanks to @johntdyer for this.

For reference, in case its of use to anyone, here's what I needed to change (including fixing some of my own misinterpretations!) ...

 (1) If you're not using an SSL cert, change verify=True to verify=False in Line 35 

I made two changes because I thought I should. I should NOT have, these were ...

 (2) Script Line 22: controller_url = 'https://xxxxx.xxxxx.xxxxx' 
      Even if you're not using a certificate, don't change the https to http! 

 (3) Put your username and password into Lines 23 and 24. Do NOT put them into lines 30 and 31 again! 

Note: Once I used @johntdyer WGET commands, I did not need to load any further modules, such as "requests" etc. All worked, once I made the above mods.

Happy network monitoring to all. Remember, "it's a hobby, not an obsession" (?)

Nice its working for me also! The SSL check to false did the trick. Now i can make the templates and put all the information in the sensors. Thank you everyone!! @johntdyer you are so good, you should make your own integration for Unifi 👍

 (1) If you're not using an SSL cert, change verify=True to verify=False in Line 35 
coldburn89 commented 4 months ago

@johntdyer Do you know by any chance to get more WAN info out of it? Currently i dont get the WAN IP for example. I see you commented out some parts of the script, but not sure if intended. By the looks of your template sensors you are getting the IP's, right?

Again, thank you so much :)

johntdyer commented 4 months ago

The WAN ip is there

➜  ~
➜  ~ python3 /config/scripts/unifi_combined2.py
{
  "data": {
    "health_wlan.num_user": 96,
    "health_wlan.num_guest": 0,
    "health_wlan.num_iot": 0,
    "health_wlan.tx_bytes": 0,
    "health_wlan.rx_bytes": 0,
    "health_wlan.status": "ok",
    "health_wlan.num_ap": 4,
    "health_wan.status": "ok",
    "health_wan.isp_organization": "ATT-INTERNET4",
    "health_wan.isp_name": "AT&T Internet",
    "health_wan.gw_version": "3.2.9.14421",
    "health_wan.num_sta": 167,
    "health_wan.cpu": "28.9",
    "health_wan.mem": "87.4",
    "health_wan.uptime": "2073560",
    "health_wan.tx_bytes": 27286,
    "health_wan.rx_bytes": 77557,
    "health_www.status": "ok",
    "health_www.tx_bytes-r": 27286,
    "health_www.rx_bytes-r": 77557,
    "health_www.latency": 2,
    "health_www.uptime": 301294,
    "health_www.drops": 5,
    "health_www.xput_up": 885.83,
    "health_www.xput_down": 798.636,
    "health_www.speedtest_status": "Success",
    "health_www.speedtest_lastrun": 1707562348,
    "health_www.speedtest_ping": 7,
    "health_lan.status": "ok",
    "health_lan.num_user": 71,
    "health_lan.num_iot": 12,
    "health_lan.num_sw": 7,
    "health_lan.num_adopted": 7,
    "health_vpn.status": "error",
    "upstairs_great_room.Activity": "0.0 Mbps",
    "upstairs_great_room.CPU": 0,
    "upstairs_great_room.RAM": 0,
    "upstairs_great_room.Uptime": "23d 1h 13m",
    "upstairs_great_room.Ports_used": 1,
    "upstairs_great_room.Ports_user": 1,
    "upstairs_great_room.Ports_guest": 0,
    "upstairs_great_room.Update": 0,
    "upstairs_great_room.Model": "USMINI",
    "attic_switch.Activity": "0.0 Mbps",
    "attic_switch.CPU": 56.6,
    "attic_switch.RAM": 38.6,
    "attic_switch.Uptime": "14d 19h 28m",
    "attic_switch.Ports_used": 1,
    "attic_switch.Ports_user": 1,
    "attic_switch.Ports_guest": 0,
    "attic_switch.Update": 0,
    "attic_switch.Model": "US8P60",
    "udmpro.Activity": "0.8 Mbps",
    "udmpro.CPU": 28.9,
    "udmpro.RAM": 87.4,
    "udmpro.Uptime": "23d 23h 59m",
    "udmpro.Ports_used": 160,
    "udmpro.Ports_user": 160,
    "udmpro.Ports_guest": 0,
    "udmpro.Update": 0,
    "udmpro.Model": "UDMPRO",
    "udmpro.Speedtest_ping": 7,
    "udmpro.Speedtest_up": 885.83,
    "udmpro.Speedtest_down": 798.636,
    "udmpro.StorageUsed": 300494848,
    "udmpro.StorageSize": 2046640128,
    "udmpro.Internet": true,
    "udmpro.SpeedTestPass": true,
    "udmpro.CPUTemp": 64.0,
    "udmpro.BoardTemp": 44.0,
    "udmpro.WanDrops": 5,
    "udmpro.WanLatency": 2,
    "udmpro.LatencyAvg": 100,
    "udmpro.WanAvailability": 100.0,
    "udmpro.UplinkIP": "xxxxx.xxxx.xxxx.xxxx",
    "garage_ap.Clients": 21,
    "garage_ap.Guests": 0,
    "garage_ap.Clients_wifi0": 20,
    "garage_ap.Clients_wifi1": 1,
    "garage_ap.Score": 96,
    "garage_ap.CPU": 15.4,
    "garage_ap.RAM": 50.1,
    "garage_ap.Uptime": "61d 23h 32m",
    "garage_ap.Score_wifi0": 96,
    "garage_ap.Score_wifi1": 100,
    "garage_ap.Activity": "0.0 Mbps",
    "garage_ap.Update": 0,
    "outside_switch.Activity": "0.0 Mbps",
    "outside_switch.CPU": 6.4,
    "outside_switch.RAM": 17.2,
    "outside_switch.Uptime": "14d 19h 29m",
    "outside_switch.Ports_used": 9,
    "outside_switch.Ports_user": 9,
    "outside_switch.Ports_guest": 0,
    "outside_switch.Update": 0,
    "outside_switch.Model": "USF5P",
    "outside_ap.Clients": 7,
    "outside_ap.Guests": 0,
    "outside_ap.Clients_wifi0": 7,
    "outside_ap.Clients_wifi1": 0,
    "outside_ap.Score": 98,
    "outside_ap.CPU": 7.4,
    "outside_ap.RAM": 48.1,
    "outside_ap.Uptime": "5d 5h 15m",
    "outside_ap.Score_wifi0": 98,
    "outside_ap.Score_wifi1": -1,
    "outside_ap.Activity": "0.0 Mbps",
    "outside_ap.Update": 0,
    "core_switch.Activity": "0.0 Mbps",
    "core_switch.CPU": 59.1,
    "core_switch.RAM": 32.2,
    "core_switch.Uptime": "9d 4h 57m",
    "core_switch.Ports_used": 42,
    "core_switch.Ports_user": 42,
    "core_switch.Ports_guest": 0,
    "core_switch.Update": 0,
    "core_switch.Model": "US48PRO",
    "upstairs_switch.Activity": "0.0 Mbps",
    "upstairs_switch.CPU": 56.5,
    "upstairs_switch.RAM": 38.6,
    "upstairs_switch.Uptime": "14d 19h 27m",
    "upstairs_switch.Ports_used": 3,
    "upstairs_switch.Ports_user": 3,
    "upstairs_switch.Ports_guest": 0,
    "upstairs_switch.Update": 0,
    "upstairs_switch.Model": "US8",
    "upstairs_ap.Clients": 25,
    "upstairs_ap.Guests": 0,
    "upstairs_ap.Clients_wifi0": 24,
    "upstairs_ap.Clients_wifi1": 1,
    "upstairs_ap.Score": 98,
    "upstairs_ap.CPU": 9.6,
    "upstairs_ap.RAM": 66.9,
    "upstairs_ap.Uptime": "4d 7h 25m",
    "upstairs_ap.Score_wifi0": 99,
    "upstairs_ap.Score_wifi1": 98,
    "upstairs_ap.Activity": "0.0 Mbps",
    "upstairs_ap.Update": 0,
    "garage_switch.Activity": "0.0 Mbps",
    "garage_switch.CPU": 0,
    "garage_switch.RAM": 0,
    "garage_switch.Uptime": "113d 20h 13m",
    "garage_switch.Ports_used": 2,
    "garage_switch.Ports_user": 2,
    "garage_switch.Ports_guest": 0,
    "garage_switch.Update": 0,
    "garage_switch.Model": "USMINI",
    "basement_ap.Clients": 41,
    "basement_ap.Guests": 0,
    "basement_ap.Clients_wifi0": 34,
    "basement_ap.Clients_wifi1": 7,
    "basement_ap.Score": 97,
    "basement_ap.CPU": 29.2,
    "basement_ap.RAM": 50.6,
    "basement_ap.Uptime": "7d 14h 53m",
    "basement_ap.Score_wifi0": 97,
    "basement_ap.Score_wifi1": 98,
    "basement_ap.Activity": "0.0 Mbps",
    "basement_ap.Update": 0
  },
  "version": "8.0.28"
}
➜  ~

or am I misunderstanding ?

coldburn89 commented 4 months ago

for you its there but not for me :( Not sure about other UDM users. The whole uplink info is not there.

Data health_wlan.num_user: 28 health_wlan.num_guest: 0 health_wlan.num_iot: 0 health_wlan.tx_bytes: 55502 health_wlan.rx_bytes: 8433 health_wlan.status: ok health_wlan.num_ap: 3 health_wan.status: ok health_wan.isp_organization: KPN B.V. health_wan.isp_name: KPN health_wan.gw_version: 3.2.12.14768 health_wan.num_sta: 32 health_wan.cpu: '3.2' health_wan.mem: '87.7' health_wan.uptime: '1006518' health_wan.tx_bytes: 10397 health_wan.rx_bytes: 17620 health_www.status: ok health_www.tx_bytes-r: 10397 health_www.rx_bytes-r: 17620 health_www.latency: 10 health_www.uptime: 1006480 health_www.drops: 1 health_www.xput_up: 58.794 health_www.xput_down: 162.908 health_www.speedtest_status: Success health_www.speedtest_lastrun: 1707793245 health_www.speedtest_ping: 13 health_lan.status: ok health_lan.num_user: 4 health_lan.num_iot: 0 health_lan.num_sw: 4 health_lan.num_adopted: 4 health_vpn.status: ok ap_03_zolder.Clients: 11 ap_03_zolder.Guests: 0 ap_03_zolder.Clients_wifi0: 9 ap_03_zolder.Clients_wifi1: 2 ap_03_zolder.Score: 97 ap_03_zolder.CPU: 1.3 ap_03_zolder.RAM: 40 ap_03_zolder.Uptime: 12d 1h 28m ap_03_zolder.Score_wifi0: 97 ap_03_zolder.Score_wifi1: 99 ap_03_zolder.Activity: 0.0 Mbps ap_03_zolder.Update: 0 usw_flex_mini_woonkamer.Activity: 0.0 Mbps usw_flex_mini_woonkamer.CPU: 0 usw_flex_mini_woonkamer.RAM: 0 usw_flex_mini_woonkamer.Uptime: 22d 9h 30m usw_flex_mini_woonkamer.Ports_used: 1 usw_flex_mini_woonkamer.Ports_user: 1 usw_flex_mini_woonkamer.Ports_guest: 0 usw_flex_mini_woonkamer.Update: 0 usw_flex_mini_woonkamer.Model: USMINI dream_machine.Clients: 11 dream_machine.Guests: 0 dream_machine.Clients_wifi0: 7 dream_machine.Clients_wifi1: 4 dream_machine.Score: 99 dream_machine.CPU: 3.2 dream_machine.RAM: 87.7 dream_machine.Uptime: 11d 15h 35m dream_machine.Score_wifi0: 99 dream_machine.Score_wifi1: 99 dream_machine.Activity: 0.2 Mbps dream_machine.Update: 0 usw_flex_mini_zolder.Activity: 0.0 Mbps usw_flex_mini_zolder.CPU: 0 usw_flex_mini_zolder.RAM: 0 usw_flex_mini_zolder.Uptime: 30d 5h 31m usw_flex_mini_zolder.Ports_used: 3 usw_flex_mini_zolder.Ports_user: 3 usw_flex_mini_zolder.Ports_guest: 0 usw_flex_mini_zolder.Update: 0 usw_flex_mini_zolder.Model: USMINI usw_flex_mini_slaapkamer.Activity: 0.0 Mbps usw_flex_mini_slaapkamer.CPU: 0 usw_flex_mini_slaapkamer.RAM: 0 usw_flex_mini_slaapkamer.Uptime: 30d 5h 1m usw_flex_mini_slaapkamer.Ports_used: 0 usw_flex_mini_slaapkamer.Ports_user: 0 usw_flex_mini_slaapkamer.Ports_guest: 0 usw_flex_mini_slaapkamer.Update: 0 usw_flex_mini_slaapkamer.Model: USMINI ap_02_slaapkamer.Clients: 6 ap_02_slaapkamer.Guests: 0 ap_02_slaapkamer.Clients_wifi0: 4 ap_02_slaapkamer.Clients_wifi1: 2 ap_02_slaapkamer.Score: 98 ap_02_slaapkamer.CPU: 0.5 ap_02_slaapkamer.RAM: 41.2 ap_02_slaapkamer.Uptime: 30d 4h 32m ap_02_slaapkamer.Score_wifi0: 98 ap_02_slaapkamer.Score_wifi1: 99 ap_02_slaapkamer.Activity: 0.0 Mbps ap_02_slaapkamer.Update: 0

PlayFaster commented 4 months ago

The WAN IP does show for me, just to confirm. Running on a UDM Pro.

I would suggest going to the URL for the Health info directly on your UDM and see what appears there.

Go to https://xxxx.xxxx.xxx/proxy/network/api/s/default/stat/health (login to your UDM console first) and see what's produced. Search for wan_ip, or your actual IP address.

coldburn89 commented 4 months ago

proxy/network/api/s/default/stat/health

Yes when i run this i see more stats including wan IP and for example targets of ping tests.. How can i integrate this into my Home Assistant? Change the python part?

I also see alot of data in https://xxx.xxx.xxx/proxy/network/api/s/default/stat/sysinfo but how do i extract it?

Below is my python script (listed by john)

`

!/usr/local/bin/python

from datetime import timedelta import json, yaml, requests from datetime import datetime import requests,time from re import sub import sys

resp={} resp['data']={}

def parse_uptime(uptime): seconds = 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' return uptime

controller_url = 'https://192.168.1.1' username = 'username' password = 'password' site = 'default' # The site ID, 'default' for most installations

login_url = f'{controller_url}/api/auth/login' login_data = { 'username': username, 'password': password }

session = requests.Session() response = session.post(login_url, json=login_data, verify=False) response.raise_for_status()

def snakecase(s): return ''.join( sub('([A-Z][a-z]+)', r' \1', sub('([A-Z]+)', r' \1', s.replace('-', ' '))).split()).lower()

rules_url = 'https://192.168.1.1/proxy/network/api/s/default/stat/device'

response = session.get(rules_url, verify=False) response.raise_for_status() rules = response.json() sysinfo_url = 'https://192.168.1.1/proxy/network/api/s/default/stat/sysinfo'

response = session.get(sysinfo_url, verify=False) response.raise_for_status() version = response.json()

health_url = 'https://192.168.1.1/proxy/network/api/s/default/stat/health'

response = session.get(health_url, verify=False) response.raise_for_status() health_data = response.json()

keys = health_data['data'][0].keys()

a = {k: set(d[k] for d in health_data['data']) for k in keys}

print(json.dumps(health_data, indent = 1))

# for h in health_data['data']:

match h['subsystem']: case 'www':

print(json.dumps(h, indent = 1))

  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".tx_bytes-r": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes-r": h['rx_bytes-r'],
    "health_" + h['subsystem'] + ".latency": h['latency'],
    "health_" + h['subsystem'] + ".uptime": h['uptime'],
    "health_" + h['subsystem'] + ".drops": h['drops'],
    "health_" + h['subsystem'] + ".xput_up": h['xput_up'],
    "health_" + h['subsystem'] + ".xput_down": h['xput_down'],
    "health_" + h['subsystem'] + ".speedtest_status": h['speedtest_status'],
    "health_" + h['subsystem'] + ".speedtest_lastrun": h['speedtest_lastrun'],
    "health_" + h['subsystem'] + ".speedtest_ping": h['speedtest_ping'],
    "health_" + h['subsystem'] + ".uptime": h['uptime']

  })

case 'vpn':
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
  })
  # test
case 'wlan':
  resp['data'].update({
    "health_" + h['subsystem'] + ".num_user": h['num_user'],
    "health_" + h['subsystem'] + ".num_guest": h['num_guest'],
    "health_" + h['subsystem'] + ".num_iot": h['num_iot'],
    "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r'],
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".num_ap": h['num_ap']
  })

case 'lan':
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".num_user": h['num_user'],
    "health_" + h['subsystem'] + ".num_iot": h['num_iot'],
    "health_" + h['subsystem'] + ".num_sw": h['num_sw'],
    "health_" + h['subsystem'] + ".num_adopted": h['num_adopted']
  })

  # test
case 'wan':
  # print(h['subsystem'])
  # print(json.dumps(h, indent = 1))
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".isp_organization": h['isp_organization'],
    "health_" + h['subsystem'] + ".isp_name": h['isp_name'],
    "health_" + h['subsystem'] + ".gw_version": h['gw_version'],
    "health_" + h['subsystem'] + ".num_sta": h['num_sta'],
    "health_" + h['subsystem'] + ".cpu": h['gw_system-stats']['cpu'],
    "health_" + h['subsystem'] + ".mem": h['gw_system-stats']['mem'],
    "health_" + h['subsystem'] + ".uptime": h['gw_system-stats']['uptime'],
    "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r']
  })

case _:
  print("else")

uptime_stats = "https://192.168.1.1/proxy/network/api/s/default/stat/stats"

#

response_stats = session.get(uptime_stats, verify=False)

response_stats.raise_for_status()

data = response_stats.json()["data"][0]

print(version)

json.dumps(print(resp['data']))

print(json.dumps(resp['data'], indent = 1))

print(json.dumps({

"cpu": data["system-stats"]["cpu"],

"cpu_temp": round(data["temperatures"][1]["value"], 1),

"system_temp": round(data["temperatures"][0]["value"], 1),

"memory": data["system-stats"]["mem"],

"disk": round(data["storage"][1]["used"] / data["storage"][1]["size"] * 100, 1),

"internet": data["wan1"]["up"],

"uptime": datetime.fromtimestamp(data["startup_timestamp"]).isoformat(),

"availability": data["uptime_stats"]["WAN"]["availability"],

"average_latency": data["uptime_stats"]["WAN"]["latency_average"],

"down": data["uplink"]["rx_rate"] / 1000000,

"up": data["uplink"]["tx_rate"] / 1000000,

"version": data["displayable_version"],

"last_wan_ip": data["last_wan_ip"]

}))

sys.exit(2)

resp["version"]=version['data'][0]['version']

Find the rule to update

for client_data in rules['data']:

If switch is offline ignore

if client_data['state'] == 0: continue

name=snake_case(client_data['name'])

print(client_data)

resp[name]={}

print(version)

json.dumps(print(client_data))

internet = None speedtest_status = None

print("client_data['model'] %s",client_data['model'] )

if client_data['model'] == "UDMPRO": speedtest_status = client_data['uplink']['speedtest_status'] == "Success" internet = client_data['uplink']['up']

if 'uplink' in client_data.keys():

#   if client_data['uplink']['uplink_source'] == 'legacy':
#     internet = client_data['uplink']['up']
#   else:
#     internet = client_data['internet']
#     print("client_data['model'] %s",client_data['model'] )
# elif 'internet' in client_data.keys():
#   internet = client_data['internet']
#   print("client_data['model'] %s",client_data['model'] )

cpu=0 ram=0 try: if client_data['system-stats'] and client_data['system-stats'] != {} and len(client_data['system-stats'].keys()) != 0: try: cpu = float(client_data['system-stats']['cpu']) except: cpu = 0.0 try: ram = float(client_data['system-stats']['mem']) except: ram = 0 except: print("An exception occurred") print(json.dumps(client_data, indent = 1)) print("------")

activity = round(client_data['uplink']['rx_bytes-r']/125000 + client_data['uplink']['tx_bytes-r']/125000,1) uptime = parse_uptime(client_data['uptime']) update = int(client_data['upgradable']) model_type = client_data['model']

print(type)

if client_data['is_access_point']: wifi0clients = client_data['radio_table_stats'][0]['user-num_sta'] wifi1clients = client_data['radio_table_stats'][1]['user-num_sta'] wifi0score = client_data['radio_table_stats'][0]['satisfaction'] wifi1score = client_data['radio_table_stats'][1]['satisfaction'] numclients = client_data['user-wlan-num_sta'] numguests = client_data['guest-wlan-num_sta'] score = client_data['satisfaction']

  # raise ValueError('Some error')
  resp['data'].update ({
      name+".Clients":numclients,
      name+".Guests":numguests,
      name+".Clients_wifi0":wifi0clients ,
      name+".Clients_wifi1":wifi1clients ,
      name+".Score":score,
      name+".CPU": cpu,
      name+".RAM":ram,
      name+".Uptime":uptime,
      name+".Score_wifi0":wifi0score ,
      name+".Score_wifi1":wifi1score ,
      name+".Activity":str(activity)+' Mbps',
      name+".Update":update,
  })

else: cpu_temp = None board_temp = None wan_drops = None wan_latency = None if 'temperatures' in client_data.keys() and client_data['temperatures']!={}: for t in client_data['temperatures']: if t['type'] == "cpu" : cpu_temp = t['value'] if t['type'] == "board" : board_temp = t['value']

# json.dumps(print(client_data))
# print(json.dumps(client_data, indent = 1))

storage_used = None
storage_size = None
if 'storage' in client_data.keys() and  client_data['storage']!=[]:
  for t in client_data['storage']:

    if t['mount_point'] == "/persistent":
      storage_size = t['size']
      storage_used = t['used']

availability=None
latency_average=None
uplink_ip=None

if 'uptime_stats' in client_data.keys() and  client_data['uptime_stats']!={}:
    for t in client_data['uptime_stats']['WAN']['alerting_monitors']:
      if t['target'] == "1.1.1.1":
        latency_average = t['latency_average']
        availability = t['availability']

if 'uplink' in client_data.keys() and client_data['uplink']!={} and 'comment' in client_data['uplink'].keys():

    # json.dumps(print(client_data['uplink']))
    # print(json.dumps(client_data['uplink'], indent = 1))
    if client_data['uplink']['comment'] == "WAN":
      wan_latency = client_data['uplink']['latency']
      wan_drops = client_data['uplink']['drops']
      uplink_ip = client_data['uplink']['ip']

uplink

    # print(t)
        # print(json.dumps(client_data, indent = 1))
# if 'speedtest-status' in client_data.keys() and client_data['speedtest-status'] is not None:
#   print("---")
#   # print(client_data['speedtest-status'])
#   # json.dumps(print(client_data))
#   print(json.dumps(client_data['uplink'], indent = 1))

#   print("---")
# internet = client_data['internet']
usedports = client_data['num_sta']
userports = client_data['user-num_sta']
guestports = client_data['guest-num_sta']

resp['data'].update({
  name+".Activity":str(activity)+' Mbps',
  name+".CPU":cpu,
  name+".RAM":ram,
  name+".Uptime":uptime,
  name+".Ports_used":usedports,
  name+".Ports_user":userports,
  name+".Ports_guest":guestports,
  name+".Update":update,
  name+".Model": model_type
})

if 'speedtest_ping' in client_data['uplink'].keys() and client_data['uplink']['speedtest_ping'] is not None:

  resp['data'].update({
    name+".Speedtest_ping": client_data['uplink']['speedtest_ping'],
    name+".Speedtest_up":   client_data['uplink']['xput_up'],
    name+".Speedtest_down": client_data['uplink']['xput_down']
  })
if storage_used is not None:
  resp['data'].update({
    name+".StorageUsed": storage_used,
    name+".StorageSize": storage_size
  })
if internet is not None:
  resp['data'].update({
    name+".Internet": internet
  })
if speedtest_status is not None:
  resp['data'].update({
    name+".SpeedTestPass": speedtest_status
  })
if cpu_temp is not None:
  resp['data'].update({
    name+".CPUTemp":cpu_temp,
    name+".BoardTemp":board_temp
  })

if wan_drops is not None:
  resp['data'].update({
    name+".WanDrops":wan_drops,
    name+".WanLatency":wan_latency
  })

if latency_average is not None:
  resp['data'].update({
    name+".LatencyAvg":latency_average,
    name+".WanAvailability":availability
  })

if uplink_ip is not None:
  resp['data'].update({
    name+".UplinkIP":uplink_ip
  })

print(resp)

formatted_json = json.dumps(resp, sort_keys=True, indent=4)

colorful_json = highlight(formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter())

print(colorful_json)

json_formatted_str = json.dumps(resp, indent=2) print(json_formatted_str)

Log out of the UniFi Controller

logout_url = f'{controller_url}/api/auth/logout' session.post(logout_url, verify=False)

sys.exit(0) `

PlayFaster commented 4 months ago

Hi There. Try adding the wan_ip line into the WAN section, see below, added as 2nd line, under status ... see if this works for you ...

case 'wan':
  # print(h['subsystem'])
  # print(json.dumps(h, indent = 1))
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".wan_ip": h['wan_ip'],
    "health_" + h['subsystem'] + ".isp_organization": h['isp_organization'],
    "health_" + h['subsystem'] + ".isp_name": h['isp_name'],
    "health_" + h['subsystem'] + ".gw_version": h['gw_version'],
    "health_" + h['subsystem'] + ".num_sta": h['num_sta'],
    "health_" + h['subsystem'] + ".cpu": h['gw_system-stats']['cpu'],
    "health_" + h['subsystem'] + ".mem": h['gw_system-stats']['mem'],
    "health_" + h['subsystem'] + ".uptime": h['gw_system-stats']['uptime'],
    "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r']
  })
coldburn89 commented 4 months ago

Hi There. Try adding the wan_ip line into the WAN section, see below, added as 2nd line, under status ... see if this works for you ...

case 'wan':
  # print(h['subsystem'])
  # print(json.dumps(h, indent = 1))
  resp['data'].update({
    "health_" + h['subsystem'] + ".status": h['status'],
    "health_" + h['subsystem'] + ".wan_ip": h['wan_ip'],
    "health_" + h['subsystem'] + ".isp_organization": h['isp_organization'],
    "health_" + h['subsystem'] + ".isp_name": h['isp_name'],
    "health_" + h['subsystem'] + ".gw_version": h['gw_version'],
    "health_" + h['subsystem'] + ".num_sta": h['num_sta'],
    "health_" + h['subsystem'] + ".cpu": h['gw_system-stats']['cpu'],
    "health_" + h['subsystem'] + ".mem": h['gw_system-stats']['mem'],
    "health_" + h['subsystem'] + ".uptime": h['gw_system-stats']['uptime'],
    "health_" + h['subsystem'] + ".tx_bytes": h['tx_bytes-r'],
    "health_" + h['subsystem'] + ".rx_bytes": h['rx_bytes-r']
  })

Works like a charm! Thank you. Do you also know how to export the values of latency?

{"WAN":{"alerting_monitors":[{"availability":100.0,"latency_average":10,"target":"ping.ui.com","type":"icmp"},{"availability":100.0,"latency_average":100,"target":"1.1.1.1","type":"dns"},{"availability":100.0,"latency_average":100,"target":"8.8.8.8","type":"dns"}],"availability":100.0,"latency_average":10,"monitors":[{"availability":100.0,"latency_average":10,"target":"www.microsoft.com","type":"icmp"},{"availability":100.0,"latency_average":10,"target":"google.com","type":"icmp"},{"availability":100.0,"latency_average":10,"target":"1.1.1.1","type":"icmp"}],"time_period":86400,"uptime":199463}}},{"subsystem":"www","status":"ok","tx_bytes-r":8125,"rx_bytes-

PlayFaster commented 4 months ago

Hi. Not sure, on mobile now, will take a look later to see.