- 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>
Fixes#425
When polling multiple controllers, if one controller was down or
unreachable, unpoller would stop collecting data from ALL controllers.
This caused complete data loss across all sites when just one was down.
Root Cause:
Both Metrics() and Events() methods would immediately return an error
when any controller failed, skipping all remaining controllers in the
loop.
Changes:
- Log errors from failed controllers but continue to next controller
- Track collection errors separately from successful data collection
- Only return error if ALL controllers failed and no data was collected
- Return success if at least one controller provided data
This allows unpoller to continue monitoring healthy controllers even
when some are temporarily unreachable due to network issues, timeouts,
or maintenance.
Example behavior:
- Controller 1: Down (timeout) - logs error, continues
- Controller 2: Up - collects data successfully
- Controller 3: Up - collects data successfully
- Result: Returns data from controllers 2 and 3
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixes#904
When a poll fails (typically with 401 Unauthorized after ~2 hour token
expiration), the code would re-authenticate but then return the original
poll error without retrying. This caused a one-minute data gap every
2 hours.
Changes:
- After successful re-authentication, retry the poll operation
- Add 500ms delay before retry to allow controller to process new auth
- Rename error variable to avoid shadowing during re-auth attempt
This ensures that transient authentication failures during the re-auth
window don't cause data gaps.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Ports providing PoE power are no longer considered "dead" even when
disabled or down. This allows users to collect PoE metrics from ports
that are disabled for security reasons but still providing power.
Fixes#910
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds log_unknown_types config option (default: false) to control logging
of unknown UniFi device types. When disabled (default), unknown devices
are silently ignored to reduce log volume. When enabled, they are logged
as DEBUG messages instead of ERROR. Addresses issue #912.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Update go.mod to use unifi library v5.6.0 (includes remote API support)
- Remove temporary replace directive now that v5.6.0 is published
- Fix empty-block linter errors in input.go by removing empty if blocks