From 7a33b30802e30aeb4ba6fba40343a32b7c488e76 Mon Sep 17 00:00:00 2001 From: "kayos@tcp.direct" Date: Tue, 6 Sep 2022 16:31:44 -0700 Subject: [PATCH] literally had to make these changes before I could turn my hallway light back on :^) --- internal/interactive/cli.go | 2 +- internal/interactive/commands.go | 60 ++++++++++++---------------- internal/interactive/completer.go | 18 +++++++-- internal/system/stats.go | 2 +- internal/ziggy/lights.go | 65 ++++++++++++++++++------------- internal/ziggy/multiplexor.go | 44 +++++++++++++++++++++ main.go | 6 +-- 7 files changed, 124 insertions(+), 73 deletions(-) diff --git a/internal/interactive/cli.go b/internal/interactive/cli.go index b9e26b6..448f488 100644 --- a/internal/interactive/cli.go +++ b/internal/interactive/cli.go @@ -261,7 +261,7 @@ func getHist() []string { func StartCLI() { log = config.GetLogger() processBridges() - grpmap, err := getGroupMap() + grpmap, err := ziggy.GetGroupMap() if err != nil { log.Fatal().Err(err).Msg("error getting group map") } diff --git a/internal/interactive/commands.go b/internal/interactive/commands.go index 05f179e..7767a7a 100644 --- a/internal/interactive/commands.go +++ b/internal/interactive/commands.go @@ -36,13 +36,10 @@ var bridgeCMD = map[string]reactor{ } func cmdLights(br *ziggy.Bridge, args []string) error { - if len(br.HueLights) == 0 { - return errors.New("no lights found") - } - for _, l := range br.HueLights { - log.Info().Str("caller", l.Name). + for name, l := range ziggy.GetLightMap() { + log.Info(). Int("ID", l.ID).Str("type", l.ProductName). - Str("model", l.ModelID).Bool("on", l.IsOn()).Msgf("%v", l.State) + Str("model", l.ModelID).Bool("on", l.IsOn()).Msgf("[+] %s", name) } return nil } @@ -156,7 +153,8 @@ func cmdSet(bridge *ziggy.Bridge, args []string) error { ) var ( - groupmap map[string]*huego.Group + groupMap map[string]*huego.Group + lightMap map[string]*huego.Light actions []action currentState *huego.State argHead = -1 @@ -170,9 +168,9 @@ func cmdSet(bridge *ziggy.Bridge, args []string) error { } log.Trace().Int("argHead", argHead).Msg(args[argHead]) switch args[argHead] { - case "group", "g", "grp": + case "group", "g": var err error - groupmap, err = getGroupMap() + groupMap, err = ziggy.GetGroupMap() if err != nil { return err } @@ -180,7 +178,7 @@ func cmdSet(bridge *ziggy.Bridge, args []string) error { return errors.New("no group specified") } argHead++ - g, ok := groupmap[strings.TrimSpace(args[argHead])] + g, ok := groupMap[strings.TrimSpace(args[argHead])] if !ok { return fmt.Errorf("group %s not found (argHead: %d)", args[argHead], argHead) } @@ -188,6 +186,21 @@ func cmdSet(bridge *ziggy.Bridge, args []string) error { 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": @@ -339,33 +352,8 @@ func cmdSet(bridge *ziggy.Bridge, args []string) error { return nil } -func getGroupMap() (map[string]*huego.Group, error) { - var groupmap = make(map[string]*huego.Group) - for _, br := range ziggy.Lucifer.Bridges { - gs, err := br.GetGroups() - if err != nil { - return nil, err - } - for i, g := range gs { - grp, gerr := br.GetGroup(i) - if gerr != nil { - log.Warn().Msgf("[%s] %w", g.Name, gerr) - continue - } - var count = 1 - groupName := g.Name - for _, ok := groupmap[groupName]; ok; _, ok = groupmap[groupName] { - groupName = fmt.Sprintf("%s_%d", g.Name, count) - } - groupmap[groupName] = grp - } - - } - return groupmap, nil -} - func cmdGroups(br *ziggy.Bridge, args []string) error { - groupmap, err := getGroupMap() + groupmap, err := ziggy.GetGroupMap() if err != nil { return err } diff --git a/internal/interactive/completer.go b/internal/interactive/completer.go index d8f481b..a2d6680 100644 --- a/internal/interactive/completer.go +++ b/internal/interactive/completer.go @@ -101,9 +101,19 @@ func init() { {Suggest: cli.Suggest{Text: "light", Description: "target light"}}, } for _, sug := range suggestions[1] { - sug.requires = map[int][]string{0: {"set", "s"}} + sug.requires = map[int][]string{0: {"delete", "del", "set", "s"}} sug.root = false } + delCompletion := []completion{ + {Suggest: cli.Suggest{Text: "scene", Description: "target scene"}}, + {Suggest: cli.Suggest{Text: "schedule", Description: "target schedule"}}, + {Suggest: cli.Suggest{Text: "sensor", Description: "target sensor"}}, + } + for _, sug := range delCompletion { + sug.requires = map[int][]string{0: {"delete", "del"}} + sug.root = false + } + suggestions[1] = append(suggestions[1], delCompletion...) } func processGroups(grps map[string]*huego.Group) { @@ -119,7 +129,7 @@ func processGroups(grps map[string]*huego.Group) { Description: "Group" + suffix, }, requires: map[int][]string{ - 0: {"set", "s"}, + 0: {"set", "s", "delete", "del"}, 1: {"group", "g"}, }, root: false, @@ -128,7 +138,7 @@ func processGroups(grps map[string]*huego.Group) { } func processLights() { - for lt, l := range ziggy.Lucifer.Lights { + for lt, l := range ziggy.GetLightMap() { suffix := "" if l.Type != "" { suffix = " (" + l.Type + ")" @@ -140,7 +150,7 @@ func processLights() { Description: "Light" + suffix, }, requires: map[int][]string{ - 0: {"set", "s"}, + 0: {"set", "s", "delete", "del"}, 1: {"light", "l"}, }, root: false, diff --git a/internal/system/stats.go b/internal/system/stats.go index b739cc6..5e26115 100644 --- a/internal/system/stats.go +++ b/internal/system/stats.go @@ -33,7 +33,7 @@ func cpuLoad(ctx context.Context) (chan int, error) { func CPULoadGradient(ctx context.Context, colors ...string) (chan colorful.Color, error) { grad, err := colorgrad.NewGradient(). HtmlColors(colors...). - Domain(0, 80). + Domain(0, 100). Build() if err != nil { return nil, err diff --git a/internal/ziggy/lights.go b/internal/ziggy/lights.go index 1089ce4..617aab5 100644 --- a/internal/ziggy/lights.go +++ b/internal/ziggy/lights.go @@ -44,7 +44,7 @@ var Lucifer = Meta{ type Bridge struct { config *config.KnownBridge Info *huego.Config - HueLights []*HueLight + HueLights []*huego.Light *huego.Bridge *sync.RWMutex } @@ -58,18 +58,22 @@ func (c *Bridge) Log() *zerolog.Logger { } type HueLight struct { - huego.Light + l huego.Light controller *Bridge } func (hl *HueLight) Log() *zerolog.Logger { l := log.With(). - Int("caller", hl.ID). - Str("name", hl.Name). - Bool("on", hl.IsOn()).Logger() + Int("caller", hl.l.ID). + Str("name", hl.l.Name). + Bool("on", hl.l.IsOn()).Logger() return &l } +func (hl *HueLight) GetPtr() (*huego.Light, error) { + return hl.controller.GetLight(hl.l.ID) +} + func getProxiedBridge(cridge *config.KnownBridge) *huego.Bridge { cridge.Proxy = strings.TrimPrefix(cridge.Proxy, "socks5://") newTransport := http.DefaultTransport.(*http.Transport).Clone() @@ -125,12 +129,12 @@ const ( Toggle ) -type lCall func(light *HueLight) (checkFunc, error) -type checkFunc func(light *HueLight) bool +type lCall func(light *huego.Light) (checkFunc, error) +type checkFunc func(light *huego.Light) bool var lightCallbacks = map[ToggleMode]lCall{ - ToggleOn: func(light *HueLight) (checkFunc, error) { - return func(light *HueLight) bool { + ToggleOn: func(light *huego.Light) (checkFunc, error) { + return func(light *huego.Light) bool { light.State = &huego.State{ On: true, Bri: 100, @@ -144,8 +148,8 @@ var lightCallbacks = map[ToggleMode]lCall{ }, light.On() }, - ToggleOff: func(light *HueLight) (checkFunc, error) { - return func(light *HueLight) bool { + ToggleOff: func(light *huego.Light) (checkFunc, error) { + return func(light *huego.Light) bool { light.State = &huego.State{ On: false, Bri: 100, @@ -159,8 +163,8 @@ var lightCallbacks = map[ToggleMode]lCall{ }, light.Off() }, - /* ToggleDim: func(light *HueLight) (checkFunc, error) { - return func(light *HueLight) bool { + /* ToggleDim: func(light *huego.Light) (checkFunc, error) { + return func(light *huego.Light) bool { if !light.IsOn() { return false } @@ -168,8 +172,8 @@ var lightCallbacks = map[ToggleMode]lCall{ }, light.On() },*/ - ToggleRainbow: func(light *HueLight) (checkFunc, error) { - return func(light *HueLight) bool { + ToggleRainbow: func(light *huego.Light) (checkFunc, error) { + return func(light *huego.Light) bool { if !light.IsOn() { return false } @@ -179,12 +183,17 @@ var lightCallbacks = map[ToggleMode]lCall{ }, } -func Assert(ctx context.Context, l *HueLight, mode ToggleMode) error { +func Assert(ctx context.Context, l *huego.Light, mode ToggleMode) error { act, ok := lightCallbacks[mode] if !ok { panic("not implemented") } + /* l, err := lo.GetPtr() + if err != nil { + return err + } + */ for { select { case <-ctx.Done(): @@ -203,13 +212,13 @@ func Assert(ctx context.Context, l *HueLight, mode ToggleMode) error { } } -func toggle(l *HueLight, mode ToggleMode) error { - on := func(l *HueLight) error { - l.Log().Trace().Msg("turning light on...") +func toggle(l *huego.Light, mode ToggleMode) error { + on := func(l *huego.Light) error { + log.Trace().Msg("turning light on...") return l.On() } - off := func(l *HueLight) error { - l.Log().Trace().Msg("turning light off...") + off := func(l *huego.Light) error { + log.Trace().Msg("turning light off...") return l.Off() } var err error @@ -230,11 +239,11 @@ func toggle(l *HueLight, mode ToggleMode) error { return err } -func ToggleLights(Lights []*HueLight, mode ToggleMode) { +func ToggleLights(Lights []*huego.Light, mode ToggleMode) { for _, l := range Lights { err := toggle(l, mode) if err != nil { - l.Log().Error().Err(err).Bool("On", l.IsOn()).Msg("failed to toggle light") + log.Error().Err(err).Bool("On", l.IsOn()).Msg("failed to toggle light") } } } @@ -250,19 +259,19 @@ func (c *Bridge) getLights() error { c.Log().Info().Msgf("Found %d lights", len(l)) for _, light := range l { newlight := &HueLight{ - Light: light, + l: light, controller: c, } - newlight.Log().Trace().Msg("+") - c.HueLights = append(c.HueLights, newlight) + log.Trace().Interface("new light", newlight.l).Msg("+") + c.HueLights = append(c.HueLights, &newlight.l) Lucifer.Lock() - Lucifer.Lights[light.UniqueID] = newlight + Lucifer.Lights[light.Name] = newlight Lucifer.Unlock() } return nil } -func (c *Bridge) Lights() []*HueLight { +func (c *Bridge) Lights() []*huego.Light { if len(c.HueLights) > 0 { return c.HueLights } diff --git a/internal/ziggy/multiplexor.go b/internal/ziggy/multiplexor.go index 879fbca..703a438 100644 --- a/internal/ziggy/multiplexor.go +++ b/internal/ziggy/multiplexor.go @@ -1,7 +1,51 @@ package ziggy +import ( + "fmt" + + "github.com/amimof/huego" +) + // Multiplex is all of the lights (all of the lights). // I'll see myself out. type Multiplex struct { bridges []*Bridge } + +func GetGroupMap() (map[string]*huego.Group, error) { + var groupmap = make(map[string]*huego.Group) + for _, br := range Lucifer.Bridges { + gs, err := br.GetGroups() + if err != nil { + return nil, err + } + for i, g := range gs { + grp, gerr := br.GetGroup(i) + if gerr != nil { + log.Warn().Msgf("[%s] %w", g.Name, gerr) + continue + } + var count = 1 + groupName := g.Name + for _, ok := groupmap[groupName]; ok; _, ok = groupmap[groupName] { + groupName = fmt.Sprintf("%s_%d", g.Name, count) + } + groupmap[groupName] = grp + } + + } + return groupmap, nil +} + +func GetLightMap() map[string]*huego.Light { + var lightMap = make(map[string]*huego.Light) + for _, l := range Lucifer.Lights { + realLight, err := l.GetPtr() + if err != nil { + l.Log().Warn().Err(err).Msg("failed to get light pointer") + continue + } + lightMap[realLight.Name] = realLight + } + return lightMap +} diff --git a/main.go b/main.go index b6799ab..4647595 100644 --- a/main.go +++ b/main.go @@ -32,9 +32,9 @@ func init() { func TurnAll(Known []*ziggy.Bridge, mode ziggy.ToggleMode) { for _, bridge := range Known { - for _, l := range bridge.HueLights { - go func(l *ziggy.HueLight) { - l.Log().Debug(). + for _, l := range ziggy.GetLightMap() { + go func(l *huego.Light) { + log.Debug(). Str("caller", bridge.Host). Str("type", l.ProductName). Bool("on", l.IsOn()).Msg(l.ModelID)