func updateLightColors(light common.Light, haLight model.LightBulb) { // HAP: [0...360] // LIFX: [0...MAX_UINT16] hue := haLight.GetHue() convertedHue := uint16(math.MaxUint16 * float64(hue) / 360) // HAP: [0...100] // LIFX: [0...MAX_UINT16] saturation := haLight.GetSaturation() convertedSaturation := uint16(math.MaxUint16 * float64(saturation) / 100) // HAP: [0...100] // LIFX: [0...MAX_UINT16] brightness := haLight.GetBrightness() convertedBrightness := uint16(math.MaxUint16 * int(brightness) / 100) // HAP: ? // LIFX: [2500..9000] kelvin := HSBKKelvinDefault log.Infof("[updateLightColors] Hue: %s => %s, Saturation: %s => %s, Brightness: %s => %s", hue, convertedHue, saturation, convertedSaturation, brightness, convertedBrightness) color := common.Color{ Hue: convertedHue, Saturation: convertedSaturation, Brightness: convertedBrightness, Kelvin: kelvin, } light.SetColor(color, 1*time.Second) }
func updateHaPowerState(light common.Light, haLight model.LightBulb) (err error) { turnedOn, err := light.GetPower() if err != nil { log.WithField(`error`, err).Error(`Getting power state light`) return err } haLight.SetOn(turnedOn) return nil }
func handleExpiredLight(light common.Light) (err error) { id := light.ID() meta, exists := lights[id] if !exists { log.Debugf("Cannot remove a light with the ID '%s' that has not been added before", id) return nil } _ = meta.light.CloseSubscription(lights[id].subscription) delete(lights, id) return nil }
func updateHaColors(light common.Light, haLight model.LightBulb) (err error) { color, err := light.GetColor() if err != nil { log.WithField(`error`, err).Error(`Getting color state of light`) return err } hue := color.Hue saturation := color.Saturation brightness := color.Brightness convertedHue := float64(hue) * 360 / math.MaxUint16 convertedSaturation := float64(saturation) * 100 / math.MaxUint16 convertedBrightness := int(brightness) * 100 / math.MaxUint16 log.Infof("[updateHaColors] Hue: %s => %s, Saturation: %s => %s, Brightness: %s => %s", hue, convertedHue, saturation, convertedSaturation, brightness, convertedBrightness) haLight.SetHue(convertedHue) haLight.SetSaturation(convertedSaturation) haLight.SetBrightness(convertedBrightness) return nil }
func (b *boblightSync) remove(l common.Light) { b.Lock() log.WithField(`light`, l.ID()).Debug(`Removing boblight sync`) if c, ok := b.lights[l.ID()]; ok { close(c) delete(b.lights, l.ID()) } b.Unlock() }
func (b *boblightSync) sync(l common.Light, boblightIDs []uint16, rateLimit time.Duration, c closer) { ticker := time.NewTicker(time.Second / 20) for { select { case <-c: ticker.Stop() return case <-ticker.C: colors := make([]common.Color, len(boblightIDs)) for i, id := range boblightIDs { bColor, err := boblight.Lights.Get(id) if err != nil { continue } colors[i] = bColor.ToLifx() } if err := l.SetColor(common.AverageColor(colors...), rateLimit); err != nil { continue } } } }
func (b *boblightSync) add(l common.Light, boblightIDs []uint16, rateLimit time.Duration) { log.WithField(`light`, l.ID()).Debug(`Adding boblight sync`) b.RLock() _, ok := b.lights[l.ID()] b.RUnlock() if ok { return } c := make(closer) b.Lock() b.lights[l.ID()] = c go b.sync(l, boblightIDs, rateLimit, c) b.Unlock() }
func ToggleLight(light common.Light) { power, _ := light.GetPower() light.SetPower(!power) }
func GetHKLight(light common.Light) *HKLight { hkLight, found := lights[light.ID()] if found { return hkLight } label, _ := light.GetLabel() log.Printf("[INFO] Creating New HKLight for %s", label) info := model.Info{ Name: label, Manufacturer: "LIFX", } lightBulb := accessory.NewLightBulb(info) power, _ := light.GetPower() lightBulb.SetOn(power) color, _ := light.GetColor() hue, saturation, brightness := ConvertLIFXColor(color) lightBulb.SetBrightness(int(brightness)) lightBulb.SetSaturation(saturation) lightBulb.SetHue(hue) transport, err := hap.NewIPTransport(pin, lightBulb.Accessory) if err != nil { log.Fatal(err) } go func() { transport.Start() }() hkLight = &HKLight{lightBulb.Accessory, nil, transport, lightBulb} lights[light.ID()] = hkLight lightBulb.OnIdentify(func() { timeout := 1 * time.Second for i := 0; i < 4; i++ { ToggleLight(light) time.Sleep(timeout) } }) lightBulb.OnStateChanged(func(power bool) { log.Printf("[INFO] Changed State for %s", label) light.SetPower(power) }) updateColor := func(light common.Light) { // HAP: [0...360] // LIFX: [0...MAX_UINT16] hue := lightBulb.GetHue() // HAP: [0...100] // LIFX: [0...MAX_UINT16] saturation := lightBulb.GetSaturation() // HAP: [0...100] // LIFX: [0...MAX_UINT16] brightness := lightBulb.GetBrightness() // [HSBKKelvinMin..HSBKKelvinMax] kelvin := HSBKKelvinDefault lifxHue := math.MaxUint16 * float64(hue) / float64(characteristic.MaxHue) lifxSaturation := math.MaxUint16 * float64(saturation) / float64(characteristic.MaxSaturation) lifxBrightness := math.MaxUint16 * float64(brightness) / float64(characteristic.MaxBrightness) color := common.Color{ uint16(lifxHue), uint16(lifxSaturation), uint16(lifxBrightness), kelvin, } light.SetColor(color, 500*time.Millisecond) } lightBulb.OnHueChanged(func(value float64) { log.Printf("[INFO] Changed Hue for %s to %d", label, value) updateColor(light) }) lightBulb.OnSaturationChanged(func(value float64) { log.Printf("[INFO] Changed Saturation for %s to %d", label, value) updateColor(light) }) lightBulb.OnBrightnessChanged(func(value int) { log.Printf("[INFO] Changed Brightness for %s to %d", label, value) updateColor(light) }) return hkLight }
func handleNewLight(light common.Light) (err error) { id := light.ID() _, exists := lights[id] if exists { log.Debugf("A light with the ID '%s' has already been added", id) return nil } subscription, err := light.NewSubscription() if err != nil { log.WithField(`error`, err).Error(`Subscribing to light events`) return err } label, _ := light.GetLabel() log.Infof("Adding light [%s]", label) info := model.Info{ Name: label, Manufacturer: "LIFX", } haLight := accessory.NewLightBulb(info) lights[id] = lightMeta{ light: light, subscription: subscription, haLight: haLight, } // Get the initial state of the light and communicate it via HomeKit updateHaPowerState(light, haLight) updateHaColors(light, haLight) events := subscription.Events() go func() { for { select { case event := <-events: switch event := event.(type) { case common.EventUpdateColor: log.Infof("Light: %s, Event: Update Color", id) updateHaColors(light, haLight) case common.EventUpdateLabel: // TODO: Find out how to update the name of a homekit device log.Infof("Light: %s, Event: Update Label", id) case common.EventUpdatePower: log.Infof("Light: %s, Event: Update Power", id) updateHaPowerState(light, haLight) default: log.Debugf("Unhandled event on light: %+v", event) continue } } } }() haLight.OnIdentify(func() { timeout := 1 * time.Second for i := 0; i < 4; i++ { toggleLight(light) time.Sleep(timeout) } }) haLight.OnStateChanged(func(on bool) { go func() { light.SetPower(on) }() }) haLight.OnBrightnessChanged(func(value int) { go func() { updateLightColors(light, haLight) }() }) haLight.OnSaturationChanged(func(value float64) { go func() { updateLightColors(light, haLight) }() }) haLight.OnHueChanged(func(value float64) { go func() { updateLightColors(light, haLight) }() }) transport, err := hap.NewIPTransport(pin, haLight.Accessory) if err != nil { log.Fatal(err) } go func() { transport.Start() }() return nil }
func toggleLight(light common.Light) { turnedOn, _ := light.GetPower() light.SetPower(!turnedOn) }
func GetHKLight(light common.Light) *HKLight { hkLight, found := lights[light.ID()] if found { return hkLight } label, _ := light.GetLabel() log.Debug.Printf("Creating New HKLight for %s", label) info := accessory.Info{ Name: label, Manufacturer: "LIFX", } acc := accessory.NewLightbulb(info) power, _ := light.GetPower() acc.Lightbulb.On.SetValue(power) color, _ := light.GetColor() hue, saturation, brightness := ConvertLIFXColor(color) acc.Lightbulb.Brightness.SetValue(int(brightness)) acc.Lightbulb.Saturation.SetValue(saturation) acc.Lightbulb.Hue.SetValue(hue) config := hc.Config{Pin: pin} transport, err := hc.NewIPTransport(config, acc.Accessory) if err != nil { log.Info.Panic(err) } go func() { transport.Start() }() hkLight = &HKLight{acc, transport, nil} lights[light.ID()] = hkLight acc.OnIdentify(func() { timeout := 1 * time.Second for i := 0; i < 4; i++ { ToggleLight(light) time.Sleep(timeout) } }) acc.Lightbulb.On.OnValueRemoteUpdate(func(power bool) { log.Debug.Printf("Changed State for %s", label) light.SetPowerDuration(power, transitionDuration) }) updateColor := func(light common.Light) { currentPower, _ := light.GetPower() // HAP: [0...360] // LIFX: [0...MAX_UINT16] hue := acc.Lightbulb.Hue.GetValue() // HAP: [0...100] // LIFX: [0...MAX_UINT16] saturation := acc.Lightbulb.Saturation.GetValue() // HAP: [0...100] // LIFX: [0...MAX_UINT16] brightness := acc.Lightbulb.Brightness.GetValue() // [HSBKKelvinMin..HSBKKelvinMax] kelvin := HSBKKelvinDefault lifxHue := math.MaxUint16 * float64(hue) / float64(HueMax) lifxSaturation := math.MaxUint16 * float64(saturation) / float64(SaturationMax) lifxBrightness := math.MaxUint16 * float64(brightness) / float64(BrightnessMax) color := common.Color{ uint16(lifxHue), uint16(lifxSaturation), uint16(lifxBrightness), kelvin, } light.SetColor(color, transitionDuration) if brightness > 0 && !currentPower { log.Debug.Printf("Color changed for %s, turning on power.", label) light.SetPowerDuration(true, transitionDuration) } else if brightness == 0 && currentPower { log.Debug.Printf("Color changed for %s, but brightness = 0 turning off power.", label) light.SetPower(false) } } acc.Lightbulb.Hue.OnValueRemoteUpdate(func(value float64) { log.Debug.Printf("Changed Hue for %s to %f", label, value) updateColor(light) }) acc.Lightbulb.Saturation.OnValueRemoteUpdate(func(value float64) { log.Debug.Printf("Changed Saturation for %s to %f", label, value) updateColor(light) }) acc.Lightbulb.Brightness.OnValueRemoteUpdate(func(value int) { log.Debug.Printf("Changed Brightness for %s to %d", label, value) updateColor(light) }) return hkLight }