package main
import (
+ "encoding/json"
"flag"
"fmt"
"io/ioutil"
"math"
"os"
+ "reflect"
+ "sync"
"time"
+ // prometheus imports
+ "net/http"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+
// color correction
"github.com/lucasb-eyer/go-colorful"
+ "golang.org/x/exp/slices"
"gopkg.in/yaml.v2"
"github.com/go-logr/logr"
- "github.com/rabbitmq/amqp091-go"
"unpiege.net/rabbit_go.git/helper"
)
configFilename string
yamlConfigFilename string
logger logr.Logger
+ lightGauge = promauto.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "light",
+ Help: "Used to measure light status in the real world",
+ },
+ []string{"location"},
+ )
)
// structs
type RGBConfigYaml struct {
RGBRelays []RGBRelay `yaml:"RGBRelays"`
RGBZigs []RGBZig `yaml:"RGBZigs"`
+ RGBPicos []RGBPico `yaml:"RGBPicos"`
+ Switches []Switch `yaml:"Switches"`
}
type Switch struct {
- state bool
- overrideTime time.Time
- expiresAt time.Time
- parentRelay *RGBRelay
+ State bool
+ Location string `yaml:"Location"`
+ FriendlyName string `yaml:"FriendlyName"`
+ OverrideSeconds int `yaml:"OverrideSeconds"`
+ ExpiresAt time.Time
+ parentRelay *RGBRelay
+}
+
+// Switch definitions
+func (curSwitch *Switch) getLocation() string {
+ return curSwitch.Location
}
func (curSwitch *Switch) isActive() bool {
- return false
+ 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
+ // 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) setParent(relay *RGBRelay) {
+ curSwitch.parentRelay = relay
+}
+
+func (curSwitch *Switch) getRoutingKey() string {
+ // this is just how zigbee switches are setup now
+ return fmt.Sprintf("zigbee2mqtt.%s", curSwitch.FriendlyName)
+}
+
+func (curSwitch *Switch) setState(state bool) {
+ curTime := time.Now().UTC()
+ curSwitch.State = state
+ curSwitch.ExpiresAt = curTime.Add(time.Duration(curSwitch.OverrideSeconds) * time.Second)
+ logger.Info("Setting state for switch", "state", state, "switch", curSwitch)
+}
+
+func (curSwitch *Switch) parseState(data map[string]interface{}) {
+ logger.V(3).Info("Got parseState on switch", "switch", curSwitch, "data", data)
+ switchAction := data["action"]
+ // switch on switch, lol
+ switch switchAction {
+ case "on_press_release", "on_press":
+ curSwitch.setState(true)
+ case "off_press_release", "off_press":
+ curSwitch.setState(false)
+ case "down_press", "down_press_release":
+ curSwitch.setExpired(true)
+ default:
+ logger.Error(nil, "Unsupported switch state/data!", "data", data)
+ }
}
+// interface defs for relays
+
type IRGBRelay interface {
Init(sendChannel chan helper.RabbitSend)
setLastMotion()
- addSwitch(newSwitch Switch)
+ addSwitch(newSwitch *Switch)
setPWM(red, green, blue float64)
getLocation() string
+ getMetricValue() float64
+}
+
+type IRGBFriendly interface {
+ IRGBRelay
+ getFriendlyName() string
+}
+
+type IRelayData interface {
+ getRelayData(red, green, blue float64) (map[string]interface{}, string)
+}
+
+type RelayData struct {
+ parent *RGBRelay
+}
+
+func (relayData RelayData) getRelayData(red, green, blue float64) (map[string]interface{}, string) {
+ relayData.parent.logger.V(3).Info("Entering getRelayData for relay")
+ retval := make(map[string]interface{}, 0)
+ if relayData.parent.LastState {
+ retval["red"] = red
+ retval["green"] = green
+ retval["blue"] = blue
+ } else {
+ retval["red"] = 0.0
+ retval["green"] = 0.0
+ retval["blue"] = 0.0
+ }
+ retval["location"] = relayData.parent.Location
+ relayData.parent.logger.V(2).Info("Final relay getRelayData output", "retval", retval)
+
+ return retval, "rgb_relay"
+
}
+
type RGBRelay struct {
UpdateStaleness int `yaml:"UpdateStaleness"`
DimmingTimeout int `yaml:"DimmingTimeout"`
LastUpdate time.Time
LastMotion time.Time
LastState bool
+ logger logr.Logger
sendChannel chan helper.RabbitSend
- switches []Switch `yaml:"Switches"`
+ switches []*Switch `yaml:"Switches"`
+ relayData IRelayData
}
/*func NewRGBRelay(Location string, DimmingTimeout int, sendChannel chan helper.RabbitSend) *RGBRelay {
}*/
func (relay *RGBRelay) Init(sendChannel chan helper.RabbitSend) {
+ relay.logger = logger.WithValues("relay", relay)
relay.sendChannel = sendChannel
+ relay.relayData = RelayData{parent: relay}
// initialize defaults, if they weren't set previously
if relay.DimmingTimeout == 0 {
relay.DimmingTimeout = 300
}
// getMetricValue is used to set prometheus lights on/off state
-func (relay *RGBRelay) getMetricValue() int {
+func (relay *RGBRelay) getMetricValue() float64 {
if relay.LastState {
return 1
} else {
return "rgb_relay"
}
-func (relay *RGBRelay) getSetMap(red, green, blue float64) map[string]interface{} {
- logger.Info("Entering getSetMap regular for relay", "relay", relay)
- retval := make(map[string]interface{}, 0)
- if relay.LastState {
- retval["red"] = red
- retval["green"] = green
- retval["blue"] = blue
- } else {
- retval["red"] = 0.0
- retval["green"] = 0.0
- retval["blue"] = 0.0
+func (relay *RGBRelay) isSwitchActive() bool {
+ var retval bool
+ for _, curSwitch := range relay.switches {
+ if curSwitch.isActive() {
+ retval = true
+ }
}
- retval["location"] = relay.Location
return retval
}
-func (relay *RGBRelay) isSwitchActive() bool {
- return false
-}
-
func (relay *RGBRelay) getSwitchOverride() bool {
var override bool
for _, curSwitch := range relay.switches {
if curSwitch.isActive() {
- override = curSwitch.state
+ override = curSwitch.State
}
}
return override
}
-func (relay *RGBRelay) addSwitch(newSwitch Switch) {
- switchPresent := false
- for _, curSwitch := range relay.switches {
- if curSwitch == newSwitch {
- logger.Info("Tried to add a switch twice", "curSwitch", curSwitch, "newSwitch", newSwitch)
- switchPresent = true
- break
- }
-
- }
- if !switchPresent {
- logger.Info("Adding new switch to relay", "relay", relay, "switch", newSwitch)
+func (relay *RGBRelay) addSwitch(newSwitch *Switch) {
+ if slices.Contains(relay.switches, newSwitch) {
+ relay.logger.Error(nil, "Tried to add a switch twice", "switch", newSwitch)
+ } else {
+ relay.logger.V(1).Info("Adding new switch to relay", "switch", newSwitch)
relay.switches = append(relay.switches, newSwitch)
+ newSwitch.setParent(relay)
}
}
-func (relay *RGBRelay) setSwitchesExpired(source Switch) {
+func (relay *RGBRelay) setSwitchesExpired(source *Switch) {
// for every switch except the one that triggered the expiration..
+ relay.logger.V(2).Info("triggered expire switches", "source", source, "relay.switches", relay.switches)
for _, curSwitch := range relay.switches {
+ // expire it
if curSwitch != source {
- // TODO expire the switch without calling the parent
+ curSwitch.setExpired(false)
}
}
}
}
func (relay *RGBRelay) sendUpdate(red, green, blue float64) {
- logger.V(3).Info("Sending update for relay", "relay", relay)
- rgbData := relay.getSetMap(red, green, blue)
- sendItem := helper.RabbitSend{Data: rgbData, RoutingKey: relay.getRoutingKey()}
+ relay.logger.V(3).Info("Sending update for relay")
+ rgbData, routingKey := relay.relayData.getRelayData(red, green, blue)
+ sendItem := helper.RabbitSend{Data: rgbData, RoutingKey: routingKey}
relay.sendChannel <- sendItem
}
if LastState == true && desiredState == true {
// last state on, desired on (aka already on)
if relay.LastUpdateTooOld() {
- logger.Info("Last update too old, refreshing (on)", "relay", relay)
+ relay.logger.V(2).Info("Last update too old, refreshing (on)")
relay.setLastUpdate()
retval = true
}
// otherwise nothing to change
} else if LastState == false && desiredState == true {
// last off, desired on (aka turn on)
- logger.Info("Turning relay on", "relay", relay)
+ relay.logger.Info("Turning relay on")
relay.LastState = true
relay.setLastUpdate()
retval = true
} else if LastState == true && desiredState == false {
// last state on, desired off (aka turn off)
- logger.Info("Turning relay off", "relay", relay)
+ relay.logger.Info("Turning relay off")
relay.LastState = false
relay.setLastUpdate()
retval = true
} else if LastState == false && desiredState == false {
// last state off, desired off (aka already off)
if relay.LastUpdateTooOld() {
- logger.Info("Last update too old, refreshing (off)", "relay", relay)
+ relay.logger.V(2).Info("Last update too old, refreshing (off)")
relay.setLastUpdate()
retval = true
}
}
// RGBZig Defs
-type RGBZig struct {
- RGBRelay `yaml:"RGBRelay"`
- FriendlyName string `yaml:"FriendlyName"`
- Sengled bool `yaml:"Sengled"`
-}
-
-/*func NewRGBZig(Location string, DimmingTimeout int, sendChannel chan helper.RabbitSend, FriendlyName string, Sengled bool) *RGBZig {
- retval := RGBZig{}
- retval.RGBRelay = NewRGBRelay(Location, DimmingTimeout, sendChannel)
- retval.FriendlyName = FriendlyName
- retval.Sengled = Sengled
- return &retval
-}*/
-
-// RGBZig overrides
-func (zig *RGBZig) getRoutingKey() string {
- return fmt.Sprintf("zigbee2mqtt.%s.set", zig.FriendlyName)
-}
-
-func (zig *RGBZig) setPWM(red, green, blue float64) {
- if zig.shouldUpdate() {
- zig.sendUpdate(red, green, blue)
- }
+type ZigRelayData struct {
+ parent *RGBZig
}
-func (zig *RGBZig) sendUpdate(red, green, blue float64) {
- logger.V(3).Info("Sending update for zig", "zig", zig)
- rgbData := zig.getSetMap(red, green, blue)
- sendItem := helper.RabbitSend{Data: rgbData, RoutingKey: zig.getRoutingKey()}
- zig.sendChannel <- sendItem
-}
-
-func (zig *RGBZig) getSetMap(red, green, blue float64) map[string]interface{} {
- logger.Info("Entering getSetMap regular for zig", "zig", zig)
+func (relayData ZigRelayData) getRelayData(red, green, blue float64) (map[string]interface{}, string) {
+ relayData.parent.logger.V(3).Info("Entering getRelayData for zig")
retval := make(map[string]interface{}, 0)
// we should be turned on
- if zig.LastState {
+ if relayData.parent.LastState {
// correct for different sengled colors
- if zig.Sengled {
+ if relayData.parent.Sengled {
red *= 1.5
blue *= 0.75
green *= 3.0
}
// gamma correct intermediate values
- red = zig.gammaCorrect(red)
- green = zig.gammaCorrect(green)
- blue = zig.gammaCorrect(blue)
+ red = relayData.parent.gammaCorrect(red)
+ green = relayData.parent.gammaCorrect(green)
+ blue = relayData.parent.gammaCorrect(blue)
// color conversions
c := colorful.Color{R: red, G: green, B: blue}
h, s, v := c.Hsv()
// again, sengled changes
- if zig.Sengled {
- logger.Info("Boosting saturation", "pre", s, "post", s+0.2)
+ if relayData.parent.Sengled {
+ logger.V(4).Info("Boosting saturation", "pre", s, "post", s+0.2)
s += 0.2
}
newColor := colorful.Hsv(h, s, v)
// we should be turned off
retval["state"] = "OFF"
}
- logger.Info("Final zig getSetMap output", "retval", retval)
- return retval
+ relayData.parent.logger.V(2).Info("Final zig getRelayData output", "retval", retval)
+ return retval, relayData.parent.getRoutingKey()
+
+}
+
+type RGBZig struct {
+ RGBRelay `yaml:"RGBRelay"`
+ FriendlyName string `yaml:"FriendlyName"`
+ Sengled bool `yaml:"Sengled"`
+}
+
+func (zig *RGBZig) Init(sendChannel chan helper.RabbitSend) {
+ zig.RGBRelay.Init(sendChannel)
+ zig.logger = logger.WithValues("relay", zig)
+ zig.RGBRelay.relayData = ZigRelayData{parent: zig}
+}
+
+// RGBZig added function
+func (zig *RGBZig) getFriendlyName() string {
+ return zig.FriendlyName
+}
+
+// RGBZig overrides
+func (zig *RGBZig) getRoutingKey() string {
+ return fmt.Sprintf("zigbee2mqtt.%s.set", zig.FriendlyName)
+}
+
+// RGBPico defs
+type PicoRelayData struct {
+ parent *RGBPico
+}
+
+func (relayData PicoRelayData) getRelayData(red, green, blue float64) (map[string]interface{}, string) {
+ relayData.parent.logger.V(3).Info("Entering getRelayData for pico")
+ // need to do this in two stages so the json encodes properly
+ actionMap := make(map[string]interface{}, 0)
+ retval := make(map[string]interface{}, 0)
+
+ // turned on last
+ if relayData.parent.LastState {
+ // need to do this in two stages so the json encodes properly
+ actionMap["red"] = red
+ actionMap["green"] = green
+ actionMap["blue"] = blue
+ actionMap["red"] = 0.0
+ actionMap["green"] = 0.0
+ actionMap["blue"] = 0.0
+ }
+ var actionData []byte
+ actionData, err := json.Marshal(actionMap)
+ if err != nil {
+ logger.Error(err, "error found when trying to encode pico action data, just ignoring")
+ }
+ retval["action"] = string(actionData)
+ // should be fully constructed for final encoding by rabbit helper
+ relayData.parent.logger.V(2).Info("Final pico getRelayData output", "retval", retval)
+ return retval, relayData.parent.getRoutingKey()
+
+}
+
+type RGBPico struct {
+ RGBZig `yaml:"RGBZig"`
+ relayData PicoRelayData
+}
+
+func (pico *RGBPico) Init(sendChannel chan helper.RabbitSend) {
+ pico.RGBZig.Init(sendChannel)
+ pico.logger = logger.WithValues("relay", pico)
+ pico.RGBZig.RGBRelay.relayData = PicoRelayData{parent: pico}
}
type RGBManager struct {
- relays []IRGBRelay
+ relays []IRGBRelay
+ switches []*Switch
+ friendlyToLocation map[string][]string
+ friendlyMutex sync.Mutex
+ rabbitHelper *helper.RabbitConfig
}
func (manager *RGBManager) addRelay(relay IRGBRelay) {
manager.relays = append(manager.relays, relay)
+ logger.V(2).Info("total relays", "manager.relays", manager.relays)
+ manager.friendlyMutex.Lock()
+ defer manager.friendlyMutex.Unlock()
+ logger.V(4).Info("(re)building friendly to location map now")
+
+ manager.friendlyToLocation = make(map[string][]string, 0)
+ // build friendlyToLocation map, in order to update linked locations later
+ for _, relay := range manager.relays {
+ // check if we implement the interface giving friendlynames (which means we're an RGBZig or subclass)
+ curZig, ok := relay.(IRGBFriendly)
+ if ok {
+ logger.V(4).Info("Found an RGBZig relay", "relay", curZig)
+ _, isPresent := manager.friendlyToLocation[curZig.getFriendlyName()]
+ if !isPresent {
+ manager.friendlyToLocation[curZig.getFriendlyName()] = make([]string, 0)
+ }
+ if !slices.Contains(manager.friendlyToLocation[curZig.getFriendlyName()], curZig.getLocation()) {
+ manager.friendlyToLocation[curZig.getFriendlyName()] = append(manager.friendlyToLocation[curZig.getFriendlyName()], curZig.getLocation())
+ }
+ }
+ }
+
+ logger.V(4).Info("Final friendlyToLocation map", "map", manager.friendlyToLocation)
+
}
-func (manager *RGBManager) init(rabbit helper.RabbitConfig) {
+func (manager *RGBManager) getLinkedLocations(sourceLocation string) []string {
+ // using a map as a set just to build all the friendly names we care about
+ uniqueFriendlyNames := make(map[string]int, 0)
+
+ for _, relay := range manager.relays {
+ // did we get a friendly name capable relay?
+ curZig, ok := relay.(IRGBFriendly)
+ if ok {
+ if curZig.getLocation() == sourceLocation {
+ uniqueFriendlyNames[curZig.getFriendlyName()] = 1
+ }
+ }
+ }
+
+ // same thing here, for the retval
+ var retval []string
+ // all the keys stored above, aka all the unique friendly names
+ for friendlyName, _ := range uniqueFriendlyNames {
+ // all the values in the map, aka all locations for every unique friendly name (may overlap!)
+ for _, linkedLocation := range manager.friendlyToLocation[friendlyName] {
+ if !slices.Contains(retval, linkedLocation) {
+ retval = append(retval, linkedLocation)
+ }
+ }
+ }
+
+ logger.V(3).Info("Linked locations (by friendly)", "sourceLocation", sourceLocation, "linkedLocations", retval)
+ return retval
+}
+
+func (manager *RGBManager) init(rabbit *helper.RabbitConfig) {
+ manager.rabbitHelper = rabbit
+
// these are hardcoded mostly, the two places we know we'll get data
bindTopics := []string{"timecolorshift.py", "motion"}
for _, bindTopic := range bindTopics {
- err := helper.Bind(bindTopic, &rabbit)
+ err := helper.Bind(bindTopic, manager.rabbitHelper)
if err != nil {
logger.Error(err, "unable to bind successfully to exchange", "routingKey", "leds")
os.Exit(1)
}
}
- deliveries, err := helper.StartConsuming(rabbit)
+}
+
+func (manager *RGBManager) addSwitch(curSwitch *Switch) {
+ // first, bind state updates for this switch so we see them later
+ err := helper.Bind(curSwitch.getRoutingKey(), manager.rabbitHelper)
+ logger.V(2).Info("Bound rabbit to routingKey", "routingKey", curSwitch.getRoutingKey())
if err != nil {
- logger.Error(err, "unable to start consuming data from rabbit")
+ logger.Error(err, "unable to bind successfully to exchange", "routingKey", curSwitch.getRoutingKey())
os.Exit(1)
}
- go manager.readLoop(deliveries)
+ // next, add to a list of all switches we monitor, so that we know where to route those state updates
+ manager.switches = append(manager.switches, curSwitch)
+
+ // finally, for all relays matching the location make sure to add the relevant switches
+ // huge caveat, needs to be done _after_ all relays are added to the manager for proper matching
+ for _, curRelay := range manager.relays {
+ if curRelay.getLocation() == curSwitch.getLocation() {
+ curRelay.addSwitch(curSwitch)
+ }
+ }
+}
+func (manager *RGBManager) handleSwitch(data map[string]interface{}) {
+ logger.Info("Got switch data", "data", data)
}
func (manager *RGBManager) handleMotion(data map[string]interface{}) {
logger.V(3).Info("Got motion data", "data", data)
- for _, relay := range manager.relays {
- if data["location"] == relay.getLocation() {
- logger.Info("Matching location for relay", "relay", relay, "data", data)
- relay.setLastMotion()
+ // only care to go further if it's moving, otherwise we'll just age out
+ if data["motion_detected"].(bool) {
+ linkedLocations := manager.getLinkedLocations(data["location"].(string))
+ for _, relay := range manager.relays {
+ // matches one of the linked locations we got above
+ if slices.Contains(linkedLocations, relay.getLocation()) {
+ logger.V(3).Info("Matching location for relay", "relay", fmt.Sprintf("%v", reflect.ValueOf(relay)), "data", data)
+ relay.setLastMotion()
+ }
}
}
}
func (manager *RGBManager) handlePWM(data map[string]interface{}) {
logger.V(2).Info("Got PWM data", "data", data)
+ var uniqueFriendlyNames = make(map[string]IRGBFriendly, 0)
for _, relay := range manager.relays {
- // float64 triplets should always hold as long as we control the sender
+ // did we get a friendly name capable relay?
+ curZig, ok := relay.(IRGBFriendly)
+ if ok {
+ // set (or overwrite) the friendly name reference to this relay
+ // essentially, get _only_ one relay per friendly name that we'll action
+ uniqueFriendlyNames[curZig.getFriendlyName()] = curZig
+ } else {
+ // immediately set the PWM for non-friendly name enabled relays (since we know there's no dupes)
+ relay.setPWM(data["red"].(float64), data["green"].(float64), data["blue"].(float64))
+ }
+
+ }
+ // here, we don't care about the key, just the fact that we only get one relay out per
+ for _, relay := range uniqueFriendlyNames {
relay.setPWM(data["red"].(float64), data["green"].(float64), data["blue"].(float64))
}
}
-func (manager *RGBManager) readLoop(deliveries <-chan amqp091.Delivery) {
+func (manager *RGBManager) updateMetrics() {
+ for {
+ // sleep for 1 second then update
+ time.Sleep(time.Duration(1) * time.Second)
+ for _, relay := range manager.relays {
+ // did we get a friendly name capable relay?
+ curZig, ok := relay.(IRGBFriendly)
+ // this should give us a fairly unique value, location is friendlyname where enabled, otherwise location is location
+ if ok {
+ lightGauge.With(prometheus.Labels{"location": curZig.getFriendlyName()}).Set(curZig.getMetricValue())
+ } else {
+ lightGauge.With(prometheus.Labels{"location": relay.getLocation()}).Set(relay.getMetricValue())
+ }
+ }
+ }
+}
+func (manager *RGBManager) readLoop() {
+ deliveries, err := helper.StartConsuming(*manager.rabbitHelper)
+ if err != nil {
+ logger.Error(err, "unable to start consuming data from rabbit")
+ os.Exit(1)
+ }
+
//var counter int
for delivery := range deliveries {
logger.V(3).Info("got a delivery", "delivery", delivery)
continue
}
switch delivery.RoutingKey {
+ // first, large bucket categories
case "motion":
manager.handleMotion(item)
case "timecolorshift.py":
manager.handlePWM(item)
+ // now, individual routing keys (entirely switches if they match)
default:
- logger.Error(nil, "no routing key match on delivery!", "routingKey", delivery.RoutingKey)
+ var matches bool
+ for _, curSwitch := range manager.switches {
+ if delivery.RoutingKey == curSwitch.getRoutingKey() {
+ matches = true
+ logger.V(2).Info("Matching routing key for switch, handling", "routingKey", delivery.RoutingKey, "switch", curSwitch)
+ curSwitch.parseState(item)
+ }
+
+ }
+ if !matches {
+ logger.Error(nil, "no routing key match on delivery!", "routingKey", delivery.RoutingKey)
+ }
+
}
}
func sendLoop(channel chan helper.RabbitSend, rabbit helper.RabbitConfig) {
for sendItem := range channel {
//helper.SendData(sendItem, rabbit, true)
+ logger.V(3).Info("Sending item", "item", sendItem)
helper.SendData(sendItem, rabbit, false)
}
}
+func promSetup() {
+ // prometheus setup
+ http.Handle("/metrics", promhttp.Handler())
+ http.ListenAndServe(":9098", nil)
+}
+
func main() {
// logging and flag initialization
flag.StringVar(&configFilename, "config", "", "the config filename")
logger.Error(err, "error parsing time config yaml file")
os.Exit(1)
}
- logger.Info("parsed config as follows", "relayDefs", relayDefs)
+ logger.V(1).Info("parsed config as follows", "relayDefs", relayDefs)
}
rabbit, err := helper.SetupRabbit(configFilename, "", "lights") // config file, default routing key, source
logger.Error(err, "unable to setup rabbit")
os.Exit(1)
}
- logger.Info("rabbit", "rabbit", rabbit)
channel := make(chan helper.RabbitSend)
go sendLoop(channel, rabbit)
manager := RGBManager{}
- manager.init(rabbit)
+ manager.init(&rabbit)
+
+ for i, _ := range relayDefs.RGBRelays {
+ relayDefs.RGBRelays[i].Init(channel)
+ logger.V(1).Info("Adding relay to manager", "relay", relayDefs.RGBRelays[i])
+ manager.addRelay(&relayDefs.RGBRelays[i])
+ }
- for _, relay := range relayDefs.RGBRelays {
- relay.Init(channel)
- manager.addRelay(&relay)
+ // we want to use the index value, because we're adding by pointer rather than value
+ for i, _ := range relayDefs.RGBZigs {
+ relayDefs.RGBZigs[i].Init(channel)
+ logger.V(1).Info("Adding relay to manager", "relay", relayDefs.RGBZigs[i])
+ manager.addRelay(&relayDefs.RGBZigs[i])
}
- for _, relay := range relayDefs.RGBZigs {
- relay.Init(channel)
- manager.addRelay(&relay)
+ for i, _ := range relayDefs.RGBPicos {
+ relayDefs.RGBPicos[i].Init(channel)
+ logger.V(1).Info("Adding relay to manager", "relay", relayDefs.RGBPicos[i])
+ manager.addRelay(&relayDefs.RGBPicos[i])
}
+ for i, _ := range relayDefs.Switches {
+ //relayDefs.Switches[i].Init(channel)
+ logger.V(1).Info("Adding switch to manager", "switch", relayDefs.Switches[i])
+ manager.addSwitch(&relayDefs.Switches[i])
+ }
+
+ go manager.readLoop()
+ go promSetup()
+
+ go manager.updateMetrics()
+
for {
time.Sleep(time.Duration(5) * time.Second)
}