Adds metrics export for UDB devices (UDB-Switch, UDB-Pro, UDB-Pro-Sector)
to all output backends. UDB-Switch is a hybrid device combining PoE switch
ports with WiFi 7 wireless bridge capability (5GHz + 6GHz radios).
- pkg/promunifi/udb.go: Prometheus metrics exporter for UDB
- pkg/influxunifi/udb.go: InfluxDB batch exporter for UDB
- pkg/datadogunifi/udb.go: Datadog batch exporter for UDB
- Wire UDB into switchExport in all three output plugins
- Add UDB to inputunifi device collection and site name override
- Update integration test expectations for InfluxDB and Datadog
- Fix addUBB() bug: was incorrectly incrementing UCI counter
Resolves#947
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* Fix panic when remote discovery fails and no controllers are configured
Call setDefaults(&u.Default) before logController(&u.Default) when
len(u.Controllers) == 0 so HashPII, DropPII, etc. are initialized
and logController does not dereference nil pointers.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore: trigger CI re-run
Co-authored-by: Cursor <cursoragent@cursor.com>
* ci: use golangci-lint v2.9 for Go 1.26-compatible deps
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(influxunifi): use CelsiusSafe() for temp fields to fix InfluxDB type conflict
Write temp_* fields as float64 instead of int64 so InfluxDB does not
report 'field type conflict' when the measurement already has float.
Requires github.com/unpoller/unifi/v5 with CelsiusSafe() (unpoller/unifi#195).
Fixes#944.
Co-authored-by: Cursor <cursoragent@cursor.com>
* deps: unifi v5.17.0; nil guards and 429 retry (unpoller#943)
- Bump github.com/unpoller/unifi/v5 to v5.17.0 (CelsiusSafe, ErrNilUnifi, RateLimitError)
- inputunifi: guard pollController for nil c.Unifi; controllerID(c) in formatSites/Clients/Devices
- inputunifi: getUnifi retry with backoff on 429 (up to 5 attempts, Retry-After or exponential backoff)
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(influxunifi): expect temp_* as float after CelsiusSafe() (fix#944)
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add Sysinfo collection from stat/sysinfo endpoint
- Export controller_info, uptime, update_available, data retention, ports
- Hostname fallback: name, then site_name when API omits hostname
- Apply site name override to Sysinfo for remote/cloud
- Add Discover/Discoverer for endpoint discovery
- Require unpoller/unifi v5.15.0
Co-authored-by: Cursor <cursoragent@cursor.com>
Restores the browser-based endpoint discovery script that was
mistakenly removed in the Go --discover PR. Optional: use this for
broader discovery (XHR capture) or unpoller --discover for known endpoints.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Require github.com/unpoller/unifi/v5 v5.13.0 (DiscoverEndpoints in release)
- Remove go.mod replace and workflow steps that cloned unifi for CI
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add --discover and --discover-output to unpoller; uses first unifi
controller from config to probe known API endpoints and write a
shareable markdown report.
- Add Discoverer interface and RunDiscover(); inputunifi implements
Discoverer via unifi.DiscoverEndpoints.
- Remove tools/endpoint-discovery/ (Python/Playwright).
- Add docs/PR_936_REPLACEMENT.md. .gitignore: test config and report.
Requires unpoller/unifi with DiscoverEndpoints (replace in go.mod until
unifi release).
- Python script (Playwright) that logs in to UniFi controller and captures
XHR/fetch requests to /api and /proxy/ endpoints
- Writes API_ENDPOINTS_HEADLESS_<date>.md in tool directory (easy for users)
- Helps debug 404s (e.g. device-tags #935): users can run and share output
- Optional, read-only; not required for building or running unpoller
Add comprehensive WAN metrics support to InfluxDB and Datadog exporters:
InfluxDB Metrics (measurement: wan):
- Configuration: failover_priority, load_balance_weight, provider_download_kbps,
provider_upload_kbps, smartq_enabled, magic_enabled, vlan_enabled
- Statistics: uptime_percentage, peak_download_percent, peak_upload_percent,
max_rx_bytes_rate, max_tx_bytes_rate
- Service Provider: service_provider_asn
- Metadata: creation_timestamp
Tags: wan_id, wan_name, wan_networkgroup, wan_type, wan_load_balance_type,
isp_name, isp_city
Datadog Metrics (namespace: unpoller.wan.*):
- Same metrics as InfluxDB with gauge type
- All metrics tagged with WAN and ISP information
Changes:
- pkg/influxunifi/wan.go: New WAN exporter for InfluxDB
- pkg/influxunifi/influxdb.go: Add WAN to loopPoints and switchExport
- pkg/datadogunifi/wan.go: New WAN exporter for Datadog
- pkg/datadogunifi/datadog.go: Add WAN to loopPoints and switchExport
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add 'tag' label to all device metric descriptors
- Update exportWithTags helper to create separate metric series per tag
- Update all device export functions (UAP, USW, UDM, USG, UXG, PDU, UBB, UCI) to include tags
- Update all label arrays (VAP, Radio, Port, etc.) to include tag label
- Devices with multiple tags create multiple metric series (one per tag)
- Devices without tags export with tag=""
Requires unpoller/unifi#92
- Add .cursorrules for Cursor AI
- Add CLAUDE.md for Claude Code
- Add AGENTS.md for universal AI agent context
- Add .github/copilot-instructions.md for GitHub Copilot
These files provide comprehensive context about the UnPoller project
architecture, coding standards, and development patterns to help AI
coding assistants understand and work with the codebase effectively.
Updated the install section in the brews configuration to use the
new Homebrew formula syntax for directory creation.
Changes:
- Changed `etc.mkdir "unpoller"` to `(etc/"unpoller").mkpath`
The old syntax was causing errors with newer Homebrew versions:
TypeError: no implicit conversion of String into Integer
This fix ensures compatibility with Homebrew 4.3+ while maintaining
backward compatibility with older versions.
Fixes#742
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added device name enrichment to alarms so that Loki logs show
human-readable device names instead of just MAC addresses.
Changes:
- Modified collectAlarms to fetch devices and build MAC-to-name lookup
- Added extractDeviceNameFromAlarm helper to extract MAC addresses from
alarm messages and lookup corresponding device names
- Device names are extracted from messages like "AP[fc:ec:da:89:a6:91]"
or from SrcMAC/DstMAC fields
- Added go.mod replace directive to use local unifi library with new
DeviceName field
The device_name field will now be included in the JSON output sent to
Loki, making it easier to identify which device triggered an alarm.
Fixes#415
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixes#417
UniFi controllers populate RemoteUserNumActive for VPN connections but
leave NumUser at 0 for the VPN subsystem. This caused dashboard queries
looking for num_user in the VPN subsystem to always show 0 active users,
even when VPN connections were active.
Root Cause:
For most subsystems (wlan, lan, www), the controller populates NumUser
directly. However, for the VPN subsystem, the controller uses the
RemoteUserNumActive field instead, leaving NumUser at 0.
The Prometheus exporter had special handling for VPN (lines 148-156 in
pkg/promunifi/site.go) and exported RemoteUserNumActive, but did not
export NumUser. The InfluxDB and Datadog exporters exported all fields
for all subsystems without special handling, resulting in num_user
always being 0 for VPN.
Existing Grafana dashboards query:
SELECT "num_user" FROM "subsystems" WHERE subsystem='vpn'
This always returned 0 even with active VPN users.
Solution:
For all three exporters (InfluxDB, Datadog, Prometheus), when the
subsystem is 'vpn' and NumUser is 0 but RemoteUserNumActive has a
value, populate num_user with RemoteUserNumActive.
Changes:
- pkg/influxunifi/site.go: Add VPN-specific num_user fallback logic
- pkg/datadogunifi/site.go: Add VPN-specific num_user fallback logic
- pkg/promunifi/site.go: Add NumUser metric to VPN case with fallback
This maintains backward compatibility - existing queries for num_user
will now work correctly, and the remote_user_num_active field is still
available for those who updated their dashboards.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>