temp refactor

This commit is contained in:
Paolo Asperti 2021-01-09 19:38:57 +01:00
parent 04d2fac964
commit 1a5819d46f
24 changed files with 809 additions and 328 deletions

View File

@ -1,118 +0,0 @@
package main
import (
"log"
"strings"
MQTT "github.com/eclipse/paho.mqtt.golang"
"github.com/spf13/viper"
)
type Channel interface {
Toggle() (bool, error)
On() error
Off() error
ToString() string
UpdateMQTT()
Status() bool
Parent() Board
Dump()
Name() string
OnBoot() string
SetOnBoot(string)
SetMQTTStateTopic(string)
SetMQTTCommandTopic(string)
MQTTCommandTopic() string
MQTTHandler(MQTT.Client, MQTT.Message)
}
type Board interface {
Init()
Dump()
Channel(uint64) Channel
}
type Outlet struct {
ID string
Num uint
Description string
Channel Channel
}
var boards []Board
var allChannels map[string]Channel
var outlets []*Outlet
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 "mqtt":
b := newMQTTBoard(boardConfig, key)
boards = append(boards, b)
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,
Channel: channel,
}
outlets[num] = &o
}
for b := range boards {
go boards[b].Init()
}
// dumpa tutto
for b := range boards {
boards[b].Dump()
}
// dumpa tutto
for o := range outlets {
outlets[o].Dump()
}
}
func (o *Outlet) Dump() {
log.Printf("Outlet %v: channel name: %v\n", o.Num, o.Channel.Name())
}

57
src/board/board.go Normal file
View File

@ -0,0 +1,57 @@
package board
import (
"errors"
MQTT "github.com/eclipse/paho.mqtt.golang"
"github.com/spf13/viper"
)
var boardCreatorFunctions = make(map[string]BoardCreatorFunction)
var AllChannels = make(map[string]Channel)
type BoardCreatorFunction func(*viper.Viper, string) Board
type onChannelUpdateFunction func(oldValue bool, c Channel)
type Board interface {
Init()
Dump()
Channel(uint64) Channel
}
type Channel interface {
Toggle() (bool, error)
On() error
Off() error
ToString() string
Status() bool
Parent() Board
Dump()
Name() string
OnBoot() string
SetOnBoot(string)
SetMQTTStateTopic(string)
SetMQTTCommandTopic(string)
MQTTStateTopic() string
MQTTCommandTopic() string
MQTTHandler(MQTT.Client, MQTT.Message)
AddOnChannelUpdateFunction(string, onChannelUpdateFunction)
}
func RegisterBoardType(name string, fun BoardCreatorFunction) {
boardCreatorFunctions[name] = fun
}
func CreateBoard(cfg *viper.Viper, key string) (Board, error) {
var createNewBoard BoardCreatorFunction
var ok bool
boardType := cfg.GetString("type")
createNewBoard, ok = boardCreatorFunctions[boardType]
if !ok {
return nil, errors.New("Unknown board type")
}
return createNewBoard(cfg, key), nil
}

View File

@ -1,30 +1,31 @@
package main package board
import ( import (
"fmt" "fmt"
"log" "log"
"strings" "strings"
MQTT "github.com/eclipse/paho.mqtt.golang" PahoMQTT "github.com/eclipse/paho.mqtt.golang"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
type DummyChannel struct { type DummyChannel struct {
ID string ID string
Num uint Num uint
name string name string
MQTTStateTopic string mqttStateTopic string
mqttCommandTopic string mqttCommandTopic string
Value bool Value bool
onboot string onboot string
parent *DummyBoard parent *DummyBoard
onChannelUpdateFunctions map[string]onChannelUpdateFunction
} }
type DummyBoard struct { type DummyBoard struct {
ID string ID string
Name string Name string
ChannelCount uint ChannelCount uint
Channels []*DummyChannel channels []*DummyChannel
} }
func newDummyChannel(v *viper.Viper, channelID string) DummyChannel { func newDummyChannel(v *viper.Viper, channelID string) DummyChannel {
@ -46,14 +47,14 @@ func newDummyChannel(v *viper.Viper, channelID string) DummyChannel {
ID: channelID, ID: channelID,
Num: v.GetUint("num"), Num: v.GetUint("num"),
name: v.GetString("name"), name: v.GetString("name"),
MQTTStateTopic: v.GetString("mqtt.statetopic"), mqttStateTopic: v.GetString("mqtt.statetopic"),
mqttCommandTopic: v.GetString("mqtt.commandtopic"), mqttCommandTopic: v.GetString("mqtt.commandtopic"),
Value: value, Value: value,
onboot: v.GetString("onboot"), onboot: v.GetString("onboot"),
} }
} }
func newDummyBoard(v *viper.Viper, id string) *DummyBoard { func newDummyBoard(v *viper.Viper, id string) Board {
var b DummyBoard var b DummyBoard
v.SetDefault("name", "board "+id) v.SetDefault("name", "board "+id)
@ -86,33 +87,41 @@ func newDummyBoard(v *viper.Viper, id string) *DummyBoard {
continue continue
} }
channels[c.Num] = &c channels[c.Num] = &c
allChannels[c.ID] = &c AllChannels[c.ID] = &c
} }
} }
} }
b.Channels = channels b.channels = channels
return &b return b
} }
func (c *DummyChannel) Toggle() (bool, error) { func (c *DummyChannel) Toggle() (bool, error) {
c.Value = !c.Value c.Value = !c.Value
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](!c.Value, c)
}
return c.Value, nil return c.Value, nil
} }
func (c *DummyChannel) On() error { func (c *DummyChannel) On() error {
oldval := c.Value
c.Value = true c.Value = true
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](oldval, c)
}
return nil return nil
} }
func (c *DummyChannel) Off() error { func (c *DummyChannel) Off() error {
oldval := c.Value
c.Value = true c.Value = true
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](oldval, c)
}
return nil return nil
} }
@ -123,9 +132,9 @@ func (c *DummyChannel) ToString() string {
return "on" return "on"
} }
func (c *DummyChannel) UpdateMQTT() { // func (c *DummyChannel) UpdateMQTT() {
MQTTpublish(c.MQTTStateTopic, c.ToString()) // mqtt.Publish(c.MQTTStateTopic, c.ToString()) // bisogna rimuovere questa
} // }
func (c *DummyChannel) SaveLastState() { func (c *DummyChannel) SaveLastState() {
if c.onboot == "last" { if c.onboot == "last" {
@ -147,19 +156,19 @@ func (c *DummyChannel) Dump() {
log.Printf(" Channel %d (on boot: %s): %s \n", c.Num, c.onboot, c.name) log.Printf(" Channel %d (on boot: %s): %s \n", c.Num, c.onboot, c.name)
} }
func (b *DummyBoard) Dump() { func (b DummyBoard) Dump() {
log.Printf("Board '%s' (id: %s): %d channels\n", b.Name, b.ID, b.ChannelCount) log.Printf("Board '%s' (id: %s): %d channels\n", b.Name, b.ID, b.ChannelCount)
for c := range b.Channels { for c := range b.channels {
b.Channels[c].Dump() b.channels[c].Dump()
} }
} }
func (b *DummyBoard) Init() { func (b DummyBoard) Init() {
return return
} }
func (b *DummyBoard) Channel(num uint64) Channel { func (b DummyBoard) Channel(num uint64) Channel {
return b.Channels[num] return b.channels[num]
} }
func (c *DummyChannel) Name() string { func (c *DummyChannel) Name() string {
@ -177,7 +186,7 @@ func (c *DummyChannel) SetOnBoot(str string) {
} }
func (c *DummyChannel) SetMQTTStateTopic(str string) { func (c *DummyChannel) SetMQTTStateTopic(str string) {
c.MQTTStateTopic = str c.mqttStateTopic = str
s := fmt.Sprintf("boards.%s.channels.%s.mqtt.statetopic", c.parent.ID, c.ID) s := fmt.Sprintf("boards.%s.channels.%s.mqtt.statetopic", c.parent.ID, c.ID)
viper.Set(s, str) viper.Set(s, str)
} }
@ -188,7 +197,7 @@ func (c *DummyChannel) SetMQTTCommandTopic(str string) {
viper.Set(s, str) viper.Set(s, str)
} }
func (c *DummyChannel) MQTTHandler(client MQTT.Client, msg MQTT.Message) { func (c *DummyChannel) MQTTHandler(client PahoMQTT.Client, msg PahoMQTT.Message) {
switch string(msg.Payload()) { switch string(msg.Payload()) {
case "on": case "on":
if !c.Value { if !c.Value {
@ -203,6 +212,21 @@ func (c *DummyChannel) MQTTHandler(client MQTT.Client, msg MQTT.Message) {
} }
} }
func (c *DummyChannel) MQTTStateTopic() string {
return c.mqttStateTopic
}
func (c *DummyChannel) MQTTCommandTopic() string { func (c *DummyChannel) MQTTCommandTopic() string {
return c.mqttCommandTopic return c.mqttCommandTopic
} }
func init() {
RegisterBoardType("dummy", newDummyBoard)
}
func (c *DummyChannel) AddOnChannelUpdateFunction(name string, f onChannelUpdateFunction) {
if c.onChannelUpdateFunctions == nil {
c.onChannelUpdateFunctions = make(map[string]onChannelUpdateFunction)
}
c.onChannelUpdateFunctions[name] = f
}

View File

@ -1,4 +1,4 @@
package main package board
import ( import (
"fmt" "fmt"
@ -6,36 +6,38 @@ import (
"strings" "strings"
"time" "time"
MQTT "github.com/eclipse/paho.mqtt.golang" "git.openpdu.org/OpenPDU/openpdu/syslog"
PahoMQTT "github.com/eclipse/paho.mqtt.golang"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
type MQTTChannel struct { type MQTTChannel struct {
ID string ID string
Num uint Num uint
name string name string
MQTTStateTopic string mqttStateTopic string
mqttCommandTopic string mqttCommandTopic string
Value bool Value bool
onboot string onboot string
parent *MQTTBoard parent *MQTTBoard
MQTTRemoteStateTopic string MQTTRemoteStateTopic string
MQTTRemoteCommandTopic string MQTTRemoteCommandTopic string
MQTTRemotePayloadOn string MQTTRemotePayloadOn string
MQTTRemotePayloadOff string MQTTRemotePayloadOff string
onChannelUpdateFunctions map[string]onChannelUpdateFunction
} }
type MQTTBoard struct { type MQTTBoard struct {
ID string ID string
Name string Name string
ChannelCount uint ChannelCount uint
Channels []*MQTTChannel channels []*MQTTChannel
MQTTRemoteSchema string MQTTRemoteSchema string
MQTTRemoteHost string MQTTRemoteHost string
MQTTRemotePort string MQTTRemotePort string
MQTTRemoteUsername string MQTTRemoteUsername string
MQTTRemotePassword string MQTTRemotePassword string
MQTTClient MQTT.Client MQTTClient PahoMQTT.Client
} }
func newMQTTChannel(v *viper.Viper, channelID string) MQTTChannel { func newMQTTChannel(v *viper.Viper, channelID string) MQTTChannel {
@ -62,7 +64,7 @@ func newMQTTChannel(v *viper.Viper, channelID string) MQTTChannel {
ID: channelID, ID: channelID,
Num: v.GetUint("num"), Num: v.GetUint("num"),
name: v.GetString("name"), name: v.GetString("name"),
MQTTStateTopic: v.GetString("mqtt.statetopic"), mqttStateTopic: v.GetString("mqtt.statetopic"),
mqttCommandTopic: v.GetString("mqtt.commandtopic"), mqttCommandTopic: v.GetString("mqtt.commandtopic"),
Value: value, Value: value,
onboot: v.GetString("onboot"), onboot: v.GetString("onboot"),
@ -73,7 +75,7 @@ func newMQTTChannel(v *viper.Viper, channelID string) MQTTChannel {
} }
} }
func newMQTTBoard(v *viper.Viper, id string) *MQTTBoard { func newMQTTBoard(v *viper.Viper, id string) Board {
var b MQTTBoard var b MQTTBoard
v.SetDefault("name", "board "+id) v.SetDefault("name", "board "+id)
@ -116,35 +118,47 @@ func newMQTTBoard(v *viper.Viper, id string) *MQTTBoard {
continue continue
} }
channels[c.Num] = &c channels[c.Num] = &c
allChannels[c.ID] = &c AllChannels[c.ID] = &c
} }
} }
} }
b.Channels = channels b.channels = channels
return &b return b
}
func init() {
RegisterBoardType("mqtt", newMQTTBoard)
} }
func (c *MQTTChannel) Toggle() (bool, error) { func (c *MQTTChannel) Toggle() (bool, error) {
c.Value = !c.Value c.Value = !c.Value
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](!c.Value, c)
}
c.UpdateRemoteMQTT() c.UpdateRemoteMQTT()
return c.Value, nil return c.Value, nil
} }
func (c *MQTTChannel) On() error { func (c *MQTTChannel) On() error {
oldval := c.Value
c.Value = true c.Value = true
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](oldval, c)
}
c.UpdateRemoteMQTT() c.UpdateRemoteMQTT()
return nil return nil
} }
func (c *MQTTChannel) Off() error { func (c *MQTTChannel) Off() error {
c.Value = true oldval := c.Value
c.Value = false
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](oldval, c)
}
c.UpdateRemoteMQTT() c.UpdateRemoteMQTT()
return nil return nil
} }
@ -156,10 +170,6 @@ func (c *MQTTChannel) ToString() string {
return "on" return "on"
} }
func (c *MQTTChannel) UpdateMQTT() {
MQTTpublish(c.MQTTStateTopic, c.ToString())
}
func (c *MQTTChannel) SaveLastState() { func (c *MQTTChannel) SaveLastState() {
if c.onboot == "last" { if c.onboot == "last" {
s := fmt.Sprintf("boards.%s.channels.%s.lastvalue", c.parent.ID, c.ID) s := fmt.Sprintf("boards.%s.channels.%s.lastvalue", c.parent.ID, c.ID)
@ -169,7 +179,8 @@ func (c *MQTTChannel) SaveLastState() {
} }
func (c *MQTTChannel) UpdateRemoteMQTT() { func (c *MQTTChannel) UpdateRemoteMQTT() {
if c.parent.MQTTClient.IsConnected() { connected := c.parent.MQTTClient.IsConnected()
if connected {
v := c.MQTTRemotePayloadOff v := c.MQTTRemotePayloadOff
if c.Value { if c.Value {
v = c.MQTTRemotePayloadOn v = c.MQTTRemotePayloadOn
@ -190,16 +201,16 @@ func (c *MQTTChannel) Dump() {
log.Printf(" Channel %d (on boot: %s): %s \n", c.Num, c.onboot, c.name) log.Printf(" Channel %d (on boot: %s): %s \n", c.Num, c.onboot, c.name)
} }
func (b *MQTTBoard) Dump() { func (b MQTTBoard) Dump() {
log.Printf("Board '%s' (id: %s): %d channels\n", b.Name, b.ID, b.ChannelCount) log.Printf("Board '%s' (id: %s): %d channels\n", b.Name, b.ID, b.ChannelCount)
for c := range b.Channels { for c := range b.channels {
b.Channels[c].Dump() b.channels[c].Dump()
} }
} }
func (b *MQTTBoard) Init() { func (b MQTTBoard) Init() {
uri := b.MQTTRemoteSchema + "://" + b.MQTTRemoteHost + ":" + b.MQTTRemotePort uri := b.MQTTRemoteSchema + "://" + b.MQTTRemoteHost + ":" + b.MQTTRemotePort
opts := MQTT.NewClientOptions().AddBroker(uri) opts := PahoMQTT.NewClientOptions().AddBroker(uri)
opts.SetClientID(b.ID) opts.SetClientID(b.ID)
@ -215,18 +226,18 @@ func (b *MQTTBoard) Init() {
opts.SetConnectRetryInterval(5 * time.Second) opts.SetConnectRetryInterval(5 * time.Second)
opts.SetConnectTimeout(5 * time.Second) opts.SetConnectTimeout(5 * time.Second)
opts.SetConnectionLostHandler(func(c MQTT.Client, err error) { opts.SetConnectionLostHandler(func(c PahoMQTT.Client, err error) {
logErr("mqtt connection lost error: " + err.Error()) syslog.Err("mqtt connection lost error: " + err.Error())
}) })
opts.SetReconnectingHandler(func(c MQTT.Client, options *MQTT.ClientOptions) { opts.SetReconnectingHandler(func(c PahoMQTT.Client, options *PahoMQTT.ClientOptions) {
logNotice("mqtt reconnecting") syslog.Notice("mqtt reconnecting")
}) })
opts.SetOnConnectHandler(func(c MQTT.Client) { opts.SetOnConnectHandler(func(c PahoMQTT.Client) {
logNotice("mqtt connected") syslog.Notice("mqtt connected")
// MQTTclient.Publish("openpdu/status", 0, false, "connected") // MQTTclient.Publish("openpdu/status", 0, false, "connected")
}) })
b.MQTTClient = MQTT.NewClient(opts) b.MQTTClient = PahoMQTT.NewClient(opts)
for { for {
token := b.MQTTClient.Connect() token := b.MQTTClient.Connect()
@ -237,33 +248,42 @@ func (b *MQTTBoard) Init() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
} }
for i := range b.Channels { for i := range b.channels {
topic := b.Channels[i].MQTTRemoteStateTopic topic := b.channels[i].MQTTRemoteStateTopic
if topic == "" { if topic == "" {
continue continue
} }
b.MQTTClient.Subscribe(topic, 1, b.Channels[i].MQTTRemoteHandler) b.MQTTClient.Subscribe(topic, 1, b.channels[i].MQTTRemoteHandler)
} }
} }
func (c *MQTTChannel) MQTTRemoteHandler(client MQTT.Client, msg MQTT.Message) { func (c *MQTTChannel) MQTTRemoteHandler(client PahoMQTT.Client, msg PahoMQTT.Message) {
switch string(msg.Payload()) { switch string(msg.Payload()) {
case c.MQTTRemotePayloadOn: case c.MQTTRemotePayloadOn:
if !c.Value { if !c.Value {
c.Value = true c.Value = true
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](false, c)
}
} }
case c.MQTTRemotePayloadOff: case c.MQTTRemotePayloadOff:
if c.Value { if c.Value {
c.Value = false c.Value = false
c.SaveLastState() c.SaveLastState()
c.UpdateMQTT() for f := range c.onChannelUpdateFunctions {
c.onChannelUpdateFunctions[f](true, c)
}
} }
} }
} }
func (c *MQTTChannel) MQTTHandler(client MQTT.Client, msg MQTT.Message) { func (c *MQTTChannel) MQTTHandler(client PahoMQTT.Client, msg PahoMQTT.Message) {
syslog.Debug(fmt.Sprintf("Board '%s', channel '%s', received MQTT message %s",
c.parent.Name,
c.name,
string(msg.Payload()),
))
switch string(msg.Payload()) { switch string(msg.Payload()) {
case "on": case "on":
if !c.Value { if !c.Value {
@ -280,8 +300,8 @@ func (c *MQTTChannel) MQTTHandler(client MQTT.Client, msg MQTT.Message) {
} }
} }
func (b *MQTTBoard) Channel(num uint64) Channel { func (b MQTTBoard) Channel(num uint64) Channel {
return b.Channels[num] return b.channels[num]
} }
func (c *MQTTChannel) Name() string { func (c *MQTTChannel) Name() string {
@ -299,7 +319,7 @@ func (c *MQTTChannel) SetOnBoot(str string) {
} }
func (c *MQTTChannel) SetMQTTStateTopic(str string) { func (c *MQTTChannel) SetMQTTStateTopic(str string) {
c.MQTTStateTopic = str c.mqttStateTopic = str
s := fmt.Sprintf("boards.%s.channels.%s.mqtt.statetopic", c.parent.ID, c.ID) s := fmt.Sprintf("boards.%s.channels.%s.mqtt.statetopic", c.parent.ID, c.ID)
viper.Set(s, str) viper.Set(s, str)
} }
@ -310,6 +330,17 @@ func (c *MQTTChannel) SetMQTTCommandTopic(str string) {
viper.Set(s, str) viper.Set(s, str)
} }
func (c *MQTTChannel) MQTTStateTopic() string {
return c.mqttStateTopic
}
func (c *MQTTChannel) MQTTCommandTopic() string { func (c *MQTTChannel) MQTTCommandTopic() string {
return c.mqttCommandTopic return c.mqttCommandTopic
} }
func (c *MQTTChannel) AddOnChannelUpdateFunction(name string, f onChannelUpdateFunction) {
if c.onChannelUpdateFunctions == nil {
c.onChannelUpdateFunctions = make(map[string]onChannelUpdateFunction)
}
c.onChannelUpdateFunctions[name] = f
}

54
src/boards.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"git.openpdu.org/OpenPDU/openpdu/board"
"git.openpdu.org/OpenPDU/openpdu/mqtt"
"git.openpdu.org/OpenPDU/openpdu/syslog"
"github.com/spf13/viper"
)
var boards []*board.Board
func InitBoards() {
// AllChannels = make(map[string]Channel)
boardsConfig := viper.Sub("boards")
if boardsConfig == nil {
syslog.Warning("No board configured")
return
}
for key := range boardsConfig.AllSettings() {
boardConfig := boardsConfig.Sub(key)
boardConfig.SetDefault("type", "dummy")
b, err := board.CreateBoard(boardConfig, key)
if err == nil {
boards = append(boards, &b)
}
}
for i := range board.AllChannels {
board.AllChannels[i].AddOnChannelUpdateFunction(
"mqtt-publish",
func(oldValue bool, c board.Channel) {
mqtt.Publish(c.MQTTStateTopic(), c.ToString())
})
}
// TODO: init boards array?
// outlets = make([]*Outlet, len(allChannels))
// // dumpa tutto
// for b := range boards {
// boards[b].Dump()
// }
// // dumpa tutto
// for o := range outlets {
// outlet.Outlets[o].Dump()
// }
}

View File

@ -1,8 +1,9 @@
package main package main
import ( import (
"log" "fmt"
"git.openpdu.org/OpenPDU/openpdu/syslog"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@ -13,6 +14,6 @@ func init() {
viper.AddConfigPath("/etc/openpdu/") // path to look for the config file in viper.AddConfigPath("/etc/openpdu/") // path to look for the config file in
err := viper.ReadInConfig() // Find and read the config file err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file if err != nil { // Handle errors reading the config file
log.Printf("Can't read config file: %s \n", err) syslog.Err(fmt.Sprintf("Can't read config file: %s \n", err.Error()))
} }
} }

View File

@ -6,37 +6,37 @@ import (
"net" "net"
"time" "time"
"git.openpdu.org/OpenPDU/openpdu/syslog"
"github.com/spf13/viper" "github.com/spf13/viper"
"golang.org/x/image/font" "golang.org/x/image/font"
"golang.org/x/image/font/basicfont" "golang.org/x/image/font/basicfont"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
"periph.io/x/periph/devices/ssd1306" "periph.io/x/periph/devices/ssd1306"
) )
func init() { func init() {
logInfo("display setup") syslog.Info("display setup")
viper.SetDefault("Display.Type", "none") viper.SetDefault("Display.Type", "none")
viper.SetDefault("Display.W", 128) viper.SetDefault("Display.W", 128)
viper.SetDefault("Display.H", 32) viper.SetDefault("Display.H", 32)
viper.SetDefault("Display.Rotated", false) viper.SetDefault("Display.Rotated", false)
viper.SetDefault("Display.SwapTopBottom", false) viper.SetDefault("Display.SwapTopBottom", false)
go displayLoop() go displayLoop()
logInfo("display setup completed") syslog.Info("display setup completed")
} }
func displayLoop() { func displayLoop() {
for { for {
logInfo("ssd1306 display starting loop") syslog.Info("ssd1306 display starting loop")
if viper.GetString("Display.Type") != "ssd1306" { if viper.GetString("Display.Type") != "ssd1306" {
logWarning("ssd1306 disabled") syslog.Warning("ssd1306 disabled")
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
continue continue
} }
if i2cbus == nil { if i2cbus == nil {
logWarning("ssd1306 i2cbus not found") syslog.Warning("ssd1306 i2cbus not found")
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
continue continue
} }
@ -52,17 +52,17 @@ func displayLoop() {
// Open a handle to a ssd1306 connected on the I²C bus: // Open a handle to a ssd1306 connected on the I²C bus:
dev, err := ssd1306.NewI2C(i2cbus, &opts) dev, err := ssd1306.NewI2C(i2cbus, &opts)
if err != nil { if err != nil {
logErr(err.Error()) syslog.Err(err.Error())
} }
logInfo("ssd1306 display setup completed") syslog.Info("ssd1306 display setup completed")
for { for {
err := disp(dev) err := disp(dev)
if err != nil { if err != nil {
logErr(err.Error()) syslog.Err(err.Error())
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
logWarning("ssd1306 display disp error") syslog.Warning("ssd1306 display disp error")
continue continue
} }
} }

17
src/go.mod Normal file
View File

@ -0,0 +1,17 @@
module git.openpdu.org/OpenPDU/openpdu
go 1.15
require (
github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91
github.com/eclipse/paho.mqtt.golang v1.3.1
github.com/go-macaron/binding v1.1.1
github.com/go-macaron/pongo2 v0.0.0-20200329073512-6ca146b415a1
github.com/robbiet480/go.nut v0.0.0-20200921180721-77b33bf222d9
github.com/spf13/viper v1.7.1
golang.org/x/image v0.0.0-20201208152932-35266b937fa6
gopkg.in/macaron.v1 v1.4.0
periph.io/x/periph v3.6.7+incompatible
)
replace git.openpdu.org/OpenPDU/openpdu => ./src

337
src/go.sum Normal file
View File

@ -0,0 +1,337 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91 h1:vX+gnvBc56EbWYrmlhYbFYRaeikAke1GL84N4BEYOFE=
github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91/go.mod h1:cDLGBht23g0XQdLjzn6xOGXDkLK182YfINAaZEQLCHQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/eclipse/paho.mqtt.golang v1.3.1 h1:6F5FYb1hxVSZS+p0ji5xBQamc5ltOolTYRy5R15uVmI=
github.com/eclipse/paho.mqtt.golang v1.3.1/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-macaron/binding v1.1.1 h1:agcYYn3FDj5YQ43CkVRMZ74M2BdqP/X1ut5+hVi8anI=
github.com/go-macaron/binding v1.1.1/go.mod h1:dJU/AtPKG0gUiFra1K5TTGduFGMNxMvfJzV/zmXwyGM=
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI=
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw=
github.com/go-macaron/pongo2 v0.0.0-20200329073512-6ca146b415a1 h1:WmSEGPUZkHtelzgoDBaZiJR03+5UZhr63ayrosbVY2Q=
github.com/go-macaron/pongo2 v0.0.0-20200329073512-6ca146b415a1/go.mod h1:H7wnGulppt0tQHvcfv5IoExZQsPYSfE+ywHk7ZB2nXU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/robbiet480/go.nut v0.0.0-20200921180721-77b33bf222d9 h1:9c1FT5MC79I6C9mF6EgnyIzBpr/glQk6VaJadZ/uL3w=
github.com/robbiet480/go.nut v0.0.0-20200921180721-77b33bf222d9/go.mod h1:pL1huxuIlWub46MsMVJg4p7OXkzbPp/APxh9IH0eJjQ=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190805222050-c5a2fd39b72a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/macaron.v1 v1.3.5/go.mod h1:uMZCFccv9yr5TipIalVOyAyZQuOH3OkmXvgcWwhJuP4=
gopkg.in/macaron.v1 v1.4.0 h1:RJHC09fAnQ8tuGUiZNjG0uyL1BWSdSWd9SpufIcEArQ=
gopkg.in/macaron.v1 v1.4.0/go.mod h1:uMZCFccv9yr5TipIalVOyAyZQuOH3OkmXvgcWwhJuP4=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
periph.io/x/periph v3.6.7+incompatible h1:ZfRdHbcxVekgSJZmxp3873YpxNdWs6wg7waDCF7GB18=
periph.io/x/periph v3.6.7+incompatible/go.mod h1:EWr+FCIU2dBWz5/wSWeiIUJTriYv9v2j2ENBmgYyy7Y=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"git.openpdu.org/OpenPDU/openpdu/syslog"
"periph.io/x/periph/conn/i2c" "periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/i2c/i2creg" "periph.io/x/periph/conn/i2c/i2creg"
"periph.io/x/periph/host" "periph.io/x/periph/host"
@ -78,21 +79,21 @@ func (b I2CBoard) channelToggle(ch uint) error {
func init() { func init() {
var err error var err error
logInfo("i2c setup") syslog.Info("i2c setup")
// Make sure periph is initialized. // Make sure periph is initialized.
if _, err = host.Init(); err != nil { if _, err = host.Init(); err != nil {
logErr(err.Error()) syslog.Err(err.Error())
} }
// Use i2creg I²C bus registry to find the first available I²C bus. // Use i2creg I²C bus registry to find the first available I²C bus.
// i2cbus, err = i2creg.Open("/dev/i2c-1") // i2cbus, err = i2creg.Open("/dev/i2c-1")
i2cbus, err = i2creg.Open("") i2cbus, err = i2creg.Open("")
if err != nil { if err != nil {
logErr(err.Error()) syslog.Err(err.Error())
} }
logInfo("i2c setup completed") syslog.Info("i2c setup completed")
} }
func initI2C() { func initI2C() {
@ -105,7 +106,7 @@ func initI2C() {
// read := make([]byte, 5) // read := make([]byte, 5)
// if err := d.Tx(write, read); err != nil { // if err := d.Tx(write, read); err != nil {
if _, err := mydevice.Write(write); err != nil { if _, err := mydevice.Write(write); err != nil {
logErr(err.Error()) syslog.Err(err.Error())
} }
MyBoard.i2cdev = *mydevice MyBoard.i2cdev = *mydevice
@ -116,9 +117,9 @@ func initI2C() {
for i = 0; i < 8; i++ { for i = 0; i < 8; i++ {
v, err := MyBoard.channelStatus(i) v, err := MyBoard.channelStatus(i)
if err != nil { if err != nil {
logErr(err.Error()) syslog.Err(err.Error())
} }
logInfo(fmt.Sprintf("Channel %d status: %v", i, v)) syslog.Info(fmt.Sprintf("Channel %d status: %v", i, v))
} }
}() }()
} }

View File

@ -1,22 +1,24 @@
package main package main
import ( import (
"git.openpdu.org/OpenPDU/openpdu/syslog"
"git.openpdu.org/OpenPDU/openpdu/ups"
"git.openpdu.org/OpenPDU/openpdu/webui"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
// Dictionary aaa
type Dictionary map[string]interface{}
func init() { func init() {
viper.SetDefault("system.hostname", "openpdu") viper.SetDefault("system.hostname", "openpdu")
} }
func main() { func main() {
parseBoardsConfig() InitBoards()
go mqttLoop() InitOutlets()
go UpsConnect() MQTTSetup()
logInfo("hostname: " + viper.GetString("system.hostname")) go MQTTRefreshLoop()
startServer() go ups.UpsConnect()
syslog.Info("hostname: " + viper.GetString("system.hostname"))
webui.StartServer()
} }
// https://github.com/ColorlibHQ/AdminLTE/archive/v2.4.17.tar.gz // https://github.com/ColorlibHQ/AdminLTE/archive/v2.4.17.tar.gz

View File

@ -1,8 +1,10 @@
package main package mqtt
import ( import (
"fmt"
"time" "time"
"git.openpdu.org/OpenPDU/openpdu/syslog"
MQTT "github.com/eclipse/paho.mqtt.golang" MQTT "github.com/eclipse/paho.mqtt.golang"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@ -23,13 +25,11 @@ func init() {
// MQTT.WARN = log.New(os.Stdout, "[WARN] ", 0) // MQTT.WARN = log.New(os.Stdout, "[WARN] ", 0)
// MQTT.DEBUG = log.New(os.Stdout, "[DEBUG] ", 0) // MQTT.DEBUG = log.New(os.Stdout, "[DEBUG] ", 0)
//MQTTclient.Subscribe("some_topic", 0, nil);
//MQTTclient.Disconnect(250)
} }
// https://girishjoshi.io/post/golang-paho-mqtt/ // https://girishjoshi.io/post/golang-paho-mqtt/
func mqttLoop() { func Setup() {
uri := viper.GetString("Mqtt.Schema") + "://" + viper.GetString("Mqtt.Host") + ":" + viper.GetString("Mqtt.Port") uri := viper.GetString("Mqtt.Schema") + "://" + viper.GetString("Mqtt.Host") + ":" + viper.GetString("Mqtt.Port")
opts := MQTT.NewClientOptions().AddBroker(uri) opts := MQTT.NewClientOptions().AddBroker(uri)
@ -48,13 +48,13 @@ func mqttLoop() {
opts.SetConnectTimeout(5 * time.Second) opts.SetConnectTimeout(5 * time.Second)
opts.SetConnectionLostHandler(func(c MQTT.Client, err error) { opts.SetConnectionLostHandler(func(c MQTT.Client, err error) {
logErr("mqtt connection lost error: " + err.Error()) syslog.Err("mqtt connection lost error: " + err.Error())
}) })
opts.SetReconnectingHandler(func(c MQTT.Client, options *MQTT.ClientOptions) { opts.SetReconnectingHandler(func(c MQTT.Client, options *MQTT.ClientOptions) {
logNotice("mqtt reconnecting") syslog.Notice("mqtt reconnecting")
}) })
opts.SetOnConnectHandler(func(c MQTT.Client) { opts.SetOnConnectHandler(func(c MQTT.Client) {
logNotice("mqtt connected") syslog.Notice("mqtt connected")
// MQTTclient.Publish("openpdu/status", 0, false, "connected") // MQTTclient.Publish("openpdu/status", 0, false, "connected")
}) })
@ -69,39 +69,24 @@ func mqttLoop() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
} }
for o := range outlets {
topic := outlets[o].Channel.MQTTCommandTopic()
if topic == "" {
continue
}
MQTTclient.Subscribe(viper.GetString("Mqtt.Prefix")+"/"+topic, 1, outlets[o].Channel.MQTTHandler)
}
go MQTTRefreshLoop()
} }
func MQTTreconfigure() { func Subscribe(topic string, handler func(MQTT.Client, MQTT.Message)) {
if MQTTclient.IsConnected() { // MQTTHandler(MQTT.Client, MQTT.Message)
MQTTclient.Disconnect(250) MQTTclient.Subscribe(viper.GetString("Mqtt.Prefix")+"/"+topic, 1, handler)
} syslog.Debug(fmt.Sprintf("MQTT subscribed to topic: %s", topic))
go mqttLoop()
} }
func MQTTpublish(topic string, value string) { func Connected() bool {
return MQTTclient.IsConnected()
}
func Disconnect() {
MQTTclient.Disconnect(250)
}
func Publish(topic string, value string) {
if MQTTclient.IsConnected() { if MQTTclient.IsConnected() {
MQTTclient.Publish(viper.GetString("Mqtt.Prefix")+"/"+topic, 0, false, value) MQTTclient.Publish(viper.GetString("Mqtt.Prefix")+"/"+topic, 0, false, value)
} }
} }
func MQTTRefreshLoop() {
for {
MQTTRefresh()
time.Sleep(30 * time.Second)
}
}
func MQTTRefresh() {
for o := range outlets {
outlets[o].Channel.UpdateMQTT()
}
}

20
src/outlet/outlet.go Normal file
View File

@ -0,0 +1,20 @@
package outlet
import (
"log"
"git.openpdu.org/OpenPDU/openpdu/board"
)
type Outlet struct {
ID string
Num uint
Description string
Channel board.Channel
}
var Outlets []*Outlet
func (o *Outlet) Dump() {
log.Printf("Outlet %v: channel name: %v\n", o.Num, o.Channel.Name())
}

71
src/outlets.go Normal file
View File

@ -0,0 +1,71 @@
package main
import (
"strings"
"time"
"git.openpdu.org/OpenPDU/openpdu/board"
"git.openpdu.org/OpenPDU/openpdu/mqtt"
"git.openpdu.org/OpenPDU/openpdu/outlet"
"git.openpdu.org/OpenPDU/openpdu/syslog"
"github.com/spf13/viper"
)
func InitOutlets() {
outletsConfig := viper.Sub("outlets")
if outletsConfig == nil {
syslog.Warning("No outlet configured")
return
}
outlet.Outlets = make([]*outlet.Outlet, len(board.AllChannels))
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 := board.AllChannels[channelID]
// TODO: channel non esistente
o := outlet.Outlet{
ID: key,
Num: num,
Description: description,
Channel: channel,
}
outlet.Outlets[num] = &o
}
}
func MQTTSetup() {
mqtt.Setup()
for o := range outlet.Outlets {
topic := outlet.Outlets[o].Channel.MQTTCommandTopic()
if topic == "" {
continue
}
mqtt.Subscribe(topic, outlet.Outlets[o].Channel.MQTTHandler)
}
}
func MQTTreconfigure() {
if mqtt.Connected() {
mqtt.Disconnect()
}
MQTTSetup()
go MQTTRefreshLoop()
}
func MQTTRefreshLoop() {
for {
for o := range outlet.Outlets {
topic := outlet.Outlets[o].Channel.MQTTStateTopic()
value := outlet.Outlets[o].Channel.ToString()
mqtt.Publish(topic, value)
}
time.Sleep(30 * time.Second)
}
}

View File

@ -1,17 +1,17 @@
package main package syslog
import ( import (
"log" "log"
syslog "github.com/RackSec/srslog" "github.com/RackSec/srslog"
) )
var logger *syslog.Writer var logger *srslog.Writer
func init() { func init() {
var err error var err error
logger, err = syslog.Dial("", "", syslog.LOG_ERR, "openpdu") logger, err = srslog.Dial("", "", srslog.LOG_ERR, "openpdu")
// w, err := syslog.Dial("udp", "192.168.0.50:514", syslog.LOG_ERR, "openpdu") // w, err := syslog.Dial("udp", "192.168.0.50:514", syslog.LOG_ERR, "openpdu")
@ -19,17 +19,9 @@ func init() {
log.Fatal("failed to connect to syslog:", err) log.Fatal("failed to connect to syslog:", err)
} }
// logger.Alert("this is an alert")
// logger.Crit("this is critical")
// logger.Err("this is an error")
// logger.Warning("this is a warning")
// logger.Notice("this is a notice")
// logger.Info("this is info")
// logger.Debug("this is debug")
// logger.Write([]byte("these are some bytes"))
} }
func logAlert(msg string) { func Alert(msg string) {
if logger == nil { if logger == nil {
log.Printf(msg) log.Printf(msg)
} else { } else {
@ -37,7 +29,7 @@ func logAlert(msg string) {
} }
} }
func logCrit(msg string) { func Crit(msg string) {
if logger == nil { if logger == nil {
log.Printf(msg) log.Printf(msg)
} else { } else {
@ -45,7 +37,7 @@ func logCrit(msg string) {
} }
} }
func logErr(msg string) { func Err(msg string) {
if logger == nil { if logger == nil {
log.Printf(msg) log.Printf(msg)
} else { } else {
@ -53,7 +45,7 @@ func logErr(msg string) {
} }
} }
func logWarning(msg string) { func Warning(msg string) {
if logger == nil { if logger == nil {
log.Printf(msg) log.Printf(msg)
} else { } else {
@ -61,7 +53,7 @@ func logWarning(msg string) {
} }
} }
func logNotice(msg string) { func Notice(msg string) {
if logger == nil { if logger == nil {
log.Printf(msg) log.Printf(msg)
} else { } else {
@ -69,7 +61,7 @@ func logNotice(msg string) {
} }
} }
func logInfo(msg string) { func Info(msg string) {
if logger == nil { if logger == nil {
log.Printf(msg) log.Printf(msg)
} else { } else {
@ -77,10 +69,9 @@ func logInfo(msg string) {
} }
} }
func logDebug(msg string) { func Debug(msg string) {
if logger == nil { if logger == nil {
log.Printf(msg) log.Printf(msg)
} else {
logger.Debug(msg)
} }
logger.Debug(msg)
} }

View File

@ -1,13 +1,14 @@
package main package ups
import ( import (
"git.openpdu.org/OpenPDU/openpdu/syslog"
nut "github.com/robbiet480/go.nut" nut "github.com/robbiet480/go.nut"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
var upsClient nut.Client var upsClient nut.Client
var ups nut.UPS var ups nut.UPS
var upsVars map[string]nut.Variable var Vars map[string]nut.Variable
func init() { func init() {
viper.SetDefault("Ups.Host", "localhost") viper.SetDefault("Ups.Host", "localhost")
@ -23,7 +24,7 @@ func UpsConnect() {
upsClient, connectErr = nut.Connect(viper.GetString("Ups.Host")) upsClient, connectErr = nut.Connect(viper.GetString("Ups.Host"))
if connectErr != nil { if connectErr != nil {
logErr(connectErr.Error()) syslog.Err(connectErr.Error())
return return
} }
@ -36,35 +37,35 @@ func UpsConnect() {
_, authenticationError = upsClient.Authenticate(username, password) _, authenticationError = upsClient.Authenticate(username, password)
if authenticationError != nil { if authenticationError != nil {
logErr(authenticationError.Error()) syslog.Err(authenticationError.Error())
return return
} }
upsList, listErr := upsClient.GetUPSList() upsList, listErr := upsClient.GetUPSList()
if listErr != nil { if listErr != nil {
logErr(listErr.Error()) syslog.Err(listErr.Error())
return return
} }
for _, u = range upsList { for _, u = range upsList {
if u.Name == viper.GetString("Ups.Name") { if u.Name == viper.GetString("Ups.Name") {
ups = u ups = u
logNotice("UPS connected") syslog.Notice("UPS connected")
UpsReadVars() UpsReadVars()
} }
} }
} }
func UpsReadVars() { func UpsReadVars() {
upsVars = map[string]nut.Variable{} Vars = map[string]nut.Variable{}
for _, v := range ups.Variables { for _, v := range ups.Variables {
upsVars[v.Name] = v Vars[v.Name] = v
} }
} }
func UpsReconfigure() { func Reconfigure() {
ups = nut.UPS{} ups = nut.UPS{}
upsClient = nut.Client{} upsClient = nut.Client{}
logNotice("UPS disconnected") syslog.Notice("UPS disconnected")
go UpsConnect() go UpsConnect()
} }

View File

@ -1,4 +1,4 @@
package main package webui
import "gopkg.in/macaron.v1" import "gopkg.in/macaron.v1"

View File

@ -1,4 +1,4 @@
package main package webui
import "gopkg.in/macaron.v1" import "gopkg.in/macaron.v1"

View File

@ -1,4 +1,4 @@
package main package webui
import ( import (
"strings" "strings"

View File

@ -1,4 +1,4 @@
package main package webui
import ( import (
"fmt" "fmt"
@ -6,13 +6,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.openpdu.org/OpenPDU/openpdu/outlet"
"github.com/spf13/viper" "github.com/spf13/viper"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
) )
func outletsPage(ctx *macaron.Context) { func outletsPage(ctx *macaron.Context) {
ctx.Data["outlets"] = outlets ctx.Data["outlets"] = outlet.Outlets
ctx.HTML(200, "outlets") ctx.HTML(200, "outlets")
} }
@ -27,7 +28,7 @@ type OutletPostForm struct {
func outletEditPage(ctx *macaron.Context) { func outletEditPage(ctx *macaron.Context) {
var err error var err error
var num uint64 var num uint64
var o *Outlet var o *outlet.Outlet
num, err = strconv.ParseUint(ctx.Params(":num"), 10, 64) num, err = strconv.ParseUint(ctx.Params(":num"), 10, 64)
if err != nil { if err != nil {
ctx.JSON(http.StatusOK, Dictionary{ ctx.JSON(http.StatusOK, Dictionary{
@ -37,7 +38,7 @@ func outletEditPage(ctx *macaron.Context) {
return return
} }
o = outlets[num] o = outlet.Outlets[num]
ctx.Data["outlet"] = o ctx.Data["outlet"] = o
ctx.Data["onboot_values"] = []string{"on", "off", "last"} ctx.Data["onboot_values"] = []string{"on", "off", "last"}
@ -69,23 +70,23 @@ func outletEditPost(ctx *macaron.Context, f OutletPostForm) {
outletsPage(ctx) outletsPage(ctx)
return return
} }
outlets[num].Channel.SetOnBoot(onboot) outlet.Outlets[num].Channel.SetOnBoot(onboot)
outlets[num].Description = strings.TrimSpace(f.Description) outlet.Outlets[num].Description = strings.TrimSpace(f.Description)
s2 := fmt.Sprintf("outlets.%s.description", outlets[num].ID) s2 := fmt.Sprintf("outlets.%s.description", outlet.Outlets[num].ID)
viper.Set(s2, outlets[num].Description) viper.Set(s2, outlet.Outlets[num].Description)
mqttstate := strings.TrimSpace(f.MQTTStateTopic) mqttstate := strings.TrimSpace(f.MQTTStateTopic)
if mqttstate == "" { if mqttstate == "" {
mqttstate = outlets[num].Channel.Name() mqttstate = outlet.Outlets[num].Channel.Name()
} }
outlets[num].Channel.SetMQTTStateTopic(mqttstate) outlet.Outlets[num].Channel.SetMQTTStateTopic(mqttstate)
mqttcommand := strings.TrimSpace(f.MQTTCommandTopic) mqttcommand := strings.TrimSpace(f.MQTTCommandTopic)
if mqttcommand == "" { if mqttcommand == "" {
mqttcommand = outlets[num].Channel.Name() mqttcommand = outlet.Outlets[num].Channel.Name()
} }
outlets[num].Channel.SetMQTTCommandTopic(mqttcommand) outlet.Outlets[num].Channel.SetMQTTCommandTopic(mqttcommand)
viper.WriteConfig() viper.WriteConfig()

View File

@ -1,9 +1,10 @@
package main package webui
import ( import (
"net/http" "net/http"
"strconv" "strconv"
"git.openpdu.org/OpenPDU/openpdu/outlet"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
) )
@ -15,9 +16,9 @@ func jsonStatus(ctx *macaron.Context) {
// MQTTpublish("openpdu/status", "asdss") // MQTTpublish("openpdu/status", "asdss")
var data = make([]Dictionary, 0) var data = make([]Dictionary, 0)
var o *Outlet var o *outlet.Outlet
for i := range outlets { for i := range outlet.Outlets {
o = outlets[i] o = outlet.Outlets[i]
// d := []string{fmt.Sprintf("%d", o.Num), o.Channel.Name, fmt.Sprintf("%v", o.Channel.Value)} // d := []string{fmt.Sprintf("%d", o.Num), o.Channel.Name, fmt.Sprintf("%v", o.Channel.Value)}
data = append(data, Dictionary{ data = append(data, Dictionary{
"Num": o.Num, "Num": o.Num,
@ -34,7 +35,7 @@ func jsonStatus(ctx *macaron.Context) {
func jsonOutletToggle(ctx *macaron.Context) { func jsonOutletToggle(ctx *macaron.Context) {
var err error var err error
var num uint64 var num uint64
var outlet *Outlet var o *outlet.Outlet
num, err = strconv.ParseUint(ctx.Params(":id"), 10, 64) num, err = strconv.ParseUint(ctx.Params(":id"), 10, 64)
if err != nil { if err != nil {
@ -43,14 +44,14 @@ func jsonOutletToggle(ctx *macaron.Context) {
}) })
} }
if num >= uint64(len(outlets)) || num < 0 { if num >= uint64(len(outlet.Outlets)) || num < 0 {
ctx.JSON(http.StatusOK, Dictionary{ ctx.JSON(http.StatusOK, Dictionary{
"data": "error2", "data": "error2",
}) })
} }
outlet = outlets[num] o = outlet.Outlets[num]
_, err = outlet.Channel.Toggle() _, err = o.Channel.Toggle()
if err != nil { if err != nil {
ctx.JSON(http.StatusOK, Dictionary{ ctx.JSON(http.StatusOK, Dictionary{
"data": "error3", "data": "error3",

View File

@ -1,4 +1,4 @@
package main package webui
import "gopkg.in/macaron.v1" import "gopkg.in/macaron.v1"

View File

@ -1,8 +1,9 @@
package main package webui
import ( import (
"strings" "strings"
"git.openpdu.org/OpenPDU/openpdu/ups"
"github.com/spf13/viper" "github.com/spf13/viper"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
) )
@ -18,12 +19,12 @@ func upsPage(ctx *macaron.Context) {
// ctx.Data["upsstatus"] = "unknown" // ctx.Data["upsstatus"] = "unknown"
// } else { // } else {
ctx.Data["serverstatus"] = "Connected" ctx.Data["serverstatus"] = "Connected"
ctx.Data["upsstatus"] = upsVars["ups.status"].Value ctx.Data["upsstatus"] = ups.Vars["ups.status"].Value
ctx.Data["upsmfr"] = upsVars["device.mfr"].Value ctx.Data["upsmfr"] = ups.Vars["device.mfr"].Value
ctx.Data["upsmodel"] = upsVars["device.model"].Value ctx.Data["upsmodel"] = ups.Vars["device.model"].Value
ctx.Data["upsserial"] = upsVars["device.serial"].Value ctx.Data["upsserial"] = ups.Vars["device.serial"].Value
ctx.Data["upsload"] = upsVars["ups.load"].Value ctx.Data["upsload"] = ups.Vars["ups.load"].Value
ctx.Data["upscharge"] = upsVars["battery.charge"].Value ctx.Data["upscharge"] = ups.Vars["battery.charge"].Value
// } // }
@ -44,7 +45,7 @@ func upsPost(ctx *macaron.Context, f UPSPostForm) {
viper.Set("Ups.Password", f.Password) viper.Set("Ups.Password", f.Password)
viper.WriteConfig() viper.WriteConfig()
UpsReconfigure() ups.Reconfigure()
upsPage(ctx) upsPage(ctx)
} }

View File

@ -1,19 +1,23 @@
package main package webui
import ( import (
"net/http" "net/http"
"git.openpdu.org/OpenPDU/openpdu/syslog"
"github.com/go-macaron/binding" "github.com/go-macaron/binding"
"github.com/go-macaron/pongo2" "github.com/go-macaron/pongo2"
"github.com/spf13/viper" "github.com/spf13/viper"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
) )
// Dictionary aaa
type Dictionary map[string]interface{}
func init() { func init() {
viper.SetDefault("system.listeningport", 4000) viper.SetDefault("system.listeningport", 4000)
} }
func startServer() { func StartServer() {
m := macaron.Classic() m := macaron.Classic()
m.Use(pongo2.Pongoer()) m.Use(pongo2.Pongoer())
m.Use(macaron.Static("static")) m.Use(macaron.Static("static"))
@ -32,6 +36,6 @@ func startServer() {
m.Get("/json/status", jsonStatus) m.Get("/json/status", jsonStatus)
m.Post("/json/outlet/:id/toggle", jsonOutletToggle) m.Post("/json/outlet/:id/toggle", jsonOutletToggle)
logInfo("Web interface ready") syslog.Info("Web interface ready")
http.ListenAndServe("0.0.0.0:"+viper.GetString("system.listeningport"), m) http.ListenAndServe("0.0.0.0:"+viper.GetString("system.listeningport"), m)
} }