openpdu/src/board.go

233 lines
4.6 KiB
Go

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 Board struct {
ID string
Name string
ChannelCount uint
Inverted bool // low level only
Channels []*Channel
}
type Outlet struct {
ID string
Num uint
Description string
Board *Board
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 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)
boardsConfig := viper.Sub("boards")
if boardsConfig == nil {
logWarning("No board configured")
return
}
for key := range boardsConfig.AllSettings() {
boardConfig := boardsConfig.Sub(key)
boardType := boardConfig.GetString("type")
switch boardType {
case "gpio":
default:
b := newDummyBoard(boardConfig, key)
boards = append(boards, &b)
}
}
outlets = make([]*Outlet, len(allChannels))
outletsConfig := viper.Sub("outlets")
if outletsConfig == nil {
logWarning("No outlet configured")
return
}
for key := range outletsConfig.AllSettings() {
outletConfig := outletsConfig.Sub(key)
num := outletConfig.GetUint("num")
outletConfig.SetDefault("description", "no description")
description := outletConfig.GetString("description")
channelID := strings.ToLower(outletConfig.GetString("channelID"))
channel := allChannels[channelID]
// TODO: channel non esistente
o := Outlet{
ID: key,
Num: num,
Description: description,
Board: channel.Parent,
Channel: channel,
}
outlets[num] = &o
}
// dumpa tutto
for b := range boards {
boards[b].Dump()
}
// dumpa tutto
for o := range outlets {
outlets[o].Dump()
}
}
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)
}