joshuar-go-hass-agent/internal/linux/power/powerControl.go

120 lines
3.3 KiB
Go

// Copyright (c) 2024 Joshua Rich <joshua.rich@gmail.com>
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
package power
import (
"context"
"log/slog"
"github.com/eclipse/paho.golang/paho"
mqtthass "github.com/joshuar/go-hass-anything/v12/pkg/hass"
"github.com/joshuar/go-hass-agent/internal/linux"
"github.com/joshuar/go-hass-agent/internal/logging"
"github.com/joshuar/go-hass-agent/internal/preferences"
"github.com/joshuar/go-hass-agent/pkg/linux/dbusx"
)
// powerCommand represents a power command in the agent.
type powerCommand struct {
callBack func(p *paho.Publish)
name string
id string
method string
icon string
}
// generateCommands generates a list of power commands that are available on the
// device running the agent.
func generatePowerCommands(ctx context.Context, bus *dbusx.Bus, device string) []powerCommand {
systemCommands := []powerCommand{
{
name: "Reboot",
id: device + "_reboot",
method: "Reboot",
icon: "mdi:restart",
},
{
name: "Suspend",
id: device + "_suspend",
method: "Suspend",
icon: "mdi:power-sleep",
},
{
name: "Hibernate",
id: device + "_hibernate",
method: "Hibernate",
icon: "mdi:power-sleep",
},
{
name: "Power Off",
id: device + "_poweroff",
method: "PowerOff",
icon: "mdi:power",
},
}
availableCommands := make([]powerCommand, 0, len(systemCommands))
// Add available system power commands.
for _, config := range systemCommands {
// Check if this power method is available on the system.
available, err := dbusx.GetData[string](bus, loginBasePath, loginBaseInterface, managerInterface+".Can"+config.method)
if available == "yes" || err == nil {
config.callBack = generatePowerControlCallback(ctx, bus, config.name, loginBasePath, managerInterface+"."+config.method)
availableCommands = append(availableCommands, config)
}
}
return availableCommands
}
// generatePowerControlCallback creates an MQTT callback function that can
// execute the appropriate D-Bus call to issue a power command on the device.
func generatePowerControlCallback(ctx context.Context, bus *dbusx.Bus, name, path, method string) func(p *paho.Publish) {
return func(_ *paho.Publish) {
err := dbusx.NewMethod(bus, loginBaseInterface, path, method).Call(ctx, true)
if err != nil {
logging.FromContext(ctx).With(slog.String("controller", "power")).
Warn("Could not issue power control.",
slog.String("control", name),
slog.Any("error", err))
}
}
}
func NewPowerControl(ctx context.Context, device *mqtthass.Device) ([]*mqtthass.ButtonEntity, error) {
bus, ok := linux.CtxGetSystemBus(ctx)
if !ok {
return nil, linux.ErrNoSystemBus
}
_, ok = linux.CtxGetSessionPath(ctx)
if !ok {
return nil, linux.ErrNoSessionPath
}
commands := generatePowerCommands(ctx, bus, device.Name)
entities := make([]*mqtthass.ButtonEntity, 0, len(commands))
for _, command := range commands {
entities = append(entities,
mqtthass.NewButtonEntity().
WithDetails(
mqtthass.App(preferences.AppName),
mqtthass.Name(command.name),
mqtthass.ID(command.id),
mqtthass.DeviceInfo(device),
mqtthass.Icon(command.icon),
).
WithCommand(mqtthass.CommandCallback(command.callBack)),
)
}
return entities, nil
}