diff --git a/boards/boards.go b/boards/boards.go index 680b64a..edf88f1 100644 --- a/boards/boards.go +++ b/boards/boards.go @@ -5,6 +5,7 @@ import ( "github.com/godbus/dbus/v5/introspect" "github.com/godbus/dbus/v5/prop" + "github.com/home-assistant/os-agent/boards/green" "github.com/home-assistant/os-agent/boards/supervised" "github.com/home-assistant/os-agent/boards/yellow" logging "github.com/home-assistant/os-agent/utils/log" @@ -70,6 +71,8 @@ func InitializeDBus(conn *dbus.Conn, board string) { // Initialize the board if board == "Yellow" { yellow.InitializeDBus(conn) + } else if board == "Green" { + green.InitializeDBus(conn) } else if board == "Supervised" { supervised.InitializeDBus(conn) } else { diff --git a/boards/green/green.go b/boards/green/green.go new file mode 100644 index 0000000..137f04a --- /dev/null +++ b/boards/green/green.go @@ -0,0 +1,120 @@ +package green + +import ( + "github.com/godbus/dbus/v5" + "github.com/godbus/dbus/v5/introspect" + "github.com/godbus/dbus/v5/prop" + + "github.com/home-assistant/os-agent/utils/led" + logging "github.com/home-assistant/os-agent/utils/log" +) + +const ( + objectPath = "/io/hass/os/Boards/Green" + ifaceName = "io.hass.os.Boards.Green" +) + +var ( + ledPower led.LED = led.LED{Name: "power", DefaultTrigger: "default-on"} + ledActivity led.LED = led.LED{Name: "activity", DefaultTrigger: "activity"} + ledUser led.LED = led.LED{Name: "user", DefaultTrigger: "heartbeat"} +) + +type green struct { + conn *dbus.Conn + props *prop.Properties +} + +func getTriggerLED(led led.LED) bool { + value, err := led.GetTrigger() + if err != nil { + logging.Error.Print(err) + } + return value != "none" +} + +func setTriggerLED(led led.LED, c *prop.Change) *dbus.Error { + logging.Info.Printf("Set Green %s LED to %t", led.Name, c.Value) + err := led.SetTrigger(c.Value.(bool)) + if err != nil { + return dbus.MakeFailedError(err) + } + return nil +} + +func setPowerLED(c *prop.Change) *dbus.Error { + return setTriggerLED(ledPower, c) +} + +func setActivityLED(c *prop.Change) *dbus.Error { + return setTriggerLED(ledActivity, c) +} + +func setUserLED(c *prop.Change) *dbus.Error { + return setTriggerLED(ledUser, c) +} + +func InitializeDBus(conn *dbus.Conn) { + d := green{ + conn: conn, + } + + // Init base value + ledPowerValue := getTriggerLED(ledPower) + ledActivityValue := getTriggerLED(ledActivity) + ledUserValue := getTriggerLED(ledUser) + + propsSpec := map[string]map[string]*prop.Prop{ + ifaceName: { + "PowerLED": { + Value: ledPowerValue, + Writable: true, + Emit: prop.EmitTrue, + Callback: setPowerLED, + }, + "ActivityLED": { + Value: ledActivityValue, + Writable: true, + Emit: prop.EmitTrue, + Callback: setActivityLED, + }, + "UserLED": { + Value: ledUserValue, + Writable: true, + Emit: prop.EmitTrue, + Callback: setUserLED, + }, + }, + } + + props, err := prop.Export(conn, objectPath, propsSpec) + if err != nil { + logging.Critical.Panic(err) + } + d.props = props + + err = conn.Export(d, objectPath, ifaceName) + if err != nil { + logging.Critical.Panic(err) + } + + node := &introspect.Node{ + Name: objectPath, + Interfaces: []introspect.Interface{ + introspect.IntrospectData, + prop.IntrospectData, + { + Name: ifaceName, + Methods: introspect.Methods(d), + Properties: props.Introspection(ifaceName), + }, + }, + } + + err = conn.Export(introspect.NewIntrospectable(node), objectPath, "org.freedesktop.DBus.Introspectable") + if err != nil { + logging.Critical.Panic(err) + } + + logging.Info.Printf("Exposing object %s with interface %s ...", objectPath, ifaceName) +} diff --git a/main.go b/main.go index 6a3a56b..51ae3d5 100644 --- a/main.go +++ b/main.go @@ -24,9 +24,10 @@ const ( ) var ( + // version and baord are set at link time via -X flag version string = "dev" - enableCapture bool = false board string = "unknown" + enableCapture bool = false ) func main() { diff --git a/utils/led/led.go b/utils/led/led.go new file mode 100644 index 0000000..55a5641 --- /dev/null +++ b/utils/led/led.go @@ -0,0 +1,39 @@ +package led + +import ( + "os" + "path/filepath" + "strings" +) + +type LED struct { + Name string + DefaultTrigger string +} + +func (led LED) GetTrigger() (string, error) { + ledTriggerFilePath := filepath.Join("/sys/class/leds/", led.Name, "trigger") + ledTrigger, err := os.ReadFile(ledTriggerFilePath) + if err != nil { + return "", err + } + return strings.TrimSpace(string(ledTrigger)), err +} + +func (led LED) SetTrigger(newState bool) error { + ledTriggerFilePath := filepath.Join("/sys/class/leds/", led.Name, "trigger") + var newTrigger []byte + + if newState { + newTrigger = []byte(led.DefaultTrigger) + } else { + newTrigger = []byte("none") + } + + err := os.WriteFile(ledTriggerFilePath, newTrigger, 0600) + if err != nil { + return err + } + + return nil +}