2022-09-26 15:25:21 +00:00
|
|
|
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
|
2022-10-29 10:49:28 +00:00
|
|
|
Scene(string) error
|
2022-09-26 15:25:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2022-10-29 10:49:28 +00:00
|
|
|
lightMap map[string]*ziggy.HueLight
|
2022-09-26 15:25:21 +00:00
|
|
|
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":
|
2022-10-12 12:50:02 +00:00
|
|
|
groupMap = ziggy.GetGroupMap()
|
2022-09-26 15:25:21 +00:00
|
|
|
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 {
|
2022-12-13 22:57:32 +00:00
|
|
|
terr := fmt.Errorf("given temperature is not a valid number: %w", numErr)
|
|
|
|
if numErr == nil {
|
|
|
|
terr = fmt.Errorf("temperature must be greater than 153 and less than 500")
|
|
|
|
}
|
|
|
|
return terr
|
2022-09-26 15:25:21 +00:00
|
|
|
}
|
|
|
|
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":
|
2022-10-29 10:49:28 +00:00
|
|
|
go func() {
|
|
|
|
if err := cpuInit(args[argHead], bridge, target); err != nil {
|
|
|
|
log.Error().Err(err).Msg("cpu init failed")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
log.Info().Msg("cpu load lighting started")
|
|
|
|
return nil
|
|
|
|
case "scene", "sc":
|
|
|
|
if len(args) == argHead-1 {
|
|
|
|
return errors.New("not enough arguments")
|
|
|
|
}
|
|
|
|
argHead++
|
2022-12-07 11:25:43 +00:00
|
|
|
if argHead > len(args)-1 {
|
|
|
|
return errors.New("not enough arguments")
|
|
|
|
}
|
2022-10-29 10:49:28 +00:00
|
|
|
targetScene := args[argHead]
|
|
|
|
actions = append(actions, func() error {
|
|
|
|
err := target.Scene(targetScene)
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("failed to set scene: %w", err)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
2022-09-26 15:25:21 +00:00
|
|
|
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)
|
2022-10-29 10:49:28 +00:00
|
|
|
tl, tlok := target.(*ziggy.HueLight)
|
2022-09-26 15:25:21 +00:00
|
|
|
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
|
|
|
|
}
|