Compare commits

...

3 Commits

Author SHA1 Message Date
kayos@tcp.direct 0dcd7f3030
Chore: tidy up 2023-04-12 22:27:16 -07:00
kayos@tcp.direct d4887ba088
Feat: sensor management 2023-04-12 22:26:56 -07:00
kayos@tcp.direct 9f90e0e47d
Feat: copy light to group 2023-04-12 22:25:59 -07:00
6 changed files with 92 additions and 17 deletions

View File

@ -224,6 +224,38 @@ func cmdDelete(br *ziggy.Bridge, args []string) error {
return nil
}
// cp <light> <group>
// dump the json for a group, then create a new group that adopts only the lights, then add our light id to the new group
// then use update to push the new group to the bridge
func cmdCp(br *ziggy.Bridge, args []string) error {
if len(args) < 2 {
return errors.New("not enough arguments")
}
var (
targetLight *ziggy.HueLight
targetGroup *ziggy.HueGroup
err error
)
if targetLight, err = br.FindLight(args[0]); err != nil {
return err
}
if targetGroup, err = br.FindGroup(args[1]); err != nil {
return err
}
// dump the group
var resp *huego.Response
if resp, err = br.UpdateGroup(targetGroup.ID, huego.Group{
Name: targetGroup.Name,
ID: targetGroup.ID,
Lights: append(targetGroup.Lights, strconv.Itoa(targetLight.ID)),
}); err != nil {
return err
}
log.Info().Msgf("updated group %s to include light %s", targetGroup.Name, targetLight.Name)
log.Trace().Msgf("%v", spew.Sprint(resp))
return nil
}
func cmdRename(br *ziggy.Bridge, args []string) error {
if len(args) < 3 {
return errors.New("not enough arguments")
@ -245,7 +277,7 @@ func cmdRename(br *ziggy.Bridge, args []string) error {
case "rule":
return errors.New("not implemented")
case "sensor":
return errors.New("not implemented")
target, err = br.FindSensor(args[1])
default:
return errors.New("invalid target type")
}

View File

@ -27,7 +27,6 @@ type completion struct {
func (c completion) qualifies(line string) bool {
args, err := shlex.Split(line)
if err != nil {
log.Warn().Err(err).Msg("shlex.Split failed")
return false
}
@ -101,6 +100,7 @@ func init() {
Commands["scan"] = newZiggsCommand(cmdScan, "scan for bridges/lights/sensors", 0,
"search", "find")
Commands["rename"] = newZiggsCommand(cmdRename, "rename object in bridge", 3, "mv")
Commands["cp"] = newZiggsCommand(cmdCp, "copy object pointer to a new group", 2, "copy")
Commands["adopt"] = newZiggsCommand(cmdAdopt, "adopt new lights to the bridge", 0)
Commands["dump"] = newZiggsCommand(cmdDump, "dump target object JSON to a file", 1)
Commands["load"] = newZiggsCommand(cmdLoad, "load JSON from a file into the bridge", 1)

View File

@ -25,16 +25,14 @@ var log *zerolog.Logger
var errNoBridges = errors.New("no bridges available")
type Meta struct {
Bridges map[string]*Bridge
Switches map[string]*huego.Sensor
Bridges map[string]*Bridge
*sync.RWMutex
}
// Lucifer is the lightbringer.
var Lucifer = Meta{
Bridges: make(map[string]*Bridge),
Switches: make(map[string]*huego.Sensor),
RWMutex: &sync.RWMutex{},
Bridges: make(map[string]*Bridge),
RWMutex: &sync.RWMutex{},
}
// Bridge represents a zigbee light controller. Just hue for now.
@ -58,6 +56,17 @@ func (c *Bridge) Log() *zerolog.Logger {
return c.log
}
type HueSensor struct {
*huego.Sensor
controller *Bridge
}
func (hs *HueSensor) Rename(name string) error {
hnew := &huego.Sensor{Name: name}
_, err := hs.controller.UpdateSensor(hs.ID, hnew)
return err
}
type HueLight struct {
*huego.Light
controller *Bridge
@ -264,15 +273,6 @@ func toggle(l *HueLight, mode ToggleMode) error {
return err
}
func ToggleLights(Lights []*HueLight, mode ToggleMode) {
for _, l := range Lights {
err := toggle(l, mode)
if err != nil {
log.Error().Err(err).Bool("On", l.IsOn()).Msg("failed to toggle light")
}
}
}
func (c *Bridge) getLights() error {
var l []*HueLight

View File

@ -58,6 +58,30 @@ func GetGroupMap() map[string]*HueGroup {
return groupMap
}
func GetSensorMap() map[string]*HueSensor {
var sensorMap = make(map[string]*HueSensor)
for _, c := range Lucifer.Bridges {
ss, err := c.GetSensors()
if err != nil {
log.Warn().Msgf("error getting groups on bridge %s: %v", c.ID, err)
continue
}
for _, s := range ss {
sensor, gerr := c.GetSensor(s.ID)
if gerr != nil {
log.Warn().Msgf("failed to get pointer for sensor %s on bridge %s: %v", s.Name, c.ID, gerr)
continue
}
if _, ok := sensorMap[s.Name]; ok {
log.Warn().Msgf("duplicate sensor name %s on bridge %s - please rename", s.Name, c.ID)
continue
}
sensorMap[s.Name] = &HueSensor{Sensor: sensor, controller: c}
}
}
return sensorMap
}
func GetSceneMap() map[string]*HueScene {
var sceneMap = make(map[string]*HueScene)
for _, c := range Lucifer.Bridges {

View File

@ -40,6 +40,23 @@ func (c *Bridge) FindGroup(input string) (light *HueGroup, err error) {
return &HueGroup{Group: hg, controller: c}, nil
}
func (c *Bridge) FindSensor(input string) (light *HueSensor, err error) {
var sensorID int
if sensorID, err = strconv.Atoi(input); err != nil {
targ, ok := GetSensorMap()[input]
if !ok {
return nil, fmt.Errorf("unable to resolve light ID from input: %s", input)
}
return targ, nil
}
var hs *huego.Sensor
if hs, err = c.GetSensor(sensorID); err != nil {
return nil, err
}
return &HueSensor{Sensor: hs, controller: c}, nil
}
func (hg *HueGroup) Scenes() ([]*HueScene, error) {
scenes, err := hg.controller.GetScenes()
if err != nil {

View File

@ -166,7 +166,9 @@ func main() {
log.Info().Msg("starting event client")
defer log.Warn().Msg("event client stopped")
for e := range evch {
println(e)
e = strings.TrimPrefix(e, "data: ")
os.Stdout.WriteString(e)
os.Stdout.WriteString("\n")
}
}()
evc := haptic.NewEventClient()