diff --git a/src/board.go b/src/board.go index 4001a1c..1464e11 100644 --- a/src/board.go +++ b/src/board.go @@ -1,161 +1,49 @@ package main import ( - "fmt" "log" "strings" "github.com/spf13/viper" ) -type Channel struct { - ID string - Num uint - Name string - MQTTTopic string - Value bool - Inverted bool // low level only - OnBoot string - Parent *Board +type Channel interface { + Toggle() (bool, error) + On() error + Off() error + ToString() string + UpdateMQTT() + OnChange() + Status() bool + Parent() Board + Dump() + Name() string + OnBoot() string + SetOnBoot(string) + SetMQTTTopic(string) } -type Board struct { - ID string - Name string - ChannelCount uint - Inverted bool // low level only - Channels []*Channel +type Board interface { + Init() + Dump() + Channel(uint64) Channel } type Outlet struct { ID string Num uint Description string - Board *Board - Channel *Channel + Channel Channel } -func (c *Channel) Toggle() (bool, error) { - c.Value = !c.Value - c.OnChange() - return c.Value, nil -} - -func (c *Channel) On() error { - c.Value = true - c.OnChange() - return nil -} - -func (c *Channel) Off() error { - c.Value = true - c.OnChange() - return nil -} - -func (c *Channel) ToString() string { - if !c.Value { - return "off" - } - return "on" -} - -func (c *Channel) UpdateMQTT() { - MQTTpublish(c.MQTTTopic, c.ToString()) -} - -func (c *Channel) OnChange() { - if c.OnBoot == "last" { - s := fmt.Sprintf("boards.%s.channels.%s.lastvalue", c.Parent.ID, c.ID) - viper.Set(s, c.Value) - viper.WriteConfig() - } - c.UpdateMQTT() -} - -func (c *Channel) Status() bool { - return c.Value -} - -var boards []*Board -var allChannels map[string]*Channel +var boards []Board +var allChannels map[string]Channel var outlets []*Outlet -func newDummyChannel(v *viper.Viper, channelID string) Channel { - v.SetDefault("name", "unknown") - v.SetDefault("lastValue", false) - v.SetDefault("inverted", false) - v.SetDefault("onboot", "off") - v.SetDefault("mqtttopic", v.GetString("name")) - - value := false - switch v.GetString("onboot") { - case "on": - value = true - case "last": - value = v.GetBool("lastValue") - } - // newUUID := UUID.New().String() - // v.SetDefault("id", newUUID) - return Channel{ - ID: channelID, - Num: v.GetUint("num"), - Name: v.GetString("name"), - MQTTTopic: v.GetString("mqtttopic"), - Value: value, - Inverted: v.GetBool("inverted"), - OnBoot: v.GetString("onboot"), - } -} - -func newDummyBoard(v *viper.Viper, id string) Board { - var b Board - - v.SetDefault("name", "board "+id) - v.SetDefault("inverted", false) - v.SetDefault("type", "dummy") - v.SetDefault("channelCount", 0) - v.SetDefault("channels", "") - - if v.GetInt("channelCount") > 0 { - for i := 0; i < v.GetInt("channelCount"); i++ { - v.SetDefault("channels."+fmt.Sprint(i)+".num", i) - } - } - - b = Board{ - ID: id, - Name: v.GetString("name"), - ChannelCount: v.GetUint("channelCount"), - Inverted: v.GetBool("inverted"), - } - - channels := make([]*Channel, v.GetInt("channelCount")) - if v.GetInt("channelCount") > 0 { - channelsConfig := v.Sub("channels") - if channelsConfig != nil { - for channelid1 := range channelsConfig.AllSettings() { - channelid := strings.ToLower(channelid1) - channelConfig := channelsConfig.Sub(channelid) - c := newDummyChannel(channelConfig, channelid) - c.Parent = &b - if c.Num >= v.GetUint("channelCount") { - continue - } - channels[c.Num] = &c - allChannels[c.ID] = &c - } - } - } - b.Channels = channels - - return b -} - func parseBoardsConfig() { // TODO: init boards array? - allChannels = make(map[string]*Channel) + allChannels = make(map[string]Channel) boardsConfig := viper.Sub("boards") if boardsConfig == nil { @@ -168,10 +56,13 @@ func parseBoardsConfig() { boardType := boardConfig.GetString("type") switch boardType { + case "mqtt": + b := newMQTTBoard(boardConfig, key) + boards = append(boards, b) case "gpio": default: b := newDummyBoard(boardConfig, key) - boards = append(boards, &b) + boards = append(boards, b) } @@ -197,7 +88,6 @@ func parseBoardsConfig() { ID: key, Num: num, Description: description, - Board: channel.Parent, Channel: channel, } @@ -216,17 +106,6 @@ func parseBoardsConfig() { } -func (c *Channel) Dump() { - log.Printf(" Channel %d (on boot: %s): %s \n", c.Num, c.OnBoot, c.Name) -} - -func (b *Board) Dump() { - log.Printf("Board '%s' (id: %s): %d channels\n", b.Name, b.ID, b.ChannelCount) - for c := range b.Channels { - b.Channels[c].Dump() - } -} - func (o *Outlet) Dump() { - log.Printf("Outlet %v: channel name: %v\n", o.Num, o.Channel.Name) + log.Printf("Outlet %v: channel name: %v\n", o.Num, o.Channel.Name()) } diff --git a/src/board_dummy.go b/src/board_dummy.go new file mode 100644 index 0000000..a1f0287 --- /dev/null +++ b/src/board_dummy.go @@ -0,0 +1,178 @@ +package main + +import ( + "fmt" + "log" + "strings" + + "github.com/spf13/viper" +) + +type DummyChannel struct { + ID string + Num uint + name string + MQTTTopic string + Value bool + onboot string + parent *DummyBoard +} + +type DummyBoard struct { + ID string + Name string + ChannelCount uint + Channels []*DummyChannel +} + +func newDummyChannel(v *viper.Viper, channelID string) DummyChannel { + v.SetDefault("name", "unknown") + v.SetDefault("lastValue", false) + v.SetDefault("onboot", "off") + v.SetDefault("mqtttopic", v.GetString("name")) + + value := false + switch v.GetString("onboot") { + case "on": + value = true + case "last": + value = v.GetBool("lastValue") + } + // newUUID := UUID.New().String() + // v.SetDefault("id", newUUID) + return DummyChannel{ + ID: channelID, + Num: v.GetUint("num"), + name: v.GetString("name"), + MQTTTopic: v.GetString("mqtttopic"), + Value: value, + onboot: v.GetString("onboot"), + } +} + +func newDummyBoard(v *viper.Viper, id string) *DummyBoard { + var b DummyBoard + + v.SetDefault("name", "board "+id) + v.SetDefault("type", "dummy") + v.SetDefault("channelCount", 0) + v.SetDefault("channels", "") + + if v.GetInt("channelCount") > 0 { + for i := 0; i < v.GetInt("channelCount"); i++ { + v.SetDefault("channels."+fmt.Sprint(i)+".num", i) + } + } + + b = DummyBoard{ + ID: id, + Name: v.GetString("name"), + ChannelCount: v.GetUint("channelCount"), + } + + channels := make([]*DummyChannel, v.GetInt("channelCount")) + if v.GetInt("channelCount") > 0 { + channelsConfig := v.Sub("channels") + if channelsConfig != nil { + for channelid1 := range channelsConfig.AllSettings() { + channelid := strings.ToLower(channelid1) + channelConfig := channelsConfig.Sub(channelid) + c := newDummyChannel(channelConfig, channelid) + c.parent = &b + if c.Num >= v.GetUint("channelCount") { + continue + } + channels[c.Num] = &c + allChannels[c.ID] = &c + } + } + } + b.Channels = channels + + return &b +} + +func (c *DummyChannel) Toggle() (bool, error) { + c.Value = !c.Value + c.OnChange() + return c.Value, nil +} + +func (c *DummyChannel) On() error { + c.Value = true + c.OnChange() + return nil +} + +func (c *DummyChannel) Off() error { + c.Value = true + c.OnChange() + return nil +} + +func (c *DummyChannel) ToString() string { + if !c.Value { + return "off" + } + return "on" +} + +func (c *DummyChannel) UpdateMQTT() { + MQTTpublish(c.MQTTTopic, c.ToString()) +} + +func (c *DummyChannel) OnChange() { + if c.onboot == "last" { + s := fmt.Sprintf("boards.%s.channels.%s.lastvalue", c.parent.ID, c.ID) + viper.Set(s, c.Value) + viper.WriteConfig() + } + c.UpdateMQTT() +} + +func (c *DummyChannel) Status() bool { + return c.Value +} + +func (c *DummyChannel) Parent() Board { + return c.parent +} + +func (c *DummyChannel) Dump() { + log.Printf(" Channel %d (on boot: %s): %s \n", c.Num, c.onboot, c.Name) +} + +func (b *DummyBoard) Dump() { + log.Printf("Board '%s' (id: %s): %d channels\n", b.Name, b.ID, b.ChannelCount) + for c := range b.Channels { + b.Channels[c].Dump() + } +} + +func (b *DummyBoard) Init() { + return +} + +func (b *DummyBoard) Channel(num uint64) Channel { + return b.Channels[num] +} + +func (c *DummyChannel) Name() string { + return c.name +} + +func (c *DummyChannel) OnBoot() string { + return c.onboot +} + +func (c *DummyChannel) SetOnBoot(str string) { + c.onboot = str + s := fmt.Sprintf("boards.%s.channels.%s.onboot", c.parent.ID, c.ID) + viper.Set(s, str) +} + +func (c *DummyChannel) SetMQTTTopic(str string) { + c.MQTTTopic = str + s := fmt.Sprintf("boards.%s.channels.%s.mqtttopic", c.parent.ID, c.ID) + viper.Set(s, str) +} diff --git a/src/board_mqtt.go b/src/board_mqtt.go new file mode 100644 index 0000000..18605c7 --- /dev/null +++ b/src/board_mqtt.go @@ -0,0 +1,183 @@ +package main + +import ( + "fmt" + "log" + "strings" + + "github.com/spf13/viper" +) + +type MQTTChannel struct { + ID string + Num uint + name string + MQTTTopic string + Value bool + onboot string + parent *MQTTBoard + MQTTRemoteTopic string +} + +type MQTTBoard struct { + ID string + Name string + ChannelCount uint + Channels []*MQTTChannel + MQTTRemoteHost string + MQTTRemotePort string + MQTTRemoteUsername string + MQTTRemotePassword string +} + +func newMQTTChannel(v *viper.Viper, channelID string) MQTTChannel { + v.SetDefault("name", "unknown") + v.SetDefault("lastValue", false) + v.SetDefault("onboot", "off") + v.SetDefault("mqtttopic", v.GetString("name")) + + value := false + switch v.GetString("onboot") { + case "on": + value = true + case "last": + value = v.GetBool("lastValue") + } + // newUUID := UUID.New().String() + // v.SetDefault("id", newUUID) + return MQTTChannel{ + ID: channelID, + Num: v.GetUint("num"), + name: v.GetString("name"), + MQTTTopic: v.GetString("mqtttopic"), + Value: value, + onboot: v.GetString("onboot"), + } +} + +func newMQTTBoard(v *viper.Viper, id string) *MQTTBoard { + var b MQTTBoard + + v.SetDefault("name", "board "+id) + v.SetDefault("type", "mqtt") + v.SetDefault("channelCount", 0) + v.SetDefault("channels", "") + + if v.GetInt("channelCount") > 0 { + for i := 0; i < v.GetInt("channelCount"); i++ { + v.SetDefault("channels."+fmt.Sprint(i)+".num", i) + } + } + + b = MQTTBoard{ + ID: id, + Name: v.GetString("name"), + ChannelCount: v.GetUint("channelCount"), + } + + channels := make([]*MQTTChannel, v.GetInt("channelCount")) + if v.GetInt("channelCount") > 0 { + channelsConfig := v.Sub("channels") + if channelsConfig != nil { + for channelid1 := range channelsConfig.AllSettings() { + channelid := strings.ToLower(channelid1) + channelConfig := channelsConfig.Sub(channelid) + c := newMQTTChannel(channelConfig, channelid) + c.parent = &b + if c.Num >= v.GetUint("channelCount") { + continue + } + channels[c.Num] = &c + allChannels[c.ID] = &c + } + } + } + b.Channels = channels + + return &b +} + +func (c *MQTTChannel) Toggle() (bool, error) { + c.Value = !c.Value + c.OnChange() + return c.Value, nil +} + +func (c *MQTTChannel) On() error { + c.Value = true + c.OnChange() + return nil +} + +func (c *MQTTChannel) Off() error { + c.Value = true + c.OnChange() + return nil +} + +func (c *MQTTChannel) ToString() string { + if !c.Value { + return "off" + } + return "on" +} + +func (c *MQTTChannel) UpdateMQTT() { + MQTTpublish(c.MQTTTopic, c.ToString()) +} + +func (c *MQTTChannel) OnChange() { + if c.onboot == "last" { + s := fmt.Sprintf("boards.%s.channels.%s.lastvalue", c.parent.ID, c.ID) + viper.Set(s, c.Value) + viper.WriteConfig() + } + c.UpdateMQTT() +} + +func (c *MQTTChannel) Status() bool { + return c.Value +} + +func (c *MQTTChannel) Parent() Board { + return c.parent +} + +func (c *MQTTChannel) Dump() { + log.Printf(" Channel %d (on boot: %s): %s \n", c.Num, c.onboot, c.Name) +} + +func (b *MQTTBoard) Dump() { + log.Printf("Board '%s' (id: %s): %d channels\n", b.Name, b.ID, b.ChannelCount) + for c := range b.Channels { + b.Channels[c].Dump() + } +} + +func (b *MQTTBoard) Init() { + return +} + +func (b *MQTTBoard) Channel(num uint64) Channel { + return b.Channels[num] +} + +func (c *MQTTChannel) Name() string { + return c.name +} + +func (c *MQTTChannel) OnBoot() string { + return c.onboot +} + +func (c *MQTTChannel) SetOnBoot(str string) { + c.onboot = str + s := fmt.Sprintf("boards.%s.channels.%s.onboot", c.parent.ID, c.ID) + viper.Set(s, str) +} + +func (c *MQTTChannel) SetMQTTTopic(str string) { + c.MQTTTopic = str + s := fmt.Sprintf("boards.%s.channels.%s.mqtttopic", c.parent.ID, c.ID) + viper.Set(s, str) +} diff --git a/src/outlets_ui.go b/src/outlets_ui.go index 5bc2065..93cfd4e 100644 --- a/src/outlets_ui.go +++ b/src/outlets_ui.go @@ -68,10 +68,7 @@ func outletEditPost(ctx *macaron.Context, f OutletPostForm) { outletsPage(ctx) return } - - outlets[num].Channel.OnBoot = onboot - s1 := fmt.Sprintf("boards.%s.channels.%s.onboot", outlets[num].Board.ID, outlets[num].Channel.ID) - viper.Set(s1, onboot) + outlets[num].Channel.SetOnBoot(onboot) outlets[num].Description = strings.TrimSpace(f.Description) s2 := fmt.Sprintf("outlets.%s.description", outlets[num].ID) @@ -79,11 +76,10 @@ func outletEditPost(ctx *macaron.Context, f OutletPostForm) { mqtt := strings.TrimSpace(f.MQTTTopic) if mqtt == "" { - mqtt = outlets[num].Channel.Name + mqtt = outlets[num].Channel.Name() } - outlets[num].Channel.MQTTTopic = mqtt - s3 := fmt.Sprintf("boards.%s.channels.%s.mqtttopic", outlets[num].Board.ID, outlets[num].Channel.ID) - viper.Set(s3, mqtt) + + outlets[num].Channel.SetMQTTTopic(mqtt) viper.WriteConfig() diff --git a/src/status_ui.go b/src/status_ui.go index c497c11..f73bee6 100644 --- a/src/status_ui.go +++ b/src/status_ui.go @@ -22,7 +22,7 @@ func jsonStatus(ctx *macaron.Context) { data = append(data, Dictionary{ "Num": o.Num, "Description": o.Description, - "Status": o.Channel.Value, + "Status": o.Channel.Status(), }) } diff --git a/templates/outlet_edit.html b/templates/outlet_edit.html index 46c9eef..647c25e 100644 --- a/templates/outlet_edit.html +++ b/templates/outlet_edit.html @@ -72,14 +72,14 @@
- +
- +