From 7714a4bfaad33ef79f3474bb129dfd2ff0a1f6bc Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Wed, 7 Oct 2026 09:40:34 -0500 Subject: [PATCH] chore(deps): bump github.com/unpoller/unifi/v6 to v6.3.1 v6.3.1 reports U-LTE state as a string and cellular SNR as FlexFloat. Keep exporting those readings with the new types. Co-authored-by: Cursor --- go.mod | 2 +- go.sum | 4 ++-- pkg/datadogunifi/uap.go | 4 ++-- pkg/datadogunifi/umbb.go | 12 ++++++++++-- pkg/influxunifi/uap.go | 4 ++-- pkg/influxunifi/umbb.go | 12 ++++++++++-- pkg/otelunifi/uap.go | 4 ++-- pkg/otelunifi/umbb.go | 32 ++++++++++++++++---------------- pkg/promunifi/uap.go | 4 ++-- pkg/promunifi/umbb.go | 31 ++++++++++++++++--------------- 10 files changed, 63 insertions(+), 46 deletions(-) diff --git a/go.mod b/go.mod index 80ab6930..c8f29701 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/prometheus/common v0.72.0 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.12.1 - github.com/unpoller/unifi/v6 v6.3.0 + github.com/unpoller/unifi/v6 v6.3.1 go.opentelemetry.io/otel v1.46.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0 diff --git a/go.sum b/go.sum index ac9fef80..60a0972e 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= -github.com/unpoller/unifi/v6 v6.3.0 h1:J7etDpdkarEG9sOiSORtzZB93RDyzXu9KqZ4cWoBYcQ= -github.com/unpoller/unifi/v6 v6.3.0/go.mod h1:fJ1lU/mpKrQ8Jv3b2yq399ATlrUuiOZAMbKWcw/1GaU= +github.com/unpoller/unifi/v6 v6.3.1 h1:gUBOYmSl/kmTAlSVfTEaDYqGU6iao5biMDeuQcCZmLE= +github.com/unpoller/unifi/v6 v6.3.1/go.mod h1:fJ1lU/mpKrQ8Jv3b2yq399ATlrUuiOZAMbKWcw/1GaU= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= diff --git a/pkg/datadogunifi/uap.go b/pkg/datadogunifi/uap.go index 8fb5bc44..d1f6254e 100644 --- a/pkg/datadogunifi/uap.go +++ b/pkg/datadogunifi/uap.go @@ -146,7 +146,7 @@ func (u *DatadogUnifi) batchLTE(r report, s *unifi.UAP) { "name": s.Name, "model": s.Model, "type": s.Type, - "state": s.LteState.Txt, + "state": s.LteState, "failover_mode": s.LteFailoverMode, "signal": s.LteSignal, "rat": s.LteRat, @@ -171,7 +171,7 @@ func (u *DatadogUnifi) batchLTE(r report, s *unifi.UAP) { // hasLTEStatus reports whether this access point is a cellular backup module. // U-LTE and U-LTE-Pro are typed as UAPs; their live modem status arrives as lte_* fields. func hasLTEStatus(d *unifi.UAP) bool { - return d.LteState.Txt != "" || d.LteFailoverMode != "" || d.LteRat != "" || + return d.LteState != "" || d.LteFailoverMode != "" || d.LteRat != "" || d.LteNetworkOperator != "" || d.LteSignal != "" || d.LteConnected.Txt != "" } diff --git a/pkg/datadogunifi/umbb.go b/pkg/datadogunifi/umbb.go index 49c86817..632bc1c6 100644 --- a/pkg/datadogunifi/umbb.go +++ b/pkg/datadogunifi/umbb.go @@ -105,10 +105,8 @@ func mbbOptional(rad unifi.MBBRadio) map[string]float64 { for k, v := range map[string]unifi.FlexInt{ "rsrp": rad.Rsrp, "rsrq": rad.Rsrq, - "snr": rad.Snr, "nr_rsrp": rad.RsrpNr, "nr_rsrq": rad.RsrqNr, - "nr_snr": rad.SnrNr, "signal": rad.Signal, "signal_percent": rad.SignalPercent, "lte_max_bitrate_dl": rad.MaxBitrateDl, @@ -121,6 +119,16 @@ func mbbOptional(rad unifi.MBBRadio) map[string]float64 { } } + // SNR is a fractional dB reading, so the library decodes it as FlexFloat. + for k, v := range map[string]unifi.FlexFloat{ + "snr": rad.Snr, + "nr_snr": rad.SnrNr, + } { + if v.Txt != "" { + out[k] = v.Val + } + } + return out } diff --git a/pkg/influxunifi/uap.go b/pkg/influxunifi/uap.go index d04eb098..e3e9edf4 100644 --- a/pkg/influxunifi/uap.go +++ b/pkg/influxunifi/uap.go @@ -142,7 +142,7 @@ func (u *InfluxUnifi) batchLTE(r report, s *unifi.UAP) { "name": s.Name, "model": s.Model, "type": s.Type, - "state": s.LteState.Txt, + "state": s.LteState, "failover_mode": s.LteFailoverMode, "signal": s.LteSignal, "rat": s.LteRat, @@ -166,7 +166,7 @@ func (u *InfluxUnifi) batchLTE(r report, s *unifi.UAP) { // hasLTEStatus reports whether this access point is a cellular backup module. // U-LTE and U-LTE-Pro are typed as UAPs; their live modem status arrives as lte_* fields. func hasLTEStatus(d *unifi.UAP) bool { - return d.LteState.Txt != "" || d.LteFailoverMode != "" || d.LteRat != "" || + return d.LteState != "" || d.LteFailoverMode != "" || d.LteRat != "" || d.LteNetworkOperator != "" || d.LteSignal != "" || d.LteConnected.Txt != "" } diff --git a/pkg/influxunifi/umbb.go b/pkg/influxunifi/umbb.go index 408fc341..8f8971a6 100644 --- a/pkg/influxunifi/umbb.go +++ b/pkg/influxunifi/umbb.go @@ -114,10 +114,8 @@ func mbbOptional(rad unifi.MBBRadio) map[string]float64 { for k, v := range map[string]unifi.FlexInt{ "rsrp": rad.Rsrp, "rsrq": rad.Rsrq, - "snr": rad.Snr, "nr_rsrp": rad.RsrpNr, "nr_rsrq": rad.RsrqNr, - "nr_snr": rad.SnrNr, "signal": rad.Signal, "signal_percent": rad.SignalPercent, "lte_max_bitrate_dl": rad.MaxBitrateDl, @@ -130,6 +128,16 @@ func mbbOptional(rad unifi.MBBRadio) map[string]float64 { } } + // SNR is a fractional dB reading, so the library decodes it as FlexFloat. + for k, v := range map[string]unifi.FlexFloat{ + "snr": rad.Snr, + "nr_snr": rad.SnrNr, + } { + if v.Txt != "" { + out[k] = v.Val + } + } + return out } diff --git a/pkg/otelunifi/uap.go b/pkg/otelunifi/uap.go index 17567f42..c0cc0fdb 100644 --- a/pkg/otelunifi/uap.go +++ b/pkg/otelunifi/uap.go @@ -91,7 +91,7 @@ func (u *OtelOutput) exportUAP(ctx context.Context, meter metric.Meter, r *Repor // hasLTEStatus reports whether this access point is a cellular backup module. // U-LTE and U-LTE-Pro are typed as UAPs; their live modem status arrives as lte_* fields. func hasLTEStatus(d *unifi.UAP) bool { - return d.LteState.Txt != "" || d.LteFailoverMode != "" || d.LteRat != "" || + return d.LteState != "" || d.LteFailoverMode != "" || d.LteRat != "" || d.LteNetworkOperator != "" || d.LteSignal != "" || d.LteConnected.Txt != "" } @@ -108,7 +108,7 @@ func (u *OtelOutput) exportLTE(ctx context.Context, meter metric.Meter, r *Repor attribute.String("name", s.Name), attribute.String("model", s.Model), attribute.String("type", s.Type), - attribute.String("lte_state", s.LteState.Txt), + attribute.String("lte_state", s.LteState), attribute.String("lte_failover_mode", s.LteFailoverMode), attribute.String("lte_signal", s.LteSignal), attribute.String("lte_rat", s.LteRat), diff --git a/pkg/otelunifi/umbb.go b/pkg/otelunifi/umbb.go index 30193651..e06fb0ad 100644 --- a/pkg/otelunifi/umbb.go +++ b/pkg/otelunifi/umbb.go @@ -53,24 +53,24 @@ func (u *OtelOutput) exportUMBB(ctx context.Context, meter metric.Meter, r *Repo // Signal readings and bitrates are left out when the modem does not report them, // so a missing reading is not mistaken for 0 dBm. for _, g := range []struct { - name, desc string - val unifi.FlexInt + name, desc, txt string + val float64 }{ - {"unifi_device_umbb_rsrp_dbm", "Cellular RSRP of the serving cell in dBm. LTE anchor in 5G NSA mode", rad.Rsrp}, - {"unifi_device_umbb_rsrq_db", "Cellular RSRQ of the serving cell in dB. LTE anchor in 5G NSA mode", rad.Rsrq}, - {"unifi_device_umbb_snr_db", "Cellular signal-to-noise ratio of the serving cell in dB. LTE anchor in 5G NSA mode", rad.Snr}, - {"unifi_device_umbb_nr_rsrp_dbm", "5G NR RSRP in dBm", rad.RsrpNr}, - {"unifi_device_umbb_nr_rsrq_db", "5G NR RSRQ in dB", rad.RsrqNr}, - {"unifi_device_umbb_nr_snr_db", "5G NR signal-to-noise ratio in dB", rad.SnrNr}, - {"unifi_device_umbb_signal_bars", "Cellular signal strength in bars, as shown by the controller", rad.Signal}, - {"unifi_device_umbb_signal_percent", "Cellular signal strength percentage (0-100)", rad.SignalPercent}, - {"unifi_device_umbb_lte_max_bitrate_dl_bps", "Maximum LTE downlink bitrate in bits per second", rad.MaxBitrateDl}, - {"unifi_device_umbb_lte_max_bitrate_ul_bps", "Maximum LTE uplink bitrate in bits per second", rad.MaxBitrateUl}, - {"unifi_device_umbb_nr_max_bitrate_dl_bps", "Maximum 5G NR downlink bitrate in bits per second", rad.MaxBitrateDlNr}, - {"unifi_device_umbb_nr_max_bitrate_ul_bps", "Maximum 5G NR uplink bitrate in bits per second", rad.MaxBitrateUlNr}, + {"unifi_device_umbb_rsrp_dbm", "Cellular RSRP of the serving cell in dBm. LTE anchor in 5G NSA mode", rad.Rsrp.Txt, rad.Rsrp.Val}, + {"unifi_device_umbb_rsrq_db", "Cellular RSRQ of the serving cell in dB. LTE anchor in 5G NSA mode", rad.Rsrq.Txt, rad.Rsrq.Val}, + {"unifi_device_umbb_snr_db", "Cellular signal-to-noise ratio of the serving cell in dB. LTE anchor in 5G NSA mode", rad.Snr.Txt, rad.Snr.Val}, + {"unifi_device_umbb_nr_rsrp_dbm", "5G NR RSRP in dBm", rad.RsrpNr.Txt, rad.RsrpNr.Val}, + {"unifi_device_umbb_nr_rsrq_db", "5G NR RSRQ in dB", rad.RsrqNr.Txt, rad.RsrqNr.Val}, + {"unifi_device_umbb_nr_snr_db", "5G NR signal-to-noise ratio in dB", rad.SnrNr.Txt, rad.SnrNr.Val}, + {"unifi_device_umbb_signal_bars", "Cellular signal strength in bars, as shown by the controller", rad.Signal.Txt, rad.Signal.Val}, + {"unifi_device_umbb_signal_percent", "Cellular signal strength percentage (0-100)", rad.SignalPercent.Txt, rad.SignalPercent.Val}, + {"unifi_device_umbb_lte_max_bitrate_dl_bps", "Maximum LTE downlink bitrate in bits per second", rad.MaxBitrateDl.Txt, rad.MaxBitrateDl.Val}, + {"unifi_device_umbb_lte_max_bitrate_ul_bps", "Maximum LTE uplink bitrate in bits per second", rad.MaxBitrateUl.Txt, rad.MaxBitrateUl.Val}, + {"unifi_device_umbb_nr_max_bitrate_dl_bps", "Maximum 5G NR downlink bitrate in bits per second", rad.MaxBitrateDlNr.Txt, rad.MaxBitrateDlNr.Val}, + {"unifi_device_umbb_nr_max_bitrate_ul_bps", "Maximum 5G NR uplink bitrate in bits per second", rad.MaxBitrateUlNr.Txt, rad.MaxBitrateUlNr.Val}, } { - if g.val.Txt != "" { - u.recordGauge(ctx, meter, r, g.name, g.desc, g.val.Val, attrs) + if g.txt != "" { + u.recordGauge(ctx, meter, r, g.name, g.desc, g.val, attrs) } } diff --git a/pkg/promunifi/uap.go b/pkg/promunifi/uap.go index a6c121d7..2a2bef28 100644 --- a/pkg/promunifi/uap.go +++ b/pkg/promunifi/uap.go @@ -429,7 +429,7 @@ func (u *promUnifi) exportRADtable(r report, labels []string, rt unifi.RadioTabl // U-LTE and U-LTE-Pro are typed as UAPs; their live modem status arrives as lte_* fields // on the device list, not on the gateway WAN ports. func hasLTEStatus(d *unifi.UAP) bool { - return d.LteState.Txt != "" || d.LteFailoverMode != "" || d.LteRat != "" || + return d.LteState != "" || d.LteFailoverMode != "" || d.LteRat != "" || d.LteNetworkOperator != "" || d.LteSignal != "" || d.LteConnected.Txt != "" } @@ -439,7 +439,7 @@ func (u *promUnifi) exportLTE(r report, d *unifi.UAP, labels []string) { } info := append(append([]string{}, labels...), - d.LteState.Txt, + d.LteState, d.LteFailoverMode, d.LteSignal, d.LteRat, diff --git a/pkg/promunifi/umbb.go b/pkg/promunifi/umbb.go index a847e336..c13e460c 100644 --- a/pkg/promunifi/umbb.go +++ b/pkg/promunifi/umbb.go @@ -135,24 +135,25 @@ func (u *promUnifi) exportMBB(r report, labels []string, d *unifi.UMBB) { // so a missing reading is not mistaken for 0 dBm. for _, s := range []struct { desc *prometheus.Desc - val unifi.FlexInt + txt string + val float64 dims []string }{ - {u.UMBB.Rsrp, rad.Rsrp, nil}, - {u.UMBB.Rsrq, rad.Rsrq, nil}, - {u.UMBB.Snr, rad.Snr, nil}, - {u.UMBB.RsrpNr, rad.RsrpNr, nil}, - {u.UMBB.RsrqNr, rad.RsrqNr, nil}, - {u.UMBB.SnrNr, rad.SnrNr, nil}, - {u.UMBB.SignalBars, rad.Signal, nil}, - {u.UMBB.SignalPercent, rad.SignalPercent, nil}, - {u.UMBB.MaxBitrate, rad.MaxBitrateDl, []string{"lte", "dl"}}, - {u.UMBB.MaxBitrate, rad.MaxBitrateUl, []string{"lte", "ul"}}, - {u.UMBB.MaxBitrate, rad.MaxBitrateDlNr, []string{"nr", "dl"}}, - {u.UMBB.MaxBitrate, rad.MaxBitrateUlNr, []string{"nr", "ul"}}, + {u.UMBB.Rsrp, rad.Rsrp.Txt, rad.Rsrp.Val, nil}, + {u.UMBB.Rsrq, rad.Rsrq.Txt, rad.Rsrq.Val, nil}, + {u.UMBB.Snr, rad.Snr.Txt, rad.Snr.Val, nil}, + {u.UMBB.RsrpNr, rad.RsrpNr.Txt, rad.RsrpNr.Val, nil}, + {u.UMBB.RsrqNr, rad.RsrqNr.Txt, rad.RsrqNr.Val, nil}, + {u.UMBB.SnrNr, rad.SnrNr.Txt, rad.SnrNr.Val, nil}, + {u.UMBB.SignalBars, rad.Signal.Txt, rad.Signal.Val, nil}, + {u.UMBB.SignalPercent, rad.SignalPercent.Txt, rad.SignalPercent.Val, nil}, + {u.UMBB.MaxBitrate, rad.MaxBitrateDl.Txt, rad.MaxBitrateDl.Val, []string{"lte", "dl"}}, + {u.UMBB.MaxBitrate, rad.MaxBitrateUl.Txt, rad.MaxBitrateUl.Val, []string{"lte", "ul"}}, + {u.UMBB.MaxBitrate, rad.MaxBitrateDlNr.Txt, rad.MaxBitrateDlNr.Val, []string{"nr", "dl"}}, + {u.UMBB.MaxBitrate, rad.MaxBitrateUlNr.Txt, rad.MaxBitrateUlNr.Val, []string{"nr", "ul"}}, } { - if s.val.Txt != "" { - r.send([]*metric{{s.desc, gauge, s.val.Val, append(append([]string{}, labels...), s.dims...)}}) + if s.txt != "" { + r.send([]*metric{{s.desc, gauge, s.val, append(append([]string{}, labels...), s.dims...)}}) } }