diff --git a/integrations/inputunifi/.gitignore b/integrations/inputunifi/.gitignore index 913e8eb4..2c836bd0 100644 --- a/integrations/inputunifi/.gitignore +++ b/integrations/inputunifi/.gitignore @@ -3,3 +3,5 @@ /*.1.gz /*.1 /vendor +.DS_Store +*~ diff --git a/integrations/inputunifi/README.md b/integrations/inputunifi/README.md index 8e850026..7981c6e9 100644 --- a/integrations/inputunifi/README.md +++ b/integrations/inputunifi/README.md @@ -1,12 +1,104 @@ # Unifi -Collect your Unifi Controller Client data and send it to an InfluxDB instance. Grafana dashboard included. - -![image](https://raw.githubusercontent.com/davidnewhall/unifi/master/grafana-unifi-dashboard.png) +Collect your Unifi Controller Data and send it to an InfluxDB instance. +Grafana dashboards included. ## Installation [See the Wiki!](https://github.com/davidnewhall/unifi-poller/wiki/Installation) +# Backstory + +Okay, so here's the deal. I found a simple piece of code on github that +sorta did what I needed; we all know that story. I wanted more data, so +I added more data collection. I believe I've completely rewritten every +piece of original code, except the copyright/license file and that's fine +by me. I probably wouldn't have made it this far if +[Garrett](https://github.com/dewski/unifi) hadn't written the original +code I started with. Many props my man. + +The original code pulled only the client data. This app now pulls data +for clients, access points, security gateways and switches. I currently +own two UAP-AC-PROs, one USG-3 and one US-24-250W. If your devices differ +this app may miss some data. I'm willing to help and make it better. +Open an [Issue](https://github.com/davidnewhall/unifi-poller/issues) and +we'll figure out how to get things working for you. + +# What's this data good for? + +I've been trying to get my UAP data into Grafana. Sure, google search that. +You'll find [this](https://community.ubnt.com/t5/UniFi-Wireless/Grafana-dashboard-for-UniFi-APs-now-available/td-p/1833532). +And that's all you'll find. What if you don't want to deal with SNMP? +Well, here you go. I've replicated 90% of what you see on those SNMP-powered +dashboards with this Go app running on the same mac as my Unifi controller. +All without enabling SNMP nor trying to understand those OIDs. Mad props +to [waterside](https://community.ubnt.com/t5/user/viewprofilepage/user-id/303058) +for making this dashboard; it gave me a fantastic start to making my own. + +# What now... + +- I probably suck at InfluxDB. + +I don't know what should be a tag and what should be a field. I think +I did my best, but there's certainly room for improvements in both +the data input and the Grafana graphs (output). + + +- The USW and USG code needs love. + +Up to this point, my focus has been on UAP. I have only included dashboards +that focus on UAP. I am still working on the other two, but it may be a while +before I get around to publishing them. Help is appreciated. + + +- Are there other devices that need to be included? + +I have: switch, router, access point. Three total, and the type structs are +likely missing data for variants of these devices. e.g. Some UAPs have more +radios, I probably didn't properly account for that. Some gateways have more +ports, some switches have 10Gb, etc. These are things I do not have data on +to write code for. If you have these devices, and want them graphed, open an +Issue and lets discuss. + + +- Better Installation instructions. + +If you're a nerd you can probably figure it out. I'd still like some pretty +pictures and maybe even a Twitch VOD. + + +- Sanity Checking + +Did I actually graph the right data in the right way? Some validation would +be nice. + + +- Radios, Frequencies, Interfaces, vAPs + +My access points only seem to have two radios, one interface and vAP per radio. +I'm not sure if the graphs, as-is, provide enough insight into APs with other +configurations. Help me figure that out? + +# What's it look like? + +Here's a picture of the Client dashboard. + +![image](images/unifi-clients-dashboard.png?raw=true) + +Here's a picture of the UAP dashboard. This only shows one device, but you can +select multiple to put specific stats side-by-side. + +![image](images/unifi-uap-dashboard.png?raw=true) + +# Woah, there's a library in here. + +Sure is. If you want to write your own code around unifi data, you can import +the `unidev` library and easily poll your controller. If you have interest in +how to use the library, or need more features, open an Issue. I'm not committed +to documenting it unless it seems useful. + + ## Copyright & License -Copyright © 2016 Garrett Bjerkhoel. See [MIT-LICENSE](MIT-LICENSE) for details. +- Copyright © 2016 Garrett Bjerkhoel. +- Copyright © 2018 David Newhall II. +- See [MIT-LICENSE](MIT-LICENSE) for license information. diff --git a/integrations/inputunifi/cmd/unifi-poller/config.go b/integrations/inputunifi/cmd/unifi-poller/config.go index a04de1d4..56fbbdde 100644 --- a/integrations/inputunifi/cmd/unifi-poller/config.go +++ b/integrations/inputunifi/cmd/unifi-poller/config.go @@ -4,7 +4,7 @@ import "time" // Version will be injected at build time. var ( - Version = "v0.1" + Version = "v0.2" Debug = false ) diff --git a/integrations/inputunifi/cmd/unifi-poller/main.go b/integrations/inputunifi/cmd/unifi-poller/main.go index cdfa86af..e8adb3b6 100644 --- a/integrations/inputunifi/cmd/unifi-poller/main.go +++ b/integrations/inputunifi/cmd/unifi-poller/main.go @@ -83,14 +83,14 @@ func GetConfig(configFile string) (Config, error) { func (c *Config) PollUnifiController(infdb influx.Client, unifi *unidev.AuthedReq) { ticker := time.NewTicker(c.Interval.value) for range ticker.C { - clients, err := unifi.GetUnifiClients() + clients, err := unifi.GetUnifiClientAssets() if err != nil { - log.Println("unifi.GetUnifiClients():", err) + log.Println("unifi.GetUnifiClientsAssets():", err) continue } - devices, err := unifi.GetUnifiDevices() + devices, err := unifi.GetUnifiDeviceAssets() if err != nil { - log.Println("unifi.GetUnifiDevices():", err) + log.Println("unifi.GetUnifiDeviceAssets():", err) continue } bp, err := influx.NewBatchPoints(influx.BatchPointsConfig{ @@ -102,10 +102,10 @@ func (c *Config) PollUnifiController(infdb influx.Client, unifi *unidev.AuthedRe } for _, asset := range append(clients, devices...) { - if pt, errr := asset.Point(); errr != nil { - log.Println("asset.Point():", errr) + if pt, errr := asset.Points(); errr != nil { + log.Println("asset.Points():", errr) } else { - bp.AddPoint(pt) + bp.AddPoints(pt) } } diff --git a/integrations/inputunifi/grafana-dashboards/README.md b/integrations/inputunifi/grafana-dashboards/README.md new file mode 100644 index 00000000..565178b7 --- /dev/null +++ b/integrations/inputunifi/grafana-dashboards/README.md @@ -0,0 +1,5 @@ +# Grafana Dashboards + +Import these into Grafana to quickly visualize data from your devices. + +They may/do use a few plugins: Clock, Discrete, Singlestat, Table diff --git a/integrations/inputunifi/unifi-poller-grafana-dashboard.json b/integrations/inputunifi/grafana-dashboards/unifi-clients-grafana-dash.json similarity index 100% rename from integrations/inputunifi/unifi-poller-grafana-dashboard.json rename to integrations/inputunifi/grafana-dashboards/unifi-clients-grafana-dash.json diff --git a/integrations/inputunifi/grafana-dashboards/unifi-uap-grafana-dash.json b/integrations/inputunifi/grafana-dashboards/unifi-uap-grafana-dash.json new file mode 100644 index 00000000..3fdf2626 --- /dev/null +++ b/integrations/inputunifi/grafana-dashboards/unifi-uap-grafana-dash.json @@ -0,0 +1,3577 @@ +{ + "__inputs": [ + { + "name": "DS_UNIFI", + "label": "Unifi", + "description": "", + "type": "datasource", + "pluginId": "influxdb", + "pluginName": "InfluxDB" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "grafana-clock-panel", + "name": "Clock", + "version": "0.0.9" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "influxdb", + "name": "InfluxDB", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": 1486, + "graphTooltip": 1, + "id": null, + "iteration": 1524957396402, + "links": [], + "panels": [ + { + "columns": [], + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fontSize": "100%", + "gridPos": { + "h": 6, + "w": 21, + "x": 0, + "y": 0 + }, + "id": 1, + "isNew": true, + "links": [], + "pageSize": null, + "scroll": false, + "showHeader": true, + "sort": { + "col": 11, + "desc": true + }, + "styles": [ + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Uptime", + "thresholds": [], + "type": "number", + "unit": "dtdurations" + }, + { + "alias": "Name", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": true, + "linkUrl": "http:", + "pattern": "name", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Config Version", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "cfgversion", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Board Rev", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "board_rev", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Model", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "model", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Device MAC", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "device_ap", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Unifi Serial #", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "serial", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Site ID", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "site_id", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Version", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 1, + "pattern": "Last Seen", + "sanitize": true, + "thresholds": [], + "type": "number", + "unit": "dateTimeAsUS" + }, + { + "alias": "Bandsteering Mode", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "bandsteering_mode", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 1, + "pattern": "CPU", + "thresholds": [], + "type": "number", + "unit": "percent" + } + ], + "targets": [ + { + "alias": "$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "name" + ], + "type": "tag" + }, + { + "params": [ + "model" + ], + "type": "tag" + }, + { + "params": [ + "cfgversion" + ], + "type": "tag" + }, + { + "params": [ + "board_rev" + ], + "type": "tag" + }, + { + "params": [ + "serial" + ], + "type": "tag" + }, + { + "params": [ + "site_id" + ], + "type": "tag" + }, + { + "params": [ + "bandsteering_mode" + ], + "type": "tag" + }, + { + "params": [ + "device_ap" + ], + "type": "tag" + } + ], + "measurement": "uap", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "version" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Version" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "ip" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "IP" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "uptime" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Uptime" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "last_seen" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "*1000" + ], + "type": "math" + }, + { + "params": [ + "Last Seen" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "cpu" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "CPU" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "name", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": null, + "title": "AP Details", + "transform": "table", + "transparent": false, + "type": "table" + }, + { + "content": "
\n
Unifi UAP
\n", + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 0 + }, + "id": 34, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "bgColor": "#3f2b5b", + "clockType": "12 hour", + "countdownSettings": { + "endCountdownTime": "2018-04-29T21:47:00.000Z", + "endText": "00:00:00" + }, + "dateSettings": { + "dateFormat": "YYYY-MM-DD", + "fontSize": "12px", + "fontWeight": "bold", + "showDate": true + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 3 + }, + "id": 32, + "links": [], + "mode": "time", + "offsetFromUtc": null, + "offsetFromUtcMinutes": null, + "timeSettings": { + "customFormat": "HH:mm:ss", + "fontSize": "30px", + "fontWeight": "normal" + }, + "title": "Now", + "type": "grafana-clock-panel" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 6 + }, + "height": "", + "id": 9, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "device_name", + "targets": [ + { + "alias": "", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "device_name" + ], + "type": "tag" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"channel\" FROM \"uap_radios\" WHERE (\"device_name\" =~ /^$host$/ AND \"radio\" = 'na') AND $timeFilter GROUP BY \"device_name\"", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "channel" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "na" + } + ] + } + ], + "thresholds": "", + "title": "5GHz Radio Channel", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 25, + "minValue": 6, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 6 + }, + "id": 11, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": " dBm", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 120, 193, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "device_name" + ], + "type": "tag" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tx_power" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "na" + } + ] + } + ], + "thresholds": "10,18", + "title": "5Ghz Radio Tx Power", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_UNIFI}", + "decimals": 1, + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": true, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 6 + }, + "hideTimeOverride": true, + "id": 30, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "system_uptime", + "targets": [ + { + "groupBy": [ + { + "params": [ + "name" + ], + "type": "tag" + } + ], + "measurement": "uap", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "cpu" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "name", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": "40,70", + "timeFrom": "1h", + "title": "CPU Usage", + "type": "singlestat", + "valueFontSize": "70%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_UNIFI}", + "decimals": 3, + "format": "dtdurations", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 6 + }, + "id": 29, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "system_uptime", + "targets": [ + { + "groupBy": [ + { + "params": [ + "name" + ], + "type": "tag" + } + ], + "measurement": "uap", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "uptime" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "name", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": "", + "title": "System Uptime", + "type": "singlestat", + "valueFontSize": "70%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 25, + "minValue": 6, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 6 + }, + "id": 12, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": " dBm", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "device_name" + ], + "type": "tag" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tx_power" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "radio", + "operator": "=", + "value": "ng" + }, + { + "condition": "AND", + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": "10,18", + "title": "2.4GHz Radio Tx Power", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 6 + }, + "id": 10, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "device_name" + ], + "type": "tag" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "channel" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "ng" + } + ] + } + ], + "thresholds": "", + "title": "2.4GHz Radio Channel", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 3, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_name $col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "name" + ], + "type": "tag" + } + ], + "measurement": "uap", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "loadavg_1" + ], + "type": "field" + }, + { + "params": [ + "load 1" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "loadavg_5" + ], + "type": "field" + }, + { + "params": [ + "laid 5" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "loadavg_15" + ], + "type": "field" + }, + { + "params": [ + "load15" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "name", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Load Average", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 7, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_name $col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "name" + ], + "type": "tag" + } + ], + "measurement": "uap", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "mem_buffer" + ], + "type": "field" + }, + { + "params": [ + "Buffer" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "mem_used" + ], + "type": "field" + }, + { + "params": [ + "Used" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "mem_total" + ], + "type": "field" + }, + { + "params": [ + "Total" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "name", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 18, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "ccq" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + " / 10" + ], + "type": "math" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Connection Quality", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "decimals": 0, + "editable": true, + "error": false, + "fill": 2, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 19, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name 5GHz", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "num_sta" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "na" + } + ] + }, + { + "alias": "$tag_device_name 2.4GHz", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "num_sta" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "ng" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Clients", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 8, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 3, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "cu_self_rx" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Rx" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "cu_self_tx" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Tx" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "cu_total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Total" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "na" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "5 GHz Channel Utilization", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fill": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 27, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 3, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "cu_self_rx" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Rx" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "cu_self_tx" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Tx" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "cu_total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "Total" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "ng" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "2.4GHz Channel Utilization", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 33 + }, + "id": 20, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/:Rx$/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "30s" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "rx_bytes" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "*8" + ], + "type": "math" + }, + { + "params": [ + "Rx" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_bytes" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "*8" + ], + "type": "math" + }, + { + "params": [ + "Tx" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "na" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "5 GHz Traffic", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 33 + }, + "id": 24, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/:Rx$/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "30s" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "rx_bytes" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "*8" + ], + "type": "math" + }, + { + "params": [ + "Rx" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_bytes" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "*8" + ], + "type": "math" + }, + { + "params": [ + "Tx" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "ng" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "2.4GHz Traffic", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "decimals": 0, + "description": "PPS on the na band calculated in 30 second buckets.", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 22, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/:In$/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "30s" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "rx_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Out" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "na" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "5 GHz Packets", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "decimals": 0, + "description": "PPS on the ng band calculated in 30 second buckets.", + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 25, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/:In$/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "30s" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "rx_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Out" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "ng" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "2.4GHz Packets", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "decimals": 0, + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 21, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/:In$/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "30s" + ], + "type": "time" + }, + { + "params": [ + "radio" + ], + "type": "tag" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "rx_dropped" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Drop:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_dropped" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Drop:Out" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "rx_errors" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Error:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_errors" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Error:Out" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "rx_crypts" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "BadCrypt:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "rx_frags" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "BadFrag:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_retries" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "ExsRetry:Out" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "na" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "5GHz Drops/Errors", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_UNIFI}", + "decimals": 0, + "editable": true, + "error": false, + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 26, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": null, + "sortDesc": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/:In$/", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_device_name:$col", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "30s" + ], + "type": "time" + }, + { + "params": [ + "device_name" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "uap_radios", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "rx_dropped" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Drop:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_dropped" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Drop:Out" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "rx_errors" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Error:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_errors" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "Error:Out" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "rx_crypts" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "BadCrypt:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "rx_frags" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "BadFrag:In" + ], + "type": "alias" + } + ], + [ + { + "params": [ + "tx_retries" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "1s" + ], + "type": "derivative" + }, + { + "params": [ + "ExsRetry:Out" + ], + "type": "alias" + } + ] + ], + "tags": [ + { + "key": "device_name", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "radio", + "operator": "=", + "value": "ng" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "2.4GHz Drops/Errors", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "refresh": "30s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": "Glances", + "value": "Glances" + }, + "hide": 2, + "label": null, + "name": "dataSource", + "options": [], + "query": "influxdb", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_UNIFI}", + "hide": 0, + "includeAll": true, + "label": "UniFi AP:", + "multi": true, + "name": "host", + "options": [], + "query": "show tag values from \"uap\" with key=\"name\"", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": null, + "tags": [], + "tagsQuery": null, + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-2h", + "to": "now" + }, + "timepicker": { + "nowDelay": "5s", + "refresh_intervals": [ + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "UniFi UAP Insights", + "uid": "8nQ_RPZiz", + "version": 28 +} diff --git a/integrations/inputunifi/grafana-unifi-dashboard.png b/integrations/inputunifi/images/unifi-clients-dashboard.png similarity index 100% rename from integrations/inputunifi/grafana-unifi-dashboard.png rename to integrations/inputunifi/images/unifi-clients-dashboard.png diff --git a/integrations/inputunifi/images/unifi-uap-dashboard.png b/integrations/inputunifi/images/unifi-uap-dashboard.png new file mode 100644 index 00000000..8c63867b Binary files /dev/null and b/integrations/inputunifi/images/unifi-uap-dashboard.png differ diff --git a/integrations/inputunifi/unidev/clients.go b/integrations/inputunifi/unidev/clients.go index 3e58af58..f4694537 100644 --- a/integrations/inputunifi/unidev/clients.go +++ b/integrations/inputunifi/unidev/clients.go @@ -7,8 +7,9 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Point generates a client's datapoint for InfluxDB. -func (u UCL) Point() (*influx.Point, error) { +// Points generates a client's datapoints for InfluxDB. +func (u UCL) Points() ([]*influx.Point, error) { + var points []*influx.Point if u.Name == "" && u.Hostname != "" { u.Name = u.Hostname } else if u.Hostname == "" && u.Name != "" { @@ -95,6 +96,9 @@ func (u UCL) Point() (*influx.Point, error) { "wired-tx_bytes-r": u.WiredTxBytesR, "wired-tx_packets": u.WiredTxPackets, } - - return influx.NewPoint("clients", tags, fields, time.Now()) + pt, err := influx.NewPoint("clients", tags, fields, time.Now()) + if err == nil { + points = append(points, pt) + } + return points, err } diff --git a/integrations/inputunifi/unidev/uap.go b/integrations/inputunifi/unidev/uap.go index 9e2847c1..af7c2986 100644 --- a/integrations/inputunifi/unidev/uap.go +++ b/integrations/inputunifi/unidev/uap.go @@ -7,8 +7,12 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Point generates a device's datapoint for InfluxDB. -func (u UAP) Point() (*influx.Point, error) { +// Points generates a device's datapoints for InfluxDB. +func (u UAP) Points() ([]*influx.Point, error) { + /* I generally suck at InfluxDB, so if I got the tags/fields wrong, + please send me a PR or open an Issue to address my faults. Thanks! + */ + var points []*influx.Point tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -35,7 +39,7 @@ func (u UAP) Point() (*influx.Point, error) { "has_speaker": strconv.FormatBool(u.HasSpeaker), "inform_ip": u.InformIP, "isolated": strconv.FormatBool(u.Isolated), - "last_seen": strconv.Itoa(u.LastSeen), + "last_seen": strconv.FormatFloat(u.LastSeen, 'f', 6, 64), "last_uplink_mac": u.LastUplink.UplinkMac, "last_uplink_remote_port": strconv.Itoa(u.LastUplink.UplinkRemotePort), "known_cfgversion": u.KnownCfgversion, @@ -74,6 +78,7 @@ func (u UAP) Point() (*influx.Point, error) { "loadavg_15": u.SysStats.Loadavg15, "mem_buffer": u.SysStats.MemBuffer, "mem_total": u.SysStats.MemTotal, + "mem_used": u.SysStats.MemUsed, "cpu": u.SystemStats.CPU, "mem": u.SystemStats.Mem, "system_uptime": u.SystemStats.Uptime, @@ -165,5 +170,98 @@ func (u UAP) Point() (*influx.Point, error) { "stat_wifi1-tx_packets": u.Stat.Wifi1TxPackets, "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries, } - return influx.NewPoint("uap", tags, fields, time.Now()) + pt, err := influx.NewPoint("uap", tags, fields, time.Now()) + if err != nil { + return nil, err + } + points = append(points, pt) + for _, p := range u.RadioTable { + tags := map[string]string{ + "device_name": u.Name, + "device_id": u.ID, + "device_mac": u.Mac, + "name": p.Name, + "wlangroup_id": p.WlangroupID, + "channel": p.Channel, // not the channel # + "radio": p.Radio, + } + fields := map[string]interface{}{ + "builtin_ant_gain": p.BuiltinAntGain, + "current_antenna_gain": p.CurrentAntennaGain, + "has_dfs": p.HasDfs, + "has_fccdfs": p.HasFccdfs, + "ht": p.Ht, + "is_11ac": p.Is11Ac, + "max_txpower": p.MaxTxpower, + "min_rssi_enabled": p.MinRssiEnabled, + "min_txpower": p.MinTxpower, + "nss": p.Nss, + "radio_caps": p.RadioCaps, + "tx_power": p.TxPower, + "tx_power_mode": p.TxPowerMode, + } + + for _, s := range u.RadioTableStats { + // This may be a tad slower but it allows putting + // all the radio stats into one table. + if p.Name == s.Name { + fields["ast_be_xmit"] = s.AstBeXmit + fields["ast_cst"] = s.AstCst + fields["channel"] = s.Channel + fields["ast_txto"] = s.AstTxto + fields["cu_self_rx"] = s.CuSelfRx + fields["cu_self_tx"] = s.CuSelfTx + fields["cu_total"] = s.CuTotal + fields["extchannel"] = s.Extchannel + fields["gain"] = s.Gain + fields["guest-num_sta"] = s.GuestNumSta + fields["num_sta"] = s.NumSta + fields["radio"] = s.Radio + fields["state"] = s.State + fields["radio_tx_packets"] = s.TxPackets + fields["radio_tx_power"] = s.TxPower + fields["radio_tx_retries"] = s.TxRetries + fields["user-num_sta"] = s.UserNumSta + } + } + for _, s := range u.VapTable { + if p.Name == s.RadioName { + tags["ap_mac"] = s.ApMac + tags["bssid"] = s.Bssid + fields["ccq"] = s.Ccq + fields["essid"] = s.Essid + fields["extchannel"] = s.Extchannel + tags["vap_id"] = s.ID + fields["is_guest"] = s.IsGuest + fields["is_wep"] = s.IsWep + fields["mac_filter_rejections"] = s.MacFilterRejections + fields["map_id"] = s.MapID + tags["vap_name"] = s.Name + fields["rx_bytes"] = s.RxBytes + fields["rx_crypts"] = s.RxCrypts + fields["rx_dropped"] = s.RxDropped + fields["rx_errors"] = s.RxErrors + fields["rx_frags"] = s.RxFrags + fields["rx_nwids"] = s.RxNwids + fields["rx_packets"] = s.RxPackets + fields["tx_bytes"] = s.TxBytes + fields["tx_dropped"] = s.TxDropped + fields["tx_errors"] = s.TxErrors + fields["tx_latency_avg"] = s.TxLatencyAvg + fields["tx_latency_max"] = s.TxLatencyMax + fields["tx_latency_min"] = s.TxLatencyMin + fields["tx_packets"] = s.TxPackets + fields["tx_power"] = s.TxPower + fields["tx_retries"] = s.TxRetries + fields["usage"] = s.Usage + tags["wlanconf_id"] = s.WlanconfID + } + } + pt, err := influx.NewPoint("uap_radios", tags, fields, time.Now()) + if err != nil { + return points, err + } + points = append(points, pt) + } + return points, nil } diff --git a/integrations/inputunifi/unidev/uap_type.go b/integrations/inputunifi/unidev/uap_type.go index d2f6a55a..30d1d3f2 100644 --- a/integrations/inputunifi/unidev/uap_type.go +++ b/integrations/inputunifi/unidev/uap_type.go @@ -1,7 +1,12 @@ package unidev -// UAP is a Unifi Access Point +// UAP is a Unifi Access Point. type UAP struct { + /* This was auto generated and then slowly edited by hand + to get all the data types right and graphable. + No ones feelings will be hurt if you want to break this + up into multiple structs, and/or make it better in general. + */ ID string `json:"_id"` UUptime float64 `json:"_uptime"` AdoptIP string `json:"adopt_ip,omitempty"` @@ -36,17 +41,17 @@ type UAP struct { Name string `json:"name"` NumPort float64 `json:"num_port"` } `json:"ethernet_table"` - FwCaps int `json:"fw_caps"` - GuestNumSta int `json:"guest-num_sta"` - GuestToken string `json:"guest_token"` - HasEth1 bool `json:"has_eth1"` - HasSpeaker bool `json:"has_speaker"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - Isolated bool `json:"isolated"` - KnownCfgversion string `json:"known_cfgversion"` - LastSeen int `json:"last_seen"` + FwCaps int `json:"fw_caps"` + GuestNumSta int `json:"guest-num_sta"` + GuestToken string `json:"guest_token"` + HasEth1 bool `json:"has_eth1"` + HasSpeaker bool `json:"has_speaker"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + Isolated bool `json:"isolated"` + KnownCfgversion string `json:"known_cfgversion"` + LastSeen float64 `json:"last_seen"` LastUplink struct { UplinkMac string `json:"uplink_mac"` UplinkRemotePort int `json:"uplink_remote_port"` @@ -132,28 +137,28 @@ type UAP struct { Is11Ac bool `json:"is_11ac,omitempty"` } `json:"radio_table"` RadioTableStats []struct { - AstBeXmit interface{} `json:"ast_be_xmit"` - AstCst interface{} `json:"ast_cst"` - AstTxto interface{} `json:"ast_txto"` - Channel float64 `json:"channel"` - CuSelfRx float64 `json:"cu_self_rx"` - CuSelfTx float64 `json:"cu_self_tx"` - CuTotal float64 `json:"cu_total"` - Extchannel float64 `json:"extchannel"` - Gain float64 `json:"gain"` - GuestNumSta float64 `json:"guest-num_sta"` - Name string `json:"name"` - NumSta float64 `json:"num_sta"` - Radio string `json:"radio"` - State string `json:"state"` - TxPackets float64 `json:"tx_packets"` - TxPower float64 `json:"tx_power"` - TxRetries float64 `json:"tx_retries"` - UserNumSta float64 `json:"user-num_sta"` + AstBeXmit float64 `json:"ast_be_xmit"` + AstCst float64 `json:"ast_cst"` + AstTxto float64 `json:"ast_txto"` + Channel float64 `json:"channel"` + CuSelfRx float64 `json:"cu_self_rx"` + CuSelfTx float64 `json:"cu_self_tx"` + CuTotal float64 `json:"cu_total"` + Extchannel float64 `json:"extchannel"` + Gain float64 `json:"gain"` + GuestNumSta float64 `json:"guest-num_sta"` + Name string `json:"name"` + NumSta float64 `json:"num_sta"` + Radio string `json:"radio"` + State string `json:"state"` + TxPackets float64 `json:"tx_packets"` + TxPower float64 `json:"tx_power"` + TxRetries float64 `json:"tx_retries"` + UserNumSta float64 `json:"user-num_sta"` } `json:"radio_table_stats"` Rollupgrade bool `json:"rollupgrade"` - RxBytes int `json:"rx_bytes"` - RxBytesD int `json:"rx_bytes-d"` + RxBytes float64 `json:"rx_bytes"` + RxBytesD float64 `json:"rx_bytes-d"` ScanRadioTable []interface{} `json:"scan_radio_table"` Scanning bool `json:"scanning"` Serial string `json:"serial"` @@ -257,20 +262,20 @@ type UAP struct { } `json:"stat"` State int `json:"state"` SysStats struct { - Loadavg1 string `json:"loadavg_1"` - Loadavg15 string `json:"loadavg_15"` - Loadavg5 string `json:"loadavg_5"` - MemBuffer int `json:"mem_buffer"` - MemTotal int `json:"mem_total"` - MemUsed int `json:"mem_used"` + Loadavg1 float64 `json:"loadavg_1,string"` + Loadavg15 float64 `json:"loadavg_15,string"` + Loadavg5 float64 `json:"loadavg_5,string"` + MemBuffer float64 `json:"mem_buffer"` + MemTotal float64 `json:"mem_total"` + MemUsed float64 `json:"mem_used"` } `json:"sys_stats"` SystemStats struct { - CPU string `json:"cpu"` - Mem string `json:"mem"` - Uptime string `json:"uptime"` + CPU float64 `json:"cpu,string"` + Mem float64 `json:"mem,string"` + Uptime float64 `json:"uptime,string"` } `json:"system-stats"` TxBytes float64 `json:"tx_bytes"` - TxBytesD int `json:"tx_bytes-d"` + TxBytesD float64 `json:"tx_bytes-d"` Type string `json:"type"` Upgradable bool `json:"upgradable"` Uplink struct { @@ -284,63 +289,63 @@ type UAP struct { Netmask string `json:"netmask"` NumPort int `json:"num_port"` RxBytes float64 `json:"rx_bytes"` - RxBytesR int `json:"rx_bytes-r"` - RxDropped int `json:"rx_dropped"` - RxErrors int `json:"rx_errors"` - RxMulticast int `json:"rx_multicast"` - RxPackets int `json:"rx_packets"` - Speed int `json:"speed"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` TxBytes float64 `json:"tx_bytes"` - TxBytesR int `json:"tx_bytes-r"` - TxDropped int `json:"tx_dropped"` - TxErrors int `json:"tx_errors"` - TxPackets int `json:"tx_packets"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` Type string `json:"type"` Up bool `json:"up"` UplinkMac string `json:"uplink_mac"` UplinkRemotePort int `json:"uplink_remote_port"` } `json:"uplink"` UplinkTable []interface{} `json:"uplink_table"` - Uptime int `json:"uptime"` + Uptime float64 `json:"uptime"` UserNumSta int `json:"user-num_sta"` VapTable []struct { - ApMac string `json:"ap_mac"` - Bssid string `json:"bssid"` - Ccq int `json:"ccq"` - Channel int `json:"channel"` - Essid string `json:"essid"` - Extchannel int `json:"extchannel"` - ID string `json:"id"` - IsGuest bool `json:"is_guest"` - IsWep bool `json:"is_wep"` - MacFilterRejections int `json:"mac_filter_rejections"` - MapID interface{} `json:"map_id"` - Name string `json:"name"` - NumSta int `json:"num_sta"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RxBytes int `json:"rx_bytes"` - RxCrypts int `json:"rx_crypts"` - RxDropped int `json:"rx_dropped"` - RxErrors int `json:"rx_errors"` - RxFrags int `json:"rx_frags"` - RxNwids int `json:"rx_nwids"` - RxPackets int `json:"rx_packets"` - SiteID string `json:"site_id"` - State string `json:"state"` - T string `json:"t"` - TxBytes int `json:"tx_bytes"` - TxDropped int `json:"tx_dropped"` - TxErrors int `json:"tx_errors"` - TxLatencyAvg float64 `json:"tx_latency_avg"` - TxLatencyMax float64 `json:"tx_latency_max"` - TxLatencyMin float64 `json:"tx_latency_min"` - TxPackets int `json:"tx_packets"` - TxPower int `json:"tx_power"` - TxRetries int `json:"tx_retries"` - Up bool `json:"up"` - Usage string `json:"usage"` - WlanconfID string `json:"wlanconf_id"` + ApMac string `json:"ap_mac"` + Bssid string `json:"bssid"` + Ccq int `json:"ccq"` + Channel int `json:"channel"` + Essid string `json:"essid"` + Extchannel int `json:"extchannel"` + ID string `json:"id"` + IsGuest bool `json:"is_guest"` + IsWep bool `json:"is_wep"` + MacFilterRejections int `json:"mac_filter_rejections"` + MapID string `json:"map_id"` + Name string `json:"name"` + NumSta int `json:"num_sta"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RxBytes float64 `json:"rx_bytes"` + RxCrypts float64 `json:"rx_crypts"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxFrags float64 `json:"rx_frags"` + RxNwids float64 `json:"rx_nwids"` + RxPackets float64 `json:"rx_packets"` + SiteID string `json:"site_id"` + State string `json:"state"` + T string `json:"t"` + TxBytes float64 `json:"tx_bytes"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxLatencyAvg float64 `json:"tx_latency_avg"` + TxLatencyMax float64 `json:"tx_latency_max"` + TxLatencyMin float64 `json:"tx_latency_min"` + TxPackets float64 `json:"tx_packets"` + TxPower int `json:"tx_power"` + TxRetries int `json:"tx_retries"` + Up bool `json:"up"` + Usage string `json:"usage"` + WlanconfID string `json:"wlanconf_id"` } `json:"vap_table"` Version string `json:"version"` VersionIncompatible bool `json:"version_incompatible"` diff --git a/integrations/inputunifi/unidev/unidev.go b/integrations/inputunifi/unidev/unidev.go index 324ab329..7cba8d98 100644 --- a/integrations/inputunifi/unidev/unidev.go +++ b/integrations/inputunifi/unidev/unidev.go @@ -13,9 +13,12 @@ import ( const LoginPath = "/api/login" // Asset provides a common interface to retreive metrics from a device or client. +// It currently only supports InfluxDB, but could be amended to support other +// libraries that have a similar interface. +// This app only uses the .AddPoint/s() methods with the Asset type. type Asset interface { // Point() means this is useful to influxdb.. - Point() (*influx.Point, error) + Points() ([]*influx.Point, error) // Add more methods to achieve more usefulness from this library. } diff --git a/integrations/inputunifi/unidev/unifi.go b/integrations/inputunifi/unidev/unifi.go index 1cdad897..8239e620 100644 --- a/integrations/inputunifi/unidev/unifi.go +++ b/integrations/inputunifi/unidev/unifi.go @@ -21,7 +21,7 @@ const ( ) // GetUnifiClients returns a response full of clients' data from the Unifi Controller. -func (c *AuthedReq) GetUnifiClients() ([]Asset, error) { +func (c *AuthedReq) GetUnifiClients() ([]UCL, error) { var response struct { Clients []UCL `json:"data"` Meta struct { @@ -34,68 +34,103 @@ func (c *AuthedReq) GetUnifiClients() ([]Asset, error) { return nil, err } else if body, err := ioutil.ReadAll(resp.Body); err != nil { return nil, err - } else if err = json.Unmarshal(body, response); err != nil { + } else if err = json.Unmarshal(body, &response); err != nil { return nil, err } else if err = resp.Body.Close(); err != nil { log.Println("resp.Body.Close():", err) // Not fatal? Just log it. } - clients := []Asset{} - for _, r := range response.Clients { - clients = append(clients, r) + return response.Clients, nil +} + +// GetUnifiClientAssets provides an interface to return common asset types. +func (c *AuthedReq) GetUnifiClientAssets() ([]Asset, error) { + clients, err := c.GetUnifiClients() + assets := []Asset{} + if err == nil { + for _, r := range clients { + assets = append(assets, r) + } } - return clients, nil + return assets, err } // GetUnifiDevices returns a response full of devices' data from the Unifi Controller. -func (c *AuthedReq) GetUnifiDevices() ([]Asset, error) { +func (c *AuthedReq) GetUnifiDevices() ([]USG, []USW, []UAP, error) { var parsed struct { Data []json.RawMessage `json:"data"` Meta struct { Rc string `json:"rc"` } `json:"meta"` } - assets := []Asset{} if req, err := c.UniReq(DevicePath, ""); err != nil { - return nil, err + return nil, nil, nil, err } else if resp, err := c.Do(req); err != nil { - return nil, err + return nil, nil, nil, err } else if body, err := ioutil.ReadAll(resp.Body); err != nil { - return nil, err + return nil, nil, nil, err } else if err = json.Unmarshal(body, &parsed); err != nil { - return nil, err + return nil, nil, nil, err } else if err = resp.Body.Close(); err != nil { log.Println("resp.Body.Close():", err) // Not fatal? Just log it. } + var usgs []USG + var usws []USW + var uaps []UAP for _, r := range parsed.Data { + var usg USG + var usw USW + var uap UAP // Unamrshal into a map and check "type" var obj map[string]interface{} if err := json.Unmarshal(r, &obj); err != nil { - return nil, err + return nil, nil, nil, err } - assetType := "" + assetType := "- missing -" if t, ok := obj["type"].(string); ok { assetType = t } + if Debug { + log.Println("Unmarshalling Device Type:", assetType) + } // Unmarshal again into the correct type.. - var asset Asset switch assetType { case "uap": - asset = &UAP{} - case "ugw": - asset = &USG{} + if err := json.Unmarshal(r, &uap); err != nil { + return nil, nil, nil, err + } + uaps = append(uaps, uap) + case "ugw", "usg": // in case they ever fix the name in the api. + if err := json.Unmarshal(r, &usg); err != nil { + return nil, nil, nil, err + } + usgs = append(usgs, usg) case "usw": - asset = &USW{} + if err := json.Unmarshal(r, &usw); err != nil { + return nil, nil, nil, err + } + usws = append(usws, usw) default: log.Println("unknown asset type -", assetType, "- skipping") continue } - if Debug { - log.Println("Unmarshalling", assetType) - } - if err := json.Unmarshal(r, asset); err != nil { - return nil, err - } - assets = append(assets, asset) } - return assets, nil + return usgs, usws, uaps, nil +} + +// GetUnifiDeviceAssets provides an interface to return common asset types. +func (c *AuthedReq) GetUnifiDeviceAssets() ([]Asset, error) { + usgs, usws, uaps, err := c.GetUnifiDevices() + assets := []Asset{} + if err == nil { + for _, r := range usgs { + assets = append(assets, r) + } + for _, r := range usws { + assets = append(assets, r) + } + for _, r := range uaps { + assets = append(assets, r) + } + } + return assets, err } diff --git a/integrations/inputunifi/unidev/usg.go b/integrations/inputunifi/unidev/usg.go index dbad1a6c..f904f37c 100644 --- a/integrations/inputunifi/unidev/usg.go +++ b/integrations/inputunifi/unidev/usg.go @@ -7,8 +7,9 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Point generates a device's datapoint for InfluxDB. -func (u USG) Point() (*influx.Point, error) { +// Points generates a device's datapoints for InfluxDB. +func (u USG) Points() ([]*influx.Point, error) { + var points []*influx.Point tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -117,5 +118,9 @@ func (u USG) Point() (*influx.Point, error) { "wan-tx_bytes": u.Stat.WanTxBytes, "wan-tx_packets": u.Stat.WanTxPackets, } - return influx.NewPoint("usg", tags, fields, time.Now()) + pt, err := influx.NewPoint("usg", tags, fields, time.Now()) + if err == nil { + points = append(points, pt) + } + return points, err } diff --git a/integrations/inputunifi/unidev/usw.go b/integrations/inputunifi/unidev/usw.go index 215bbc43..bbcb1dc1 100644 --- a/integrations/inputunifi/unidev/usw.go +++ b/integrations/inputunifi/unidev/usw.go @@ -7,8 +7,9 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Point generates a device's datapoint for InfluxDB. -func (u USW) Point() (*influx.Point, error) { +// Points generates a device's datapoints for InfluxDB. +func (u USW) Points() ([]*influx.Point, error) { + var points []*influx.Point tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -109,5 +110,9 @@ func (u USW) Point() (*influx.Point, error) { "stat_tx_retries": u.Stat.TxRetries, // Add the port stats too. } - return influx.NewPoint("usw", tags, fields, time.Now()) + pt, err := influx.NewPoint("usw", tags, fields, time.Now()) + if err == nil { + points = append(points, pt) + } + return points, err }