diff --git a/openpdu_example.yaml b/openpdu_example.yaml index 165e98c..9d9da2b 100644 --- a/openpdu_example.yaml +++ b/openpdu_example.yaml @@ -4,7 +4,8 @@ display: swaptopbottom: false type: ssd1306 w: 128 -hostname: openpdu-rack1 +system: + hostname: openpdu-rack1 mqtt: cliendid: openpdu-main @@ -25,23 +26,24 @@ boards: type: dummy inverted: false channelCount: 4 + name: The Dummy Board channels: 4976c508-1f63-4894-a859-cc5bd555b3c1: num: 0 name: autonomo - startValue: false + onboot: off c0a4d271-2b75-41c0-8b05-86c5ca0b3e94: num: 1 name: fenomeno - startValue: false + onboot: off 4d0b384f-6bcb-4eca-a803-ebea90c2a434: num: 2 name: ecomeno - startValue: false + onboot: off acb5e9d5-959c-4427-a850-17c262b96c16: num: 3 name: ripopolo - startValue: false + onboot: off outlets: 0fca047e-0e7f-4cee-83a8-2086ee306faf: num: 0 diff --git a/src/board.go b/src/board.go index 655a89f..9dfded9 100644 --- a/src/board.go +++ b/src/board.go @@ -9,46 +9,48 @@ import ( ) type Channel struct { - id string - num uint - name string - value bool - inverted bool // low level only - startValue bool - parent *Board + ID string + Num uint + Name 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 + ID string + Name string + ChannelCount uint + Inverted bool // low level only + Channels []Channel } type Outlet struct { - num uint - board *Board - channel *Channel + ID string + Num uint + Description string + Board *Board + Channel *Channel } func (c Channel) Toggle() (bool, error) { - c.value = !c.value - return c.value, nil + c.Value = !c.Value + return c.Value, nil } func (c Channel) On() error { - c.value = true + c.Value = true return nil } func (c Channel) Off() error { - c.value = true + c.Value = true return nil } func (c Channel) Status() bool { - return c.value + return c.Value } var boards []Board @@ -57,17 +59,26 @@ var outlets []Outlet func newDummyChannel(v *viper.Viper, channelID string) Channel { v.SetDefault("name", "unknown") - v.SetDefault("startValue", false) + v.SetDefault("lastValue", false) v.SetDefault("inverted", false) + v.SetDefault("onboot", "off") + + 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"), - value: v.GetBool("startValue"), - inverted: v.GetBool("inverted"), - startValue: v.GetBool("startValue"), + ID: channelID, + Num: v.GetUint("num"), + Name: v.GetString("name"), + Value: value, + Inverted: v.GetBool("inverted"), + OnBoot: v.GetString("onboot"), } } @@ -87,10 +98,10 @@ func newDummyBoard(v *viper.Viper, id string) Board { } b = Board{ - id: id, - name: v.GetString("name"), - channelCount: v.GetUint("channelCount"), - inverted: v.GetBool("inverted"), + ID: id, + Name: v.GetString("name"), + ChannelCount: v.GetUint("channelCount"), + Inverted: v.GetBool("inverted"), } channels := make([]Channel, v.GetInt("channelCount")) @@ -101,16 +112,16 @@ func newDummyBoard(v *viper.Viper, id string) Board { channelid := strings.ToLower(channelid1) channelConfig := channelsConfig.Sub(channelid) c := newDummyChannel(channelConfig, channelid) - c.parent = &b - if c.num >= v.GetUint("channelCount") { + c.Parent = &b + if c.Num >= v.GetUint("channelCount") { continue } - channels[c.num] = c - allChannels[c.id] = &c + channels[c.Num] = c + allChannels[c.ID] = &c } } } - b.channels = channels + b.Channels = channels return b } @@ -139,6 +150,8 @@ func parseBoardsConfig() { } + outlets = make([]Outlet, len(allChannels)) + outletsConfig := viper.Sub("outlets") if outletsConfig == nil { logWarning("No outlet configured") @@ -148,16 +161,20 @@ func parseBoardsConfig() { 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{ - num: num, - board: channel.parent, - channel: channel, + ID: key, + Num: num, + Description: description, + Board: channel.Parent, + Channel: channel, } - outlets = append(outlets, o) + outlets[num] = o } // dumpa tutto @@ -173,20 +190,16 @@ func parseBoardsConfig() { } func (c Channel) Dump() { - v := "off" - if c.startValue { - v = "on" - } - log.Printf(" Channel %d (start: %s): %s \n", c.num, v, c.name) + 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() + 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_ui.go b/src/board_ui.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/src/board_ui.go @@ -0,0 +1 @@ +package main diff --git a/src/main.go b/src/main.go index 66f8817..aba9e23 100644 --- a/src/main.go +++ b/src/main.go @@ -8,14 +8,14 @@ import ( type Dictionary map[string]interface{} func init() { - viper.SetDefault("hostname", "openpdu") + viper.SetDefault("system.hostname", "openpdu") } func main() { parseBoardsConfig() go mqttLoop() go UpsConnect() - logInfo("hostname: " + viper.GetString("hostname")) + logInfo("hostname: " + viper.GetString("system.hostname")) startServer() } diff --git a/src/outlets_ui.go b/src/outlets_ui.go new file mode 100644 index 0000000..e1c9df4 --- /dev/null +++ b/src/outlets_ui.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/spf13/viper" + "gopkg.in/macaron.v1" +) + +func outletsPage(ctx *macaron.Context) { + + ctx.Data["outlets"] = outlets + + ctx.HTML(200, "outlets") +} + +type OutletPostForm struct { + Description string `form:"description" binding:"Required"` + OnBoot string `form:"onboot" binding:"Required"` +} + +func outletEditPage(ctx *macaron.Context) { + var err error + var num uint64 + var o Outlet + num, err = strconv.ParseUint(ctx.Params(":num"), 10, 64) + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "result": "error", + "error": err.Error(), + }) + return + } + + o = outlets[num] + ctx.Data["outlet"] = o + + ctx.Data["onboot_values"] = []string{"on", "off", "last"} + ctx.HTML(200, "outlet_edit") +} + +func outletEditPost(ctx *macaron.Context, f OutletPostForm) { + var err error + var num uint64 + + num, err = strconv.ParseUint(ctx.Params(":num"), 10, 64) + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "result": "error", + "error": err.Error(), + }) + return + } + + onboot := "on" + onbootForm := strings.ToLower(strings.TrimSpace(f.OnBoot)) + switch onbootForm { + case + "on", + "off", + "last": + onboot = onbootForm + default: + 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].Description = strings.TrimSpace(f.Description) + s2 := fmt.Sprintf("outlets.%s.description", outlets[num].ID) + viper.Set(s2, outlets[num].Description) + + viper.WriteConfig() + + ctx.Redirect("/outlets") +} diff --git a/src/webui.go b/src/webui.go index 5ef148a..3f5aceb 100644 --- a/src/webui.go +++ b/src/webui.go @@ -33,7 +33,7 @@ func jsonStatus(ctx *macaron.Context) { var o Outlet for i := range outlets { o = 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, d) } @@ -59,7 +59,7 @@ func jsonOutletToggle(ctx *macaron.Context) { } func init() { - viper.SetDefault("listeningport", 4000) + viper.SetDefault("system.listeningport", 4000) } func startServer() { @@ -69,6 +69,9 @@ func startServer() { // m.Get("/", myHandler) m.Get("/", statusPage) + m.Get("/outlets", outletsPage) + m.Get("/outlet/:num", outletEditPage) + m.Post("/outlet/:num", binding.Bind(OutletPostForm{}), outletEditPost) m.Get("/lan", lanPage) m.Get("/mqtt", mqttPage) m.Post("/mqtt", binding.Bind(MQTTPostForm{}), mqttPost) @@ -83,8 +86,8 @@ func startServer() { ctx.HTML(200, "boards") // 200 is the response code. }) - logInfo("hostname: " + viper.GetString("hostname")) + logInfo("hostname: " + viper.GetString("system.hostname")) logInfo("Web interface ready") - http.ListenAndServe("0.0.0.0:"+viper.GetString("listeningport"), m) + http.ListenAndServe("0.0.0.0:"+viper.GetString("system.listeningport"), m) } diff --git a/templates/common/common-head.html b/templates/common/common-head.html index 5fcc25b..505bd12 100644 --- a/templates/common/common-head.html +++ b/templates/common/common-head.html @@ -4,16 +4,16 @@ - + - + - + - + - + @@ -23,4 +23,4 @@ - \ No newline at end of file + diff --git a/templates/common/common-js.html b/templates/common/common-js.html index 66cfded..e6abab4 100644 --- a/templates/common/common-js.html +++ b/templates/common/common-js.html @@ -1,10 +1,10 @@ - + - + - + - + - + diff --git a/templates/common/sidebar-menu.html b/templates/common/sidebar-menu.html index 9851c36..151c861 100644 --- a/templates/common/sidebar-menu.html +++ b/templates/common/sidebar-menu.html @@ -19,7 +19,7 @@ -
  • +
  • @@ -30,6 +30,10 @@