239 lines
5.8 KiB
Go
239 lines
5.8 KiB
Go
|
package cli
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"image/color"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/amimof/huego"
|
||
|
|
||
|
"git.tcp.direct/kayos/ziggs/internal/common"
|
||
|
"git.tcp.direct/kayos/ziggs/internal/ziggy"
|
||
|
)
|
||
|
|
||
|
type cmdTarget interface {
|
||
|
On() error
|
||
|
Off() error
|
||
|
Bri(uint8) error
|
||
|
Ct(uint16) error
|
||
|
Hue(uint16) error
|
||
|
Sat(uint8) error
|
||
|
Col(color.Color) error
|
||
|
SetState(huego.State) error
|
||
|
Alert(string) error
|
||
|
}
|
||
|
|
||
|
func cmdSet(bridge *ziggy.Bridge, args []string) error {
|
||
|
if len(args) < 3 {
|
||
|
return errors.New("not enough arguments")
|
||
|
}
|
||
|
|
||
|
type (
|
||
|
action func() error
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
groupMap map[string]*huego.Group
|
||
|
lightMap map[string]*huego.Light
|
||
|
actions []action
|
||
|
currentState *huego.State
|
||
|
argHead = -1
|
||
|
target cmdTarget
|
||
|
)
|
||
|
|
||
|
for range args {
|
||
|
argHead++
|
||
|
if len(args) <= argHead {
|
||
|
break
|
||
|
}
|
||
|
log.Trace().Int("argHead", argHead).Msg(args[argHead])
|
||
|
switch args[argHead] {
|
||
|
case "group", "g":
|
||
|
var err error
|
||
|
groupMap, err = ziggy.GetGroupMap()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if len(args) <= argHead-1 {
|
||
|
return errors.New("no group specified")
|
||
|
}
|
||
|
argHead++
|
||
|
g, ok := groupMap[strings.TrimSpace(args[argHead])]
|
||
|
if !ok {
|
||
|
return fmt.Errorf("group %s not found (argHead: %d)", args[argHead], argHead)
|
||
|
}
|
||
|
log.Trace().Str("group", g.Name).Msgf("found group %s via args[%d]",
|
||
|
args[argHead], argHead,
|
||
|
)
|
||
|
target = g
|
||
|
case "light", "l":
|
||
|
lightMap = ziggy.GetLightMap()
|
||
|
if len(args) <= argHead-1 {
|
||
|
return errors.New("no light specified")
|
||
|
}
|
||
|
argHead++
|
||
|
l, ok := lightMap[strings.TrimSpace(args[argHead])]
|
||
|
if !ok {
|
||
|
return fmt.Errorf("light %s not found (argHead: %d)", args[argHead], argHead)
|
||
|
}
|
||
|
if extraDebug {
|
||
|
log.Trace().Str("group", l.Name).Msgf("found light %s via args[%d]",
|
||
|
args[argHead], argHead)
|
||
|
}
|
||
|
target = l
|
||
|
case "on":
|
||
|
actions = append(actions, target.On)
|
||
|
case "off":
|
||
|
actions = append(actions, target.Off)
|
||
|
case "brightness--", "dim":
|
||
|
actions = append(actions, func() error {
|
||
|
if currentState == nil {
|
||
|
return fmt.Errorf("no state found")
|
||
|
}
|
||
|
err := target.Bri(currentState.Bri - 5)
|
||
|
if err != nil {
|
||
|
err = fmt.Errorf("couldn't lower brightness: %w", err)
|
||
|
}
|
||
|
return err
|
||
|
})
|
||
|
case "brightness++", "brighten":
|
||
|
actions = append(actions, func() error {
|
||
|
if currentState == nil {
|
||
|
return fmt.Errorf("no state found")
|
||
|
}
|
||
|
err := target.Bri(currentState.Bri + 5)
|
||
|
if err != nil {
|
||
|
err = fmt.Errorf("couldn't raise brightness: %w", err)
|
||
|
}
|
||
|
return err
|
||
|
})
|
||
|
case "brightness", "bri":
|
||
|
if len(args) == argHead-1 {
|
||
|
return errors.New("no brightness specified")
|
||
|
}
|
||
|
argHead++
|
||
|
newBrightness, numErr := strconv.Atoi(args[argHead])
|
||
|
if numErr != nil {
|
||
|
return fmt.Errorf("given brightness is not a number: %w", numErr)
|
||
|
}
|
||
|
actions = append(actions, func() error {
|
||
|
err := target.Bri(uint8(newBrightness))
|
||
|
if err != nil {
|
||
|
err = fmt.Errorf("failed to set brightness: %w", err)
|
||
|
}
|
||
|
return err
|
||
|
})
|
||
|
case "color":
|
||
|
if len(args) == argHead-1 {
|
||
|
return errors.New("not enough arguments")
|
||
|
}
|
||
|
argHead++
|
||
|
newcolor, err := common.ParseHexColorFast(args[argHead])
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
actions = append(actions, func() error {
|
||
|
colErr := target.Col(newcolor)
|
||
|
if colErr != nil {
|
||
|
colErr = fmt.Errorf("failed to set color: %w", colErr)
|
||
|
}
|
||
|
return colErr
|
||
|
})
|
||
|
case "hue", "h":
|
||
|
if len(args) == argHead-1 {
|
||
|
return errors.New("not enough arguments")
|
||
|
}
|
||
|
argHead++
|
||
|
newHue, numErr := strconv.Atoi(args[argHead])
|
||
|
if numErr != nil || newHue > 65535 || newHue < 0 {
|
||
|
return fmt.Errorf("given hue is not a valid number: %w", numErr)
|
||
|
}
|
||
|
actions = append(actions, func() error {
|
||
|
err := target.Hue(uint16(newHue))
|
||
|
if err != nil {
|
||
|
err = fmt.Errorf("failed to set hue: %w", err)
|
||
|
}
|
||
|
return err
|
||
|
})
|
||
|
case "saturation", "sat":
|
||
|
if len(args) == argHead-1 {
|
||
|
return errors.New("not enough arguments")
|
||
|
}
|
||
|
argHead++
|
||
|
newSat, numErr := strconv.Atoi(args[argHead])
|
||
|
if numErr != nil || newSat > 255 || newSat < 0 {
|
||
|
return fmt.Errorf("given saturation is not a valid number: %w", numErr)
|
||
|
}
|
||
|
actions = append(actions, func() error {
|
||
|
err := target.Sat(uint8(newSat))
|
||
|
if err != nil {
|
||
|
err = fmt.Errorf("failed to set saturation: %w", err)
|
||
|
}
|
||
|
return err
|
||
|
})
|
||
|
case "temperature", "temp":
|
||
|
if len(args) == argHead-1 {
|
||
|
return errors.New("not enough arguments")
|
||
|
}
|
||
|
argHead++
|
||
|
newTemp, numErr := strconv.Atoi(args[argHead])
|
||
|
if numErr != nil || newTemp > 500 || newTemp < 153 {
|
||
|
return fmt.Errorf("given temperature is not a valid number: %w", numErr)
|
||
|
}
|
||
|
actions = append(actions, func() error {
|
||
|
err := target.Ct(uint16(newTemp))
|
||
|
if err != nil {
|
||
|
err = fmt.Errorf("failed to set temperature: %w", err)
|
||
|
}
|
||
|
return err
|
||
|
})
|
||
|
case "alert":
|
||
|
actions = append(actions, func() error {
|
||
|
alErr := target.Alert("select")
|
||
|
if alErr != nil {
|
||
|
alErr = fmt.Errorf("failed to turn on alert: %w", alErr)
|
||
|
}
|
||
|
return alErr
|
||
|
})
|
||
|
case "cpu", "cpu2":
|
||
|
go cpuInit(args[argHead], bridge, target)
|
||
|
default:
|
||
|
return fmt.Errorf("unknown argument: " + args[argHead])
|
||
|
}
|
||
|
}
|
||
|
if actions == nil {
|
||
|
return errors.New("no action specified")
|
||
|
}
|
||
|
if target == nil {
|
||
|
return errors.New("no target specified")
|
||
|
}
|
||
|
tg, tgok := target.(*huego.Group)
|
||
|
tl, tlok := target.(*huego.Light)
|
||
|
switch {
|
||
|
case tgok:
|
||
|
currentState = tg.State
|
||
|
case tlok:
|
||
|
currentState = tl.State
|
||
|
default:
|
||
|
return errors.New("unknown target")
|
||
|
}
|
||
|
log.Trace().Msgf("current state: %v", currentState)
|
||
|
for d, act := range actions {
|
||
|
log.Trace().Msgf("running action %d", d)
|
||
|
err := act()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
switch {
|
||
|
case tgok:
|
||
|
currentState = tg.State
|
||
|
case tlok:
|
||
|
currentState = tl.State
|
||
|
}
|
||
|
log.Trace().Msgf("new state: %v", currentState)
|
||
|
}
|
||
|
return nil
|
||
|
}
|