diff --git a/internal/linux/net/networkConnection.go b/internal/linux/net/networkConnection.go index 5210993d..6954f2d3 100644 --- a/internal/linux/net/networkConnection.go +++ b/internal/linux/net/networkConnection.go @@ -141,11 +141,14 @@ func monitorConnection(ctx context.Context, p dbus.ObjectPath) <-chan sensor.Det // process updates and handle cancellation connCtx, connCancel := context.WithCancel(ctx) go func() { - defer connCancel() defer close(sensorCh) defer close(updateCh) for { select { + case <-connCtx.Done(): + log.Debug().Str("connection", c.Name()).Str("path", string(c.path)). + Msg("Connection deactivated.") + return case <-ctx.Done(): log.Debug().Str("connection", c.Name()).Str("path", string(c.path)). Msg("Stopped monitoring connection.") @@ -184,6 +187,7 @@ func monitorConnection(ctx context.Context, p dbus.ObjectPath) <-chan sensor.Det // monitor state changes go func() { + defer connCancel() for state := range monitorConnectionState(connCtx, string(c.path)) { updateCh <- state } diff --git a/internal/linux/net/wifiProps.go b/internal/linux/net/wifiProps.go index 6eba07fd..179a42ab 100644 --- a/internal/linux/net/wifiProps.go +++ b/internal/linux/net/wifiProps.go @@ -7,6 +7,7 @@ package net import ( "context" + "slices" "github.com/godbus/dbus/v5" "github.com/rs/zerolog/log" @@ -17,6 +18,19 @@ import ( "github.com/joshuar/go-hass-agent/pkg/linux/dbusx" ) +const ( + accessPointInterface = dBusNMObj + ".AccessPoint" + accessPointProp = dBusNMObj + ".Device.Wireless.ActiveAccessPoint" + + ssidProp = "Ssid" + hwAddrProp = "HwAddress" + bitRateProp = "MaxBitrate" + freqProp = "Frequency" + strProp = "Strength" +) + +var wifiPropList = []string{ssidProp, hwAddrProp, bitRateProp, freqProp, strProp} + type wifiSensor struct { linux.Sensor } @@ -77,21 +91,21 @@ func (w *wifiSensor) Icon() string { func newWifiSensor(sensorType string) *wifiSensor { switch sensorType { - case "Ssid": + case ssidProp: return &wifiSensor{ Sensor: linux.Sensor{ SensorTypeValue: linux.SensorWifiSSID, IsDiagnostic: true, }, } - case "HwAddress": + case hwAddrProp: return &wifiSensor{ Sensor: linux.Sensor{ SensorTypeValue: linux.SensorWifiHWAddress, IsDiagnostic: true, }, } - case "MaxBitrate": + case bitRateProp: return &wifiSensor{ Sensor: linux.Sensor{ SensorTypeValue: linux.SensorWifiSpeed, @@ -101,7 +115,7 @@ func newWifiSensor(sensorType string) *wifiSensor { IsDiagnostic: true, }, } - case "Frequency": + case freqProp: return &wifiSensor{ Sensor: linux.Sensor{ SensorTypeValue: linux.SensorWifiFrequency, @@ -111,7 +125,7 @@ func newWifiSensor(sensorType string) *wifiSensor { IsDiagnostic: true, }, } - case "Strength": + case strProp: return &wifiSensor{ Sensor: linux.Sensor{ SensorTypeValue: linux.SensorWifiStrength, @@ -139,15 +153,14 @@ func monitorWifi(ctx context.Context, p dbus.ObjectPath) <-chan sensor.Details { } for _, d := range wifiDevices { // for each device, get the access point it is currently associated with - ap, err := dbusx.GetProp[dbus.ObjectPath](req.Path(d), dBusNMObj+".Device.Wireless.ActiveAccessPoint") + ap, err := dbusx.GetProp[dbus.ObjectPath](req.Path(d), accessPointProp) if err != nil { log.Warn().Err(err).Msg("Could not ascertain access point.") continue } - propBase := dBusNMObj + ".AccessPoint" - for _, prop := range []string{"Ssid", "HwAddress", "MaxBitrate", "Frequency", "Strength"} { + for _, prop := range wifiPropList { // for the associated access point, get the wifi properties as sensors - value, err := dbusx.GetProp[any](req.Path(ap), propBase+"."+prop) + value, err := dbusx.GetProp[any](req.Path(ap), accessPointInterface+"."+prop) if err != nil { log.Warn().Err(err).Str("prop", prop).Msg("Could not get Wi-Fi property %s.") continue @@ -175,39 +188,42 @@ func monitorWifi(ctx context.Context, p dbus.ObjectPath) <-chan sensor.Details { func monitorWifiProps(ctx context.Context, p dbus.ObjectPath) chan sensor.Details { sensorCh := make(chan sensor.Details) - err := dbusx.NewBusRequest(ctx, dbusx.SystemBus). - Match([]dbus.MatchOption{ - dbus.WithMatchObjectPath(p), - }). - Handler(func(s *dbus.Signal) { - if len(s.Body) <= 1 { - log.Debug().Caller().Interface("body", s.Body).Msg("Unexpected body length.") - return - } - props, ok := s.Body[1].(map[string]dbus.Variant) - if ok { - go func() { - for k, v := range props { - wifiSensor := newWifiSensor(k) - if wifiSensor == nil { - log.Debug().Msgf("Could not determine Wi-Fi sensor type for %s.", k) - return - } - wifiSensor.Value = v.Value() - sensorCh <- wifiSensor - } - }() - } - }). - AddWatch(ctx) + + events, err := dbusx.WatchBus(ctx, &dbusx.Watch{ + Bus: dbusx.SystemBus, + Names: wifiPropList, + Path: string(p), + }) if err != nil { - log.Error().Err(err). - Msg("Failed to create WiFi property D-Bus watch.") + log.Debug().Err(err). + Msg("Failed to create wifi properties D-Bus watch.") close(sensorCh) + return sensorCh } + go func() { defer close(sensorCh) - <-ctx.Done() + for { + select { + case <-ctx.Done(): + log.Debug().Msg("Unmonitoring wifi properties.") + return + case event := <-events: + props, err := dbusx.ParsePropertiesChanged(event.Content) + if err != nil { + log.Warn().Err(err).Msg("Did not understand received trigger.") + continue + } + for prop, value := range props.Changed { + if slices.Contains(wifiPropList, prop) { + wifiSensor := newWifiSensor(prop) + wifiSensor.Value = value.Value() + sensorCh <- wifiSensor + } + } + } + } }() + return sensorCh }