100 Commits
Author SHA1 Message Date
Cody LeeandCursor c742df91e8 chore(deps): bump github.com/unpoller/unifi/v6 to v6.2.0
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 11:28:06 -05:00
Cody LeeandCursor 912ea91ac0 feat(protect): export air quality readings when present
Prefer a known stats channel and fall back to airQuality for temperature
and humidity. Omit channels whose status is unknown, and add the
particulate and gas series only when the controller includes them.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 09:46:13 -05:00
Cody LeeandCursor 45d60f7824 chore(deps): bump github.com/unpoller/unifi/v6 to v6.1.3
Picks up JSON-encoded login credentials so passwords containing quotes authenticate.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 09:09:40 -05:00
Cody LeeandCursor 122226bc4b fix: honor scrape-cache disable and export locate-mode devices
interval=0 now turns off the Prometheus scrape cache as PR #1014
documented, and sub-15s intervals warn instead of clamping (#1083).
Adopted devices stay in Prometheus, Influx, OTel, and Datadog exports
while locate/identify is on (#1075).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-11 08:51:32 -05:00
Cody LeeandCursor 8a78355e12 fix: use external test package for remote site helpers
golangci-lint testpackage requires tests in inputunifi_test.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-31 14:01:11 -04:00
Cody LeeandCursor e4c2934bdc fix: poll remote multi-site controllers by internalReference
Remote discovery stored Integration display names, so extra sites were dropped when checkSites compared them to legacy Site.Name. Use unifi v6.1.0 InternalReference instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-31 13:54:21 -04:00
Cody LeeandCursor ce4cfe3971 fix: respect configured default_site_name_override in remote mode
Remote API discovery was unconditionally overwriting default_site_name_override
with the console name for Cloud Gateways. Only apply the console name fallback
when the user has not already configured an override.

Fixes #1057

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 16:57:41 -05:00
Cody LeeandCursor 9bc7f2c5bf Complete InfluxDB v3 rollout: tests, docs, and docker example.
Add v3 integration and version tests, migration notes, InfluxDB 3 docker-compose stack, and README updates to finish the remaining plan phases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 16:24:09 -05:00
Cody LeeandCursor 5e31d2f252 Add InfluxDB v3 support and fix tag/field schema collisions.
Introduce explicit version selection with the influxdb3-go client alongside existing v1 and v2 paths, and resolve overlapping tag/field keys required for InfluxDB 3 write validation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 15:49:59 -05:00
Cody Lee 3df98dcc45 Merge pull request #1063 from unpoller/fix/release-makefile-go-install
fix: use go install for release build tool dependencies
2026-08-27 13:00:54 -05:00
Cody LeeandCursor de8a6e46f1 fix: use go install for release build tool dependencies
GoReleaser's make man hook failed because go get no longer works
outside a module. Replace deprecated go get with go install for
md2roff and rsrc.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 12:58:36 -05:00
Cody LeeandCursor b753232e6a ci: bump golangci-lint to v2.13 for Go 1.27 deps
golangci-lint v2.9 is built with Go 1.26 and panics when type-checking
dependencies that include go1.27-only source files.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 12:09:13 -05:00
Cody Lee 65ad210f20 feat: add UniFi Protect device metrics (closes #1015)
Collects Protect device data (sensors, cameras, lights, bridges, link
stations, NVR) via the official Integration API and exports it through
Prometheus, InfluxDB, and DataDog. Opt-in via save_protect_devices,
gated by protect_api_key.

Bumps github.com/unpoller/unifi to v6, which added the Protect API
client (breaking change: FlexInt/FlexBool/FlexFloat replace nullable
pointers).
2026-08-19 15:14:43 -05:00
Cody LeeandClaude Opus 5 01ac7ca2b7 refactor(unas): replace disable flag with enable, defaulting to off
`disable = false` is a double negative, and a bool named disable cannot
express opt-in anyway: it zero-values to false, so the flag was inert and
opt-in rested entirely on the device list being empty.

`enable` defaults to false and is now the real gate -- Initialize, Metrics
and DebugInput all return early unless it is set. The two existing guards
remain: an empty device list is still a no-op, and no default URL is ever
synthesized.

Configuring devices while enable is false is always a mistake, so that
combination logs one error instead of silently collecting nothing.

Adds binding tests for the flag across toml, json, yaml and UP_UNAS_ENABLE
(the env name derives from the xml tag, not the json one), plus a test that
all three shipped examples default to off. Both were verified by mutation:
breaking a struct tag or flipping an example fails the suite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 09:34:02 -05:00
Cody LeeandClaude Opus 5 3d178bed8d fix: AppendMetrics silently dropped SpeedTests and the batch timestamp
AppendMetrics merges every slice field on Metrics except SpeedTests, so
speed test results were discarded on the way from the input to the
outputs. Both call sites start from a non-nil &Metrics{}, so this hit
every user on every poll: inputunifi collected the results, and the
export code in promunifi, influxunifi and datadogunifi was dead.

TS was dropped the same way. The aggregate starts bare and nothing
restored the timestamp, so it stayed zero -- and influxunifi's collect()
stamps any point that carries no timestamp of its own with the
aggregate's, which meant the zero time. Both Influx clients omit a zero
timestamp and let the server assign one, so the damage was limited to
points being stamped on arrival rather than at poll time, but it made
the fallback path meaningless. First writer wins: the earliest input's
timestamp is the one that describes the batch.

The failure mode here is what makes it worth guarding rather than just
patching. A new metric family needs a field on Metrics and an append
line in AppendMetrics, and omitting the second loses every metric in
that family with no error, no log line, and a passing build.
TestAppendMetricsCoversEverySliceField walks the struct by reflection
and fails naming any slice field that is not merged, so a new field is
covered the moment it is declared rather than when someone notices the
graphs are empty.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 07:59:04 -05:00
Cody LeeandClaude Opus 5 d5dfc771d5 feat: add opt-in UNAS Pro support (closes #785)
Adds a new `unas` input plugin that polls UNAS Pro storage consoles and
exports console health, storage pools, disks and shares to Prometheus,
InfluxDB and DataDog.

UNAS is a separate plugin rather than a device type inside inputunifi
because a storage-only console has no Network application: it cannot
answer /status, has no sites, and shares none of the UniFi device schema.

The plugin is opt-in and inert until an operator names a console. Opt-in
is expressed as "no devices configured" rather than a `disable` flag,
because a bool named `disable` zero-values to false and so cannot make a
plugin default-off. Initialize returns silently on an empty device list
and, unlike inputunifi, nothing synthesizes a default URL.

Two behaviours are worth calling out for reviewers:

  - Metrics returns (metrics, nil) whenever any console was collected.
    poller.collectMetrics uses `if err != nil {} else if metric != nil`,
    so returning both would discard every healthy console because one
    failed. Only a total failure returns an error.

  - Re-auth fires on total failure, not on a 401. A mid-session 401 from
    GetData surfaces as ErrInvalidStatusCode, not ErrAuthenticationFailed,
    so there is no sentinel to match on. Session expiry fails all four
    endpoints at once, which is exactly the total-failure case.

Prometheus metrics use the `unifi_unas_` prefix, which diverges from the
`unas_` prefix used by the reference implementation; dashboards built
against that will need query edits.

Requires unifi/v5 v5.31.0 for the UNAS client and structs.

Credit to alexgreenbank/unaspoller for mapping the endpoints.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 07:52:37 -05:00
Cody Lee 3dee271de0 inputunifi: skip alarms endpoint on 400 api.err.InvalidObject
Some Network 10.x+ controllers (UniFi OS, Network 10.5.67 confirmed)
return HTTP 400 api.err.InvalidObject from list/alarm instead of a 404
when the endpoint is gone, so collectAlarms fell through the existing
ErrEndpointNotFound skip and logged a real ERROR on every poll.

Fixes #1050
2026-08-18 09:41:03 -05:00
Cody LeeandClaude Sonnet 5 58294420f8 promunifi: add state label to wan_interface_state metric
BACKUP and DISCONNECTED WAN interfaces both reported as 0, making
them indistinguishable in Prometheus (fixes #1045). InfluxDB and
DataDog already expose the raw state; this brings Prometheus in
line by adding a state label alongside the existing 1/0 gauge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 09:32:14 -05:00
Cody Lee 12073ba523 Fix nil-pointer panic in collectEvents for disabled input plugins
InputUnifi.Events returns (nil, nil) when disabled, but collectEvents
dereferenced e.Logs unconditionally after a successful (err == nil)
call, crashing the poller. Same crash class as #1030, found while
verifying the recover-based fix.
2026-08-18 08:36:50 -05:00
Cody LeeandClaude Sonnet 5 8063f06777 Extract recover-and-convert-panic helpers for input plugin calls
Replaces the sent-bool guard duplicated across three goroutines with a
small per-call helper (recoverInitialize/recoverEvents/recoverMetrics)
that wraps the plugin call and converts a panic into a returned error.
Each goroutine then always sends its result exactly once, so there's
no risk of a double-send deadlocking the collector.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 08:31:34 -05:00
Cody LeeandClaude Sonnet 5 cc60dc9239 Recover input plugin panics in poller goroutines (fixes #1030)
Metrics/Events/Initialize each fan out to input plugins in their own
goroutines with no recover(), so a panic there (e.g. a UniFi
controller returning an unexpected Site Speed Test aggregated-dashboard
payload) crashes the whole process with exit code 2. Because the
panic occurs in a child goroutine, promunifi's existing safeRefresh
recover() in the caller's goroutine never sees it, which is why the
crash survived the earlier robustness work. This converts a panicking
input into a logged/returned error so polling continues instead of
crashing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 15:36:37 -05:00
Cody Lee aa37353e3d fix: explicitly dispatch release workflow after creating a tag
Tags pushed with the default GITHUB_TOKEN don't trigger other
workflows' push events, so release.yml never ran after tag.yml
created a new tag. Add workflow_dispatch to release.yml and have
tag.yml call `gh workflow run release.yml --ref <tag>` right after
pushing the tag.
2026-07-20 18:22:40 -05:00
Cody LeeandClaude Sonnet 5 d4c8bcab42 feat: add manual tag-creation workflow using git-semver
Adds a workflow_dispatch workflow that lets maintainers bump the
patch, minor (default), or major version using mdomke/git-semver,
then tags and pushes the result to trigger the existing release
workflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 10:42:39 -05:00
Cody LeeandClaude Opus 4.7 dabfeffe66 fix(prometheus): serve scrapes from cached background poll (#1013)
Decouples Prometheus scrape cadence from upstream UniFi API calls so a
429 backoff loop on the controller side no longer stalls /metrics. The
output plugin now owns a 60s background poller (configurable) whose
result is served from an in-memory cache. Concurrent /scrape requests
for the same target are coalesced via singleflight to prevent a noisy
scraper from multiplying upstream load.

Adds two new metrics so operators can detect cache staleness and
refresh failures independently:
- unpoller_prometheus_cache_age_seconds
- unpoller_prometheus_refresh_failures_total

Background goroutine recovers from panics so a malformed input payload
no longer silently kills refreshes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:43:44 -05:00
Cody LeeandClaude Opus 4.7 0b83c6ad19 fix(release): drop universal_binaries so homebrew_casks can find macOS archives
The v3.1.2 release failed because homebrew_casks filters archives by
goarch=[amd64 arm64], but universal_binaries.replace=true collapses the
darwin amd64+arm64 builds into a single darwin/all archive — which the
cask filter rejects.

Drop the universal_binaries block. The unpoller-mac build still produces
darwin amd64 and darwin arm64 separately, and the cask resolves them
into per-arch on_intel/on_arm blocks. Net effect on release artifacts:
the single universal macOS archive is replaced by two per-arch archives.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:55:18 -05:00
Cody LeeandClaude Opus 4.7 630613625e chore(release): migrate goreleaser config off deprecated fields
- Rename archives.builds/nfpms.builds to ids; convert format/format_overrides.format to formats arrays.
- Collapse three dockers + six docker_manifests entries into one dockers_v2 block; update Dockerfile to use $TARGETPLATFORM for multi-arch buildx.
- Migrate brews to homebrew_casks (binary->binaries, url_template->url.template, install/post_install->hooks.post.install). Cask is macOS-only, so ids is reduced to unpoller-mac.

Per-arch image tags (e.g. :latest-amd64, :latest-arm64v8, :latest-armv7) are no longer published; only the multi-arch manifest tags (latest, v{Major}, full version) remain. Linuxbrew install path is dropped; Linux users should use the deb/rpm or Docker image.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:37:39 -05:00
Cody Lee 84a14edb64 chore(deps): upgrade unifi to v5.28.0
Picks up the gzip decompression fix for the Site Manager remote API
(unpoller/unifi#220), which restores remote-API discovery for Official
UniFi Cloud Hosted consoles whose responses are gzip-compressed but
served without a Content-Encoding header.

Closes #997
2026-05-09 09:57:52 -05:00
Cody LeeandClaude Opus 4.7 679faceafd chore(deps): upgrade unifi to v5.27.0 and refresh golang.org/x deps
Bumps github.com/unpoller/unifi/v5 from v5.26.0 to v5.27.0 along with
golang.org/x/crypto, term, sys, and text to their latest releases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:37:07 -05:00
Cody LeeandClaude Opus 4.7 fef3ae74f2 test: update integration expectations for new UAP uplink fields
Influx and Datadog integration tests assert that the captured field/gauge
sets exactly match the YAML. Add the new uap uplink_* entries so the
TestInfluxV1Integration and Datadog integration tests stay green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:27:30 -05:00
Cody LeeandClaude Opus 4.7 b1a8d60460 feat: add UAP uplink metrics and Prometheus parity for USW/UBB/UDB (closes #988)
Exposes the uplink medium (wire vs wireless) and link speed for UniFi access
points so users can detect when an AP downgrades from gigabit to fast ethernet,
which was the original ask in #988. UAPs previously had zero uplink coverage
in any output plugin; now influxunifi, datadogunifi, and promunifi all report
uplink_type, uplink_speed, uplink_max_speed, and related fields.

Also brings Prometheus to parity with Influx/Datadog by emitting uplink
metrics for USW, UBB, and UDB devices (previously only USG/UDM/UXG had them
in promunifi). A new exportDeviceUplink helper in promunifi/usg.go reuses
the existing unpoller_device_uplink_* descriptors to avoid descriptor
collision (per c48b9917).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 09:23:41 -05:00
Cody LeeandClaude Opus 4.7 511c524e6e feat(influxunifi): add global tags applied to every measurement
Closes #1001. Mirrors the DataDog plugin's global tags feature for
InfluxDB. Per-metric tags take precedence on key collision so
site/device identifiers can never be overwritten by a misconfigured
global. Configurable via TOML/JSON/YAML under influxdb.tags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 08:59:16 -05:00
Cody LeeandClaude Opus 4.7 8697e455f6 fix: reference up.conf.example in brew install steps (#995)
The Homebrew formula's install/post_install blocks referenced
examples/up.conf, but the source tarball ships examples/up.conf.example,
causing brew install to fail with ENOENT. Update both references to use
the correct filename, matching how the rest of .goreleaser.yaml already
sources this file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:59:02 -05:00
Cody LeeandClaude Opus 4.7 d2948b8bd0 feat: upgrade unifi to v5.26.0 and add Integration/v1 + new legacy metrics
Adds 21 new data types from unifi v5.26.0 across all metric output plugins
(InfluxDB, Prometheus, DataDog). Per-site Integration/v1 calls are gated on
API key configuration and only run for user-configured sites; ErrEndpointNotFound
is handled gracefully so older firmware continues to work without log spam.

Also migrates events collection (collectAlarms, collectAnomalies, collectEvents,
collectIDs, collectProtectLogs) to handle Network 10.x+ endpoint removals via
ErrEndpointNotFound, with debug-level logging to avoid per-poll noise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:45:47 -05:00
Cody Lee 5e4a6cbef3 upgrade unifi 2026-01-31 10:19:38 -06:00
Cody Lee a94b530adf bump unifi version 2026-01-30 11:48:00 -06:00
Cody Lee 5e68016564 fix client side log error 2026-01-27 21:14:21 -06:00
Cody LeeandClaude Sonnet 4.5 3f60654a2a Fix Homebrew formula for newer Homebrew versions
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>
2026-01-25 12:29:13 -06:00
Cody Lee 0fc8b6f008 use new unifi version 2026-01-25 12:21:16 -06:00
Cody LeeandClaude Sonnet 4.5 97d3f995b1 Enrich alarms with device names for Loki logs
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>
2026-01-25 12:17:12 -06:00
Cody LeeandClaude Sonnet 4.5 ae1ab40386 Populate num_user field for VPN subsystem metrics
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>
2026-01-25 12:09:01 -06:00
Cody LeeandClaude Sonnet 4.5 f51a0c7202 Allow polling to continue when individual controllers fail
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>
2026-01-25 12:01:37 -06:00
Cody LeeandClaude Sonnet 4.5 a1a8963159 Fix authentication retry to prevent data gaps after re-auth
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>
2026-01-25 11:53:31 -06:00
Cody LeeandClaude Sonnet 4.5 9e3debd58a Allow PoE-providing ports to be scraped even when disabled
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>
2026-01-25 11:31:39 -06:00
Cody LeeandClaude Sonnet 4.5 07781214c3 Add config option to suppress unknown device type messages
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>
2026-01-25 11:24:33 -06:00
Cody LeeandClaude Sonnet 4.5 a00aeb2eb5 Add byte counters for InfluxDB and Prometheus outputs (issue #350)
Track the number of bytes written per request for both InfluxDB and Prometheus outputs.

InfluxDB:
- Added bytesT counter constant
- Implemented calculateMetricBytes() to estimate line protocol size
- Updated batchV1() and batchV2() to count bytes per point
- Updated log output to display bytes written

Prometheus:
- Added Bytes field to Report struct
- Updated export() to calculate approximate metric byte size
- Updated log output to display bytes written

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 10:55:33 -06:00
Cody LeeandClaude Sonnet 4.5 0ffe6152ab Fix multi-WAN speed test reporting (issue #841)
Speed tests were not being reported correctly for multi-WAN setups
because the device-level speedtest-status field was returning zeros.
The data has moved to a new aggregated dashboard API endpoint.

Changes:
- Add GetSpeedTests() and GetSiteSpeedTests() methods to fetch from
  /v2/api/site/{site}/aggregated-dashboard endpoint
- Create SpeedTestResult data structures to capture per-WAN metrics
- Update Prometheus exporter with new speedtest_* metrics per interface
- Update InfluxDB exporter to write speedtest measurements per WAN
- Update Datadog exporter with unifi.speedtest.* metrics per WAN
- Update metrics collection to include speed test data for all sites

Metrics now include labels/tags for:
- wan_interface: Physical interface (eth8, eth9, etc.)
- wan_group: Logical WAN name (WAN, WAN2, etc.)
- site_name: Site identifier
- source: Controller URL

Gracefully handles older controllers without the new API endpoint.

Fixes #841

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 16:46:14 -06:00
Cody LeeandClaude Sonnet 4.5 8000597fce Refactor Prometheus UBB label construction to use append
Replace manual array indexing (labels[1], labels[2], labels[3]) with
cleaner append syntax using slice notation (labels[1:]...).

This makes the code more maintainable and idiomatic Go.

Before: labelTotal := []string{"total", labels[1], labels[2], labels[3]}
After:  labelTotal := append([]string{"total"}, labels[1:]...)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 11:12:00 -06:00
Cody LeeandClaude Sonnet 4.5 c61d2651a2 Enhance InfluxDB and Datadog UBB outputs with comprehensive metrics
This change significantly expands the metrics exported for UBB devices
to InfluxDB and Datadog, matching the comprehensive coverage added to
the Prometheus output.

Changes to InfluxDB (pkg/influxunifi/ubb.go):
- Added batchUBBstats() to export comprehensive statistics separated
  by radio (total, wifi0, terra2, user-wifi0, user-terra2)
- Added VAP table export via processVAPTable()
- Added Radio table export via processRadTable()
- Added P2P stats (rx_rate, tx_rate, throughput)
- Added link quality metrics (link_quality, link_quality_current,
  link_capacity)
- Comprehensive stats exported to new "ubb_stats" table with full
  breakdown of traffic per radio

Changes to Datadog (pkg/datadogunifi/ubb.go):
- Added batchUBBstats() to export comprehensive statistics separated
  by radio (total, wifi0, terra2, user-wifi0, user-terra2)
- Added VAP table export via processVAPTable()
- Added Radio table export via processRadTable()
- Added P2P stats (rx_rate, tx_rate, throughput)
- Added link quality metrics (link_quality, link_quality_current,
  link_capacity)
- Comprehensive stats exported with namespace "ubb.stats"

All implementations now fully support:
- 5GHz radio (wifi0) metrics
- 60GHz radio (terra2/ad) metrics - Full 802.11ad support!
- Per-radio RX/TX packets, bytes, errors, dropped, retries
- User-specific metrics for each radio
- Interface-specific metrics (ath0 for 5GHz, wlan0 for 60GHz)
- Point-to-point link statistics and quality metrics

Fixes: #409

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 11:04:35 -06:00
Cody Lee ab2c677f30 uses new unifi lib 2025-12-09 10:48:45 -06:00
Cody LeeandClaude Sonnet 4.5 6a135c60a7 Enhance UBB device support with comprehensive Prometheus metrics
This change significantly improves UniFi Building Bridge (UBB) device
support by adding comprehensive Prometheus metric exports.

UBB devices are point-to-point wireless bridges with dual radios:
- wifi0: 5GHz radio (802.11ac)
- terra2/wlan0/ad: 60GHz radio (802.11ad - Terragraph/WiGig)

Changes:
- Added exportUBBstats() to export UBB-specific statistics separated
  by radio (total, wifi0, terra2, user-wifi0, user-terra2)
- Added exportP2Pstats() to export point-to-point link metrics
  (rx_rate, tx_rate, throughput)
- Added VAP (Virtual Access Point) table export via existing exportVAPtable()
- Added Radio table export via existing exportRADtable() to capture
  60GHz radio metrics
- Added link quality metrics (link_quality, link_quality_current,
  link_capacity)
- Added comprehensive comments documenting UBB device characteristics
  and 60GHz band support

The implementation reuses existing UAP metric descriptors where
appropriate, allowing UBB metrics to be collected alongside UAP metrics
in Prometheus with proper labeling for differentiation.

Requires: unpoller/unifi#169 (UBB type definition fixes)
Fixes: #409

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 10:20:23 -06:00
Cody LeeandClaude Sonnet 4.5 832334655c Fix health check port binding conflict (issue #892)
The Docker health check was attempting to bind to ports already in use by
the running application, causing "address already in use" errors. This fix
adds a health check mode that skips network binding operations while still
validating output configuration (listen addresses, paths, etc.).

Changes:
- Add health check mode flag in pkg/poller/outputs.go
- Update prometheus and webserver DebugOutput() to skip port binding in health check mode
- Maintain full configuration validation without network conflicts

Fixes #892

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 08:11:21 -06:00
Cody Lee f0ed2954b8 bump unifi to v5.2.0 2025-12-08 13:55:10 -06:00
Cody LeeandClaude Sonnet 4.5 b960695f3b Add Docker health check support
Implements #406 by adding a --health CLI flag and HEALTHCHECK instruction
to the Dockerfile. This allows Docker and container orchestration platforms
to monitor container health automatically.

Changes:
- Added --health flag that validates configuration and plugin connectivity
- Implemented HealthCheck() method in pkg/poller/commands.go
- Updated Dockerfile with HEALTHCHECK instruction (30s interval, 10s timeout)
- Updated MANUAL.md with --health flag documentation
- Added health check documentation to Docker README
- Added comments to docker-compose examples about built-in health check

The health check:
- Validates configuration file is found and parseable
- Ensures at least one input and one enabled output are configured
- Performs basic validation on enabled outputs
- Returns exit code 0 (healthy) or 1 (unhealthy)
- Runs silently for Docker compatibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-08 13:09:10 -06:00
Cody Lee 7e2fb0135e fix dd client interface change, update deprecated context lib in influxdb 2025-12-03 11:51:40 -06:00
Cody Lee c778ddea43 fix verify 2025-12-03 11:42:47 -06:00
Cody Lee 6f4384c18d fix linting 2025-12-03 11:40:21 -06:00
Cody Lee 944ce85477 make dependabot group updates 2025-11-04 12:31:04 -06:00
Cody Lee b37317a88d bump unifi version to 5.1.1 2025-08-20 11:40:37 -05:00
Cody Lee c3126d27e3 interface change updates 2025-08-20 11:36:29 -05:00
Cody Lee 4040203ff8 fix homebrew formula again, other two vars 2025-04-30 16:24:41 -05:00
Cody Lee 0ae46889d8 fix homebrew formula 2025-04-30 16:20:43 -05:00
Cody Lee 4b19b873ab address issue 2025-04-04 08:33:58 -05:00
Cody Lee 5122360018 migrate golangci-lint config 2025-04-04 08:32:42 -05:00
Cody Lee 0790aeda22 update toolchain 2025-04-04 08:31:46 -05:00
Cody Lee e53b8d5e5a update all deps, update golangci-lint 2025-04-04 08:30:22 -05:00
Cody Lee 6d4065113f fixes metrics prefix names for ubb and uci devices 2025-01-15 15:50:47 -06:00
Cody Lee e946f246eb update example conf file 2025-01-10 15:25:16 -06:00
Cody Lee cba1111f29 add support for api-key auth 2025-01-10 15:19:30 -06:00
Cody Lee ed3c222992 oops fix dd expectation 2025-01-02 12:51:37 -06:00
Cody Lee 9d1f8606df update expectations 2025-01-02 12:46:17 -06:00
Cody Lee 4da299ff46 adds device uplink stats for issue #585 2025-01-02 12:41:34 -06:00
Cody Lee 1b120a258a tests pass locally; 2025-01-02 11:33:28 -06:00
Cody Lee 3602d8cc8f adds in UBB & UCI support 2025-01-02 08:57:47 -06:00
Cody Lee a30c82093d add ubb and uci initial support 2024-12-31 16:26:54 -06:00
Cody Lee ebdb224d95 fixes mocks 2024-12-31 15:03:55 -06:00
Cody Lee 78f30e0056 fix vet 2024-12-31 14:47:06 -06:00
Cody Lee b372198840 painful upgrade for dumb go versioning 2024-12-31 14:44:10 -06:00
Cody Lee b9d668abee upgrading dependencies 2024-12-31 14:23:53 -06:00
Cody Lee 38ac45fc17 update golangci-lint, address lint issue 2024-12-31 14:12:35 -06:00
Cody Lee 9bdc6e8d0f auto fix lint rules 2024-09-09 08:55:12 -05:00
Cody Lee 45a9e0d1eb update base go toolchain, upgrade golangci-lint to address symbol issues 2024-09-09 08:50:21 -05:00
Cody Lee 37df12c8d8 fix warn about specifiying version on goreleaser 2024-06-13 13:07:55 -05:00
Cody Lee 8511800d98 stalebot died, but stale action took over 2024-05-08 08:33:47 -05:00
Cody Lee 5b58e6c237 fix promver collector to default buildinfo collector 2024-04-19 15:51:18 -05:00
Cody Lee 4bd56677c9 fix type 2024-04-19 15:43:00 -05:00
Cody Lee 1367ddbd38 bump unifi client version for more catname flexstring changes 2024-04-19 15:38:24 -05:00
Cody Lee fe3a9a1f7b Merge branch 'master' of github.com:unpoller/unpoller 2024-04-03 18:53:44 -05:00
Cody Lee 169062eeb5 address deprecation warning https://goreleaser.com/deprecations/\#brewsfolder 2024-04-03 18:53:36 -05:00
Cody Lee cfd35ddf67 nice find here, pct should be float 2024-04-03 18:41:34 -05:00
Cody Lee f372ddd3b6 fix integration test 2024-04-03 18:34:54 -05:00
Cody Lee cff22ea303 bump go version to stable, fix unpoller/unifi version with new fake fixes 2024-04-03 18:31:53 -05:00
Cody Lee 7308a1c2e6 fix type errors 2024-04-03 12:17:24 -05:00
Cody Lee c1af2341ec bump go version, bump unifi version for new IDS events 2024-04-03 12:13:55 -05:00
Cody Lee b87ee94111 add hostname per #415 request to loki exports 2024-03-04 18:28:04 -06:00
Cody Lee 6277e443a2 fix freebsd package 2023-11-06 08:26:00 -06:00
Cody Lee 73810739d7 helps if I use the right variable names for docker hub 2023-09-11 15:49:41 -05:00
Cody Lee abe6250a1f update docker hub page overview on release 2023-09-11 15:16:37 -05:00
Cody Lee d1d2f08122 Merge pull request #609 from unpoller/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 3 to 4
2023-09-08 14:44:59 -05:00
Cody Lee 70e61b2b26 Merge pull request #493 from unpoller/docker-hub-push
add docker hub push
2023-09-08 14:41:53 -05:00
Cody Lee 70fa5ceeed Merge pull request #602 from unpoller/dependabot/go_modules/golang.org/x/term-0.12.0
Bump golang.org/x/term from 0.11.0 to 0.12.0
2023-09-04 05:30:29 -05:00