}
type Switch struct {
- State bool
- Location string `yaml:"Location"`
- FriendlyName string `yaml:"FriendlyName"`
- OverrideSeconds int `yaml:"OverrideSeconds"`
- ExpiresAt time.Time
- parentRelay *RGBRelay
+ State bool
+ ColorState bool
+ Location string `yaml:"Location"`
+ FriendlyName string `yaml:"FriendlyName"`
+ OverrideSeconds int `yaml:"OverrideSeconds"`
+ StateExpiresAt time.Time
+ ColorStateExpiresAt time.Time
+ parentRelay *RGBRelay
}
// Switch definitions
return curSwitch.Location
}
-func (curSwitch *Switch) isActive() bool {
- curTime := time.Now().UTC()
- // this will default true when initialized
- // thus, switch will start inactive like we want
- if curTime.After(curSwitch.ExpiresAt) {
- logger.V(5).Info("Switch is not active", "switch", curSwitch)
- return false
- }
- logger.V(3).Info("Switch is active!", "switch", curSwitch)
- return true
-}
-
func (curSwitch *Switch) setExpired(bubbleUp bool) {
logger.Info("Override removed for switch", "switch", curSwitch)
curTime := time.Now().UTC()
- curSwitch.ExpiresAt = curTime
+ curSwitch.StateExpiresAt = curTime
+ curSwitch.ColorStateExpiresAt = curTime
// set every other switch (not including us to avoid the loop) at this location to expired
if curSwitch.parentRelay != nil && bubbleUp {
curSwitch.parentRelay.setSwitchesExpired(curSwitch)
func (curSwitch *Switch) setState(state bool) {
curTime := time.Now().UTC()
curSwitch.State = state
- curSwitch.ExpiresAt = curTime.Add(time.Duration(curSwitch.OverrideSeconds) * time.Second)
+ curSwitch.StateExpiresAt = curTime.Add(time.Duration(curSwitch.OverrideSeconds) * time.Second)
logger.Info("Setting state for switch", "state", state, "switch", curSwitch)
}
+func (curSwitch *Switch) setColor() {
+ curTime := time.Now().UTC()
+ curSwitch.ColorStateExpiresAt = curTime.Add(time.Duration(curSwitch.OverrideSeconds) * time.Second)
+ logger.Info("Setting color state for switch", "switch", curSwitch)
+}
+
+// get on off status, first "is active", second "is on (or off)"
+func (curSwitch *Switch) getOnOff() (bool, bool) {
+ curTime := time.Now().UTC()
+ // this will default true when initialized
+ // thus, switch will start inactive like we want
+ if curTime.After(curSwitch.StateExpiresAt) {
+ logger.V(5).Info("Switch is not active", "switch", curSwitch)
+ return false, curSwitch.State
+ }
+ logger.V(3).Info("Switch is active!", "switch", curSwitch)
+ return true, curSwitch.State
+}
+
+// get color status, first "is active", second "is full white"
+func (curSwitch *Switch) getColor() (bool, bool) {
+ curTime := time.Now().UTC()
+ // this will default true when initialized
+ // thus, switch will start inactive like we want
+ if curTime.After(curSwitch.ColorStateExpiresAt) {
+ logger.V(5).Info("Switch is not active", "switch", curSwitch)
+ return false, curSwitch.ColorState
+ }
+ logger.V(3).Info("Switch is active!", "switch", curSwitch)
+ return true, curSwitch.ColorState
+}
+
func (curSwitch *Switch) parseState(data map[string]interface{}) {
logger.V(3).Info("Got parseState on switch", "switch", curSwitch, "data", data)
switchAction := data["action"]
curSwitch.setState(true)
case "off_press_release", "off_press":
curSwitch.setState(false)
+ case "up_press", "up_press_release":
+ curSwitch.setColor()
case "down_press", "down_press_release":
curSwitch.setExpired(true)
default:
} else {
inputVal = inputVal / 12.92
}
+ // clamp to 1.0
+ inputVal = math.Min(1.0, inputVal)
return inputVal
}
return "rgb_relay"
}
-func (relay *RGBRelay) isSwitchActive() bool {
- var retval bool
- for _, curSwitch := range relay.switches {
- if curSwitch.isActive() {
- retval = true
- }
- }
- return retval
-}
-
-func (relay *RGBRelay) getSwitchOverride() bool {
- var override bool
- for _, curSwitch := range relay.switches {
- if curSwitch.isActive() {
- override = curSwitch.State
- }
- }
- return override
-}
func (relay *RGBRelay) addSwitch(newSwitch *Switch) {
if slices.Contains(relay.switches, newSwitch) {
relay.logger.Error(nil, "Tried to add a switch twice", "switch", newSwitch)
func (relay *RGBRelay) sendUpdate(red, green, blue float64) {
relay.logger.V(3).Info("Sending update for relay")
+ // now, override for any switch that's active
+ for _, curSwitch := range relay.switches {
+ isActive, _ := curSwitch.getColor()
+ if isActive {
+ red, green, blue = 1.0, 1.0, 1.0
+ break
+ }
+ }
+
rgbData, routingKey := relay.relayData.getRelayData(red, green, blue)
sendItem := helper.RabbitSend{Data: rgbData, RoutingKey: routingKey, EmptySource: true}
relay.sendChannel <- sendItem
// get desired state, starting with the should dim value - i.e. was there recent motion
var desiredState = !relay.shouldDim()
// now, override for any switch that's active
- if relay.isSwitchActive() {
- desiredState = relay.getSwitchOverride()
+ for _, curSwitch := range relay.switches {
+ isActive, isOn := curSwitch.getOnOff()
+ if isActive {
+ desiredState = isOn
+ break
+ }
}
+
// just for brevity and clarity
var LastState = relay.LastState
// again, sengled changes
if relayData.parent.Sengled {
- logger.V(4).Info("Boosting saturation", "pre", s, "post", s+0.2)
- s += 0.2
+ post := s + 0.2
+ post = math.Min(1.0, post)
+ logger.V(4).Info("Boosting saturation", "pre", s, "post", post)
+ s = post
}
newColor := colorful.Hsv(h, s, v)
x, y, z := newColor.Xyz()
}
//var counter int
- for delivery := range deliveries {
+ for {
+ delivery, ok := <-deliveries
+ if !ok {
+ logger.Error(nil, "Consume failed in read loop because channel closed, exiting")
+ os.Exit(1)
+ }
logger.V(3).Info("got a delivery", "delivery", delivery)
item, err := helper.DecodeDelivery(delivery)
// it's just one delivery so we're going to yell and then continue along unabated
logger.Error(err, "Unable to send data to rabbit, exiting!")
os.Exit(1)
}
+ // give zigbee a bit of a delay to catch up?
+ time.Sleep(time.Duration(500) * time.Millisecond)
}
}
os.Exit(1)
}
- channel := make(chan helper.RabbitSend)
+ // buffer 5 messages
+ channel := make(chan helper.RabbitSend, 5)
go sendLoop(channel, rabbit)
manager := RGBManager{}