Skip to content

Commit

Permalink
perf(linux): ⚡ try to avoid dynamic sensor ID generation
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuar committed Sep 5, 2024
1 parent a3096d0 commit 1013711
Show file tree
Hide file tree
Showing 21 changed files with 65 additions and 62 deletions.
3 changes: 1 addition & 2 deletions internal/hass/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,14 @@ func (c *Client) handleSensorUpdate(ctx context.Context, details sensor.Details)
}

func (c *Client) handleRegistration(ctx context.Context, details sensor.Details) error {
// req, err := sensor.NewRegistrationRequest(details)
req, err := sensor.NewRequest(sensor.RequestTypeRegister, details)
if err != nil {
return fmt.Errorf("unable to handle sensor update: %w", err)
}

response, err := send[sensor.RegistrationResponse](ctx, c, req)
if err != nil {
c.logger.Error("failed to send registration request", slog.Any("error", err))
return fmt.Errorf("failed to send sensor registration request for %s: %w", details.ID(), err)
}

// If the registration failed, log a warning.
Expand Down
2 changes: 1 addition & 1 deletion internal/hass/sensor/sensor.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func createStateUpdateRequest(sensor State) *stateUpdateRequest {
type registrationRequest struct {
*stateUpdateRequest
Name string `json:"name" validate:"required"`
UnitOfMeasurement string `json:"unit_of_measurement,omitempty" validate:"required_with:DeviceClass"`
UnitOfMeasurement string `json:"unit_of_measurement,omitempty" validate:"required_with=DeviceClass"`
StateClass string `json:"state_class,omitempty"`
EntityCategory string `json:"entity_category,omitempty"`
DeviceClass string `json:"device_class,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions internal/linux/apps/activeApps.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
const (
activeAppsIcon = "mdi:application"
activeAppsName = "Active App"
activeAppsID = "active_app"
)

type activeAppSensor struct {
Expand All @@ -22,6 +23,7 @@ func newActiveAppSensor() *activeAppSensor {
return &activeAppSensor{
Sensor: linux.Sensor{
DisplayName: activeAppsName,
UniqueID: activeAppsID,
DataSource: linux.DataSrcDbus,
IconString: activeAppsIcon,
},
Expand Down
2 changes: 2 additions & 0 deletions internal/linux/apps/runningApps.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
runningAppsIcon = "mdi:apps"
runningAppsUnits = "apps"
runningAppsName = "Running Apps"
runningAppsID = "running_apps"
)

type runningAppsSensor struct {
Expand All @@ -32,6 +33,7 @@ func newRunningAppsSensor() *runningAppsSensor {
return &runningAppsSensor{
Sensor: linux.Sensor{
DisplayName: runningAppsName,
UniqueID: runningAppsID,
IconString: runningAppsIcon,
UnitsString: runningAppsUnits,
StateClassValue: types.StateClassMeasurement,
Expand Down
25 changes: 11 additions & 14 deletions internal/linux/cpu/loadAvgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"path/filepath"
"time"

"github.com/iancoleman/strcase"

"github.com/joshuar/go-hass-agent/internal/hass/sensor"
"github.com/joshuar/go-hass-agent/internal/linux"
)
Expand All @@ -33,13 +35,9 @@ const (

var ErrParseLoadAvgs = errors.New("error parsing load averages")

type loadavgSensor struct {
linux.Sensor
}

type loadAvgsSensorWorker struct {
path string
loadAvgs []*loadavgSensor
loadAvgs []*linux.Sensor
}

func (w *loadAvgsSensorWorker) Interval() time.Duration { return loadAvgUpdateInterval }
Expand Down Expand Up @@ -67,17 +65,16 @@ func (w *loadAvgsSensorWorker) Sensors(_ context.Context, _ time.Duration) ([]se
return sensors, nil
}

func newLoadAvgSensors() []*loadavgSensor {
sensors := make([]*loadavgSensor, loadAvgsTotal)
func newLoadAvgSensors() []*linux.Sensor {
sensors := make([]*linux.Sensor, loadAvgsTotal)

for idx, loadType := range []string{"CPU load average (1 min)", "CPU load average (5 min)", "CPU load average (15 min)"} {
loadAvgSensor := &loadavgSensor{
Sensor: linux.Sensor{
IconString: loadAvgIcon,
UnitsString: loadAvgUnit,
DataSource: linux.DataSrcProcfs,
DisplayName: loadType,
},
loadAvgSensor := &linux.Sensor{
IconString: loadAvgIcon,
UnitsString: loadAvgUnit,
DataSource: linux.DataSrcProcfs,
DisplayName: loadType,
UniqueID: strcase.ToSnake(loadType),
}

sensors[idx] = loadAvgSensor
Expand Down
3 changes: 3 additions & 0 deletions internal/linux/cpu/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"strings"
"time"

"github.com/iancoleman/strcase"

"github.com/joshuar/go-hass-agent/internal/hass/sensor"
"github.com/joshuar/go-hass-agent/internal/hass/sensor/types"
"github.com/joshuar/go-hass-agent/internal/linux"
Expand Down Expand Up @@ -157,6 +159,7 @@ func (w *usageWorker) newCountSensor(name, icon, valueStr string) *linux.Sensor

return &linux.Sensor{
DisplayName: name,
UniqueID: strcase.ToSnake(name),
Value: valueInt,
IconString: icon,
DataSource: linux.DataSrcProcfs,
Expand Down
2 changes: 2 additions & 0 deletions internal/linux/desktop/desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func (w *worker) newAccentColorSensor(accent string) (*desktopSettingSensor, err
IconString: "mdi:palette",
DataSource: linux.DataSrcDbus,
DisplayName: "Desktop Accent Color",
UniqueID: "desktop_accent_color",
Value: accent,
},
}, nil
Expand All @@ -80,6 +81,7 @@ func (w *worker) newColorSchemeSensor(scheme string) (*desktopSettingSensor, err
IsDiagnostic: true,
DataSource: linux.DataSrcDbus,
DisplayName: "Desktop Color Scheme",
UniqueID: "desktop_color_scheme",
Value: scheme,
},
}
Expand Down
4 changes: 4 additions & 0 deletions internal/linux/mem/memUsage.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"math"
"time"

"github.com/iancoleman/strcase"

"github.com/joshuar/go-hass-agent/internal/hass/sensor"
"github.com/joshuar/go-hass-agent/internal/hass/sensor/types"
"github.com/joshuar/go-hass-agent/internal/linux"
Expand Down Expand Up @@ -42,6 +44,7 @@ var (
func newMemSensor(id memStatID, stat *memStat) *linux.Sensor {
return &linux.Sensor{
DisplayName: id.String(),
UniqueID: strcase.ToSnake(id.String()),
DeviceClassValue: types.DeviceClassDataSize,
StateClassValue: types.StateClassTotal,
IconString: memorySensorIcon,
Expand All @@ -58,6 +61,7 @@ func newMemSensorPc(name string, value, total uint64) *linux.Sensor {

return &linux.Sensor{
DisplayName: name,
UniqueID: strcase.ToSnake(name),
StateClassValue: types.StateClassMeasurement,
IconString: memorySensorIcon,
DataSource: linux.DataSrcProcfs,
Expand Down
28 changes: 11 additions & 17 deletions internal/linux/net/connectionAddrSensor.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ const (
type connectionAddrSensor struct {
bus *dbusx.Bus
configProp *dbusx.Property[dbus.ObjectPath]
name string
id string
addr string
gateway string
nameservers []string
Expand All @@ -35,14 +33,6 @@ type connectionAddrSensor struct {
ver int
}

func (c *connectionAddrSensor) Name() string {
return c.name
}

func (c *connectionAddrSensor) ID() string {
return c.id
}

func (c *connectionAddrSensor) Attributes() map[string]any {
attributes := c.Sensor.Attributes()
attributes["prefix"] = c.prefix
Expand Down Expand Up @@ -139,7 +129,7 @@ func (c *connectionAddrSensor) updateGateway(configPath string) {
// Get the gateway property using the given config path.
gateway, err := dbusx.NewProperty[string](c.bus, configPath, dBusNMObj, gatewayIntr).Get()
if err != nil {
slog.With(slog.String("connection", c.name)).Debug("Could not retrieve gateway from D-Bus.", slog.Any("error", err))
slog.With(slog.String("connection", c.Name())).Debug("Could not retrieve gateway from D-Bus.", slog.Any("error", err))
} else {
c.gateway = gateway
}
Expand All @@ -155,7 +145,7 @@ func (c *connectionAddrSensor) updateNameservers(path string) {
// Get the gateway property using the given config path.
nameservers, err := dbusx.NewProperty[[]map[string]dbus.Variant](c.bus, path, dBusNMObj, nameserversIntr).Get()
if err != nil {
slog.With(slog.String("connection", c.name)).Debug("Could not retrieve nameservers from D-Bus.", slog.Any("error", err))
slog.With(slog.String("connection", c.Name())).Debug("Could not retrieve nameservers from D-Bus.", slog.Any("error", err))
} else {
for _, details := range nameservers {
nameserver, err := dbusx.VariantToValue[string](details["address"])
Expand Down Expand Up @@ -183,11 +173,15 @@ func newConnectionAddrSensor(bus *dbusx.Bus, ver int, connectionPath, connection
}

return &connectionAddrSensor{
bus: bus,
ver: ver,
name: name,
id: id,
Sensor: linux.Sensor{DataSource: linux.DataSrcDbus, IconString: icon, IsDiagnostic: true},
bus: bus,
ver: ver,
Sensor: linux.Sensor{
DataSource: linux.DataSrcDbus,
IconString: icon,
IsDiagnostic: true,
DisplayName: name,
UniqueID: id,
},
configProp: dbusx.NewProperty[dbus.ObjectPath](bus, connectionPath, dBusNMObj, configPropName),
}
}
18 changes: 5 additions & 13 deletions internal/linux/net/connectionStateSensor.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,10 @@ type connIcon uint32

type connectionStateSensor struct {
stateProp *dbusx.Property[connState]
name string
id string
linux.Sensor
value connState
}

func (c *connectionStateSensor) Name() string {
return c.name
}

func (c *connectionStateSensor) ID() string {
return c.id
}

func (c *connectionStateSensor) Icon() string {
return connIcon(c.value).String()
}
Expand Down Expand Up @@ -90,9 +80,11 @@ func (c *connectionStateSensor) updateState() error {

func newConnectionStateSensor(bus *dbusx.Bus, connectionPath, connectionName string) *connectionStateSensor {
return &connectionStateSensor{
Sensor: linux.Sensor{DataSource: linux.DataSrcDbus},
name: connectionName + " Connection State",
id: strcase.ToSnake(connectionName) + "_connection_state",
Sensor: linux.Sensor{
DataSource: linux.DataSrcDbus,
DisplayName: connectionName + " Connection State",
UniqueID: strcase.ToSnake(connectionName) + "_connection_state",
},
stateProp: dbusx.NewProperty[connState](bus, connectionPath, dBusNMObj, connectionStateProp),
}
}
3 changes: 3 additions & 0 deletions internal/linux/net/networkRates.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"fmt"
"time"

"github.com/iancoleman/strcase"
"github.com/shirou/gopsutil/v3/net"

"github.com/joshuar/go-hass-agent/internal/hass/sensor"
Expand Down Expand Up @@ -92,6 +93,7 @@ func newNetIOSensor(t rateSensor) *netIOSensor {
sensorType: t,
Sensor: linux.Sensor{
DisplayName: t.String(),
UniqueID: strcase.ToSnake(t.String()),
UnitsString: countUnit,
DeviceClassValue: types.DeviceClassDataSize,
StateClassValue: types.StateClassMeasurement,
Expand Down Expand Up @@ -133,6 +135,7 @@ func newNetIORateSensor(t rateSensor) *netIORateSensor {
sensorType: t,
Sensor: linux.Sensor{
DisplayName: t.String(),
UniqueID: strcase.ToSnake(t.String()),
UnitsString: rateUnit,
DeviceClassValue: types.DeviceClassDataRate,
StateClassValue: types.StateClassMeasurement,
Expand Down
6 changes: 6 additions & 0 deletions internal/linux/net/wifiSensor.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,25 +102,31 @@ func newWifiSensor(prop string, value any) *wifiSensor {
switch prop {
case ssidPropName:
wifiSensor.DisplayName = "Wi-Fi SSID"
wifiSensor.UniqueID = "wi_fi_ssid"
case hwAddrPropName:
wifiSensor.DisplayName = "Wi-Fi BSSID"
wifiSensor.UniqueID = "wi_fi_bssid"
case maxBitRatePropName:
wifiSensor.DisplayName = "Wi-Fi Link Speed"
wifiSensor.UniqueID = "wi_fi_link_speed"
wifiSensor.UnitsString = "kB/s"
wifiSensor.DeviceClassValue = types.DeviceClassDataRate
wifiSensor.StateClassValue = types.StateClassMeasurement
case freqPropName:
wifiSensor.DisplayName = "Wi-Fi Frequency"
wifiSensor.UniqueID = "wi_fi_frequency"
wifiSensor.UnitsString = "MHz"
wifiSensor.DeviceClassValue = types.DeviceClassFrequency
wifiSensor.StateClassValue = types.StateClassMeasurement
case bandwidthPropName:
wifiSensor.DisplayName = "Wi-Fi Bandwidth"
wifiSensor.UniqueID = "wi_fi_bandwidth"
wifiSensor.UnitsString = "MHz"
wifiSensor.DeviceClassValue = types.DeviceClassFrequency
wifiSensor.StateClassValue = types.StateClassMeasurement
case strPropName:
wifiSensor.DisplayName = "Wi-Fi Signal Strength"
wifiSensor.UniqueID = "wi_fi_signal_strength"
wifiSensor.UnitsString = "%"
wifiSensor.StateClassValue = types.StateClassMeasurement
}
Expand Down
1 change: 1 addition & 0 deletions internal/linux/power/powerProfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
func newPowerSensor(profile string) *linux.Sensor {
return &linux.Sensor{
DisplayName: "Power Profile",
UniqueID: "power_profile",
Value: profile,
IconString: powerProfileIcon,
DataSource: linux.DataSrcDbus,
Expand Down
1 change: 1 addition & 0 deletions internal/linux/power/powerState.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func newPowerState(signalName powerSignal, signalValue any) *powerStateSensor {
signal: signalName,
Sensor: linux.Sensor{
DisplayName: "Power State",
UniqueID: "power_state",
Value: signalValue,
DataSource: linux.DataSrcDbus,
IsDiagnostic: true,
Expand Down
1 change: 1 addition & 0 deletions internal/linux/power/screenLock.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func newScreenlockEvent(value bool) *screenlockSensor {
return &screenlockSensor{
Sensor: linux.Sensor{
DisplayName: "Screen Lock",
UniqueID: "screen_lock",
IsBinary: true,
DataSource: linux.DataSrcDbus,
Value: value,
Expand Down
1 change: 1 addition & 0 deletions internal/linux/problems/problems.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func (w *worker) Sensors(ctx context.Context, _ time.Duration) ([]sensor.Details
list: make(map[string]map[string]any),
Sensor: linux.Sensor{
DisplayName: "Problems",
UniqueID: "problems",
IconString: "mdi:alert",
UnitsString: "problems",
StateClassValue: types.StateClassMeasurement,
Expand Down
5 changes: 2 additions & 3 deletions internal/linux/sensor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (
"fmt"
"strings"

"github.com/iancoleman/strcase"

"github.com/joshuar/go-hass-agent/internal/hass/sensor/types"
)

Expand All @@ -28,6 +26,7 @@ var ErrUnimplemented = errors.New("unimplemented functionality")
// interface, alllowing them to be sent as a sensor to Home Assistant.
type Sensor struct {
DisplayName string
UniqueID string
LastReset string
Value any
IconString string
Expand All @@ -48,7 +47,7 @@ func (l *Sensor) Name() string {
}

func (l *Sensor) ID() string {
return strcase.ToSnake(l.DisplayName)
return l.UniqueID
}

func (l *Sensor) State() any {
Expand Down
Loading

0 comments on commit 1013711

Please sign in to comment.