Skip to content

Commit

Permalink
perf(linux): ⚡ rework wifi properties sensors to use dbusx.WatchBus f…
Browse files Browse the repository at this point in the history
…unction
  • Loading branch information
joshuar committed May 19, 2024
1 parent 1bd5d08 commit d5189ce
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 38 deletions.
6 changes: 5 additions & 1 deletion internal/linux/net/networkConnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Expand Down Expand Up @@ -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
}
Expand Down
90 changes: 53 additions & 37 deletions internal/linux/net/wifiProps.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package net

import (
"context"
"slices"

"github.com/godbus/dbus/v5"
"github.com/rs/zerolog/log"
Expand All @@ -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
}
Expand Down Expand Up @@ -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,
Expand All @@ -101,7 +115,7 @@ func newWifiSensor(sensorType string) *wifiSensor {
IsDiagnostic: true,
},
}
case "Frequency":
case freqProp:
return &wifiSensor{
Sensor: linux.Sensor{
SensorTypeValue: linux.SensorWifiFrequency,
Expand All @@ -111,7 +125,7 @@ func newWifiSensor(sensorType string) *wifiSensor {
IsDiagnostic: true,
},
}
case "Strength":
case strProp:
return &wifiSensor{
Sensor: linux.Sensor{
SensorTypeValue: linux.SensorWifiStrength,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

0 comments on commit d5189ce

Please sign in to comment.