From fb819a71c4d2394aa546281a08675642c2eea284 Mon Sep 17 00:00:00 2001 From: paspo Date: Sun, 27 Oct 2019 22:39:00 +0100 Subject: [PATCH] go on --- t/board.go | 88 ++++++++++++++++ t/boardlink.go | 45 +++++++++ t/config.go | 41 ++++++++ t/main.go | 36 +++++++ t/mock.go | 102 +++++++++++++++++++ t/mqtt.go | 13 +++ t/outlet.go | 49 +++++++++ t/t.go | 270 ------------------------------------------------- t/web.go | 29 ++++++ t/webjson.go | 129 +++++++++++++++++++++++ t/webpages.go | 14 +++ 11 files changed, 546 insertions(+), 270 deletions(-) create mode 100644 t/board.go create mode 100644 t/boardlink.go create mode 100644 t/config.go create mode 100644 t/main.go create mode 100644 t/mock.go create mode 100644 t/mqtt.go create mode 100644 t/outlet.go delete mode 100644 t/t.go create mode 100644 t/web.go create mode 100644 t/webjson.go create mode 100644 t/webpages.go diff --git a/t/board.go b/t/board.go new file mode 100644 index 0000000..36221c7 --- /dev/null +++ b/t/board.go @@ -0,0 +1,88 @@ +package main + +import "log" + +// BoardType Status +const ( + BoardTypeDummy uint = 0 + BoardTypeGPIO uint = 1 + BoardTypeI2CGPIO uint = 2 + BoardTypeI2CADC uint = 3 +) + +// Board def +type Board struct { + ChannelCount uint `json:"channelcount"` + ID string `json:"id"` + Name string `json:"name"` + Type uint `json:"type"` + Bus uint `json:"bus"` + Address uint `json:"address"` + dummyValue map[uint]bool +} + +// ChannelName - return the name of a channel, useful for onboard GPIO +func (b *Board) ChannelName(num uint) string { + return string(num) +} + +// PowerON def +func (b *Board) PowerON(num uint) error { + switch b.Type { + case BoardTypeDummy: + if b.dummyValue == nil { + b.dummyValue = make(map[uint]bool) + } + b.dummyValue[num] = true + return nil + } + + return nil +} + +// PowerOFF def +func (b *Board) PowerOFF(num uint) error { + switch b.Type { + case BoardTypeDummy: + if b.dummyValue == nil { + b.dummyValue = make(map[uint]bool) + } + b.dummyValue[num] = false + return nil + } + return nil +} + +// PowerToggle def +func (b *Board) PowerToggle(num uint) error { + switch b.Type { + case BoardTypeDummy: + if b.dummyValue == nil { + b.dummyValue = make(map[uint]bool) + } + v, _ := b.PowerStatus(num) + log.Printf("toggle prestatus %v:%v", num, b.dummyValue[num]) + b.dummyValue[num] = !v + log.Printf("toggle poststatus %v:%v", num, b.dummyValue[num]) + return nil + } + return nil +} + +// PowerStatus def +func (b *Board) PowerStatus(num uint) (bool, error) { + switch b.Type { + case BoardTypeDummy: + if b.dummyValue == nil { + b.dummyValue = make(map[uint]bool) + } + val, ok := b.dummyValue[num] + if !ok { + b.dummyValue[num] = true + val = true + } + log.Printf("status %v:%v", num, val) + return val, nil + } + return false, nil +} diff --git a/t/boardlink.go b/t/boardlink.go new file mode 100644 index 0000000..c69da48 --- /dev/null +++ b/t/boardlink.go @@ -0,0 +1,45 @@ +package main + +// Boardlink def +type Boardlink struct { + BoardID string `json:"boardid"` + Channel uint `json:"channel"` + board Board +} + +// Board def +func (bl Boardlink) Board() Board { + if bl.board.ID == "" { + for i := range TheConfig.Boards { + if TheConfig.Boards[i].ID == bl.BoardID { + bl.board = TheConfig.Boards[i] + break + } + } + } + return bl.board +} + +// PowerON def +func (bl Boardlink) PowerON() error { + b := bl.Board() + return b.PowerON(bl.Channel) +} + +// PowerOFF def +func (bl Boardlink) PowerOFF() error { + b := bl.Board() + return b.PowerOFF(bl.Channel) +} + +// PowerToggle def +func (bl Boardlink) PowerToggle() error { + b := bl.Board() + return b.PowerToggle(bl.Channel) +} + +// PowerStatus def +func (bl Boardlink) PowerStatus() (bool, error) { + b := bl.Board() + return b.PowerStatus(bl.Channel) +} diff --git a/t/config.go b/t/config.go new file mode 100644 index 0000000..530c7d3 --- /dev/null +++ b/t/config.go @@ -0,0 +1,41 @@ +package main + +import ( + "encoding/json" + "io/ioutil" +) + +// Configuration def +type Configuration struct { + Hostname string `json:"hostname"` + Outlets map[(uint)]Outlet `json:"outlets"` + Boards []Board `json:"boards"` + MQTT MQTTConfig `json:"mqtt"` +} + +func loadConfig(filename string) (Configuration, error) { + bytes, err := ioutil.ReadFile(filename) + if err != nil { + return Configuration{}, err + } + + var c Configuration + err = json.Unmarshal(bytes, &c) + if err != nil { + return Configuration{}, err + } + + return c, nil +} + +func saveConfig(c Configuration, filename string) error { + bytes, err := json.MarshalIndent(c, "", " ") + if err != nil { + return err + } + + return ioutil.WriteFile(filename, bytes, 0644) +} + +// TheConfig def +var TheConfig Configuration diff --git a/t/main.go b/t/main.go new file mode 100644 index 0000000..39006f5 --- /dev/null +++ b/t/main.go @@ -0,0 +1,36 @@ +package main + +// Dictionary definition +type Dictionary map[string]interface{} + +func initOutlets() { + for _, o := range TheConfig.Outlets { + o.PowerInitial() + } +} + +func main() { + var err error + + var c1 Configuration + + c1 = createMockConfig() + + err = saveConfig(c1, "t.json") + if err != nil { + panic(err) + } + + TheConfig, err = loadConfig("t.json") + if err != nil { + panic(err) + } + + err = saveConfig(TheConfig, "t1.json") + if err != nil { + panic(err) + } + + startServer() + +} diff --git a/t/mock.go b/t/mock.go new file mode 100644 index 0000000..b59ef98 --- /dev/null +++ b/t/mock.go @@ -0,0 +1,102 @@ +package main + +func createMockConfig() Configuration { + return Configuration{ + Hostname: "maramao", + MQTT: MQTTConfig{ + BrokerIP: "192.168.2.190", + BrokerPort: "1883", + ClientID: "openpdu-123", + Username: "DVES_USER", + Password: "DVES_PASS", + CleanSession: false, + Topic: "openpdu/ok", + HomeAssistant: true, + }, + Boards: []Board{ + Board{ + ID: "47e41dc9-4a14-4b79-8644-d7442a15cb50", + Name: "Virtual IO", + Type: BoardTypeDummy, + ChannelCount: 40, + }, + Board{ + ID: "6561df75-bf93-43f5-82ac-9b3dda081961", + Name: "Internal GPIO", + Type: BoardTypeGPIO, + ChannelCount: 40, + }, + Board{ + Bus: 1, + Address: 0x29, + ID: "79690164-214f-41b0-93f9-e910dd54f323", + Name: "bordo1", + Type: BoardTypeI2CGPIO, + ChannelCount: 8, + }, + Board{ + Bus: 1, + Address: 0x27, + ID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713", + Name: "bordo2", + Type: BoardTypeI2CADC, + ChannelCount: 4, + }, + }, + Outlets: map[(uint)]Outlet{ + 0: Outlet{ + Name: "uscita 0", + Location: "port 1 dx", + HasPowerMeter: true, + Command: Boardlink{ + BoardID: "79690164-214f-41b0-93f9-e910dd54f323", + Channel: 0, + }, + PowerMeter: Boardlink{ + BoardID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713", + Channel: 0, + }, + }, + 1: Outlet{ + Name: "uscita 1", + Location: "port 1 sx", + HasPowerMeter: true, + Command: Boardlink{ + BoardID: "79690164-214f-41b0-93f9-e910dd54f323", + Channel: 1, + }, + PowerMeter: Boardlink{ + BoardID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713", + Channel: 1, + }, + }, + 2: Outlet{ + Name: "uscita 2", + Location: "port 2 dx", + HasPowerMeter: false, + Command: Boardlink{ + BoardID: "79690164-214f-41b0-93f9-e910dd54f323", + Channel: 2, + }, + }, + 3: Outlet{ + Name: "uscita 5v 1", + Location: "usb avanti 1", + HasPowerMeter: false, + Command: Boardlink{ + BoardID: "47e41dc9-4a14-4b79-8644-d7442a15cb50", + Channel: 21, + }, + }, + 4: Outlet{ + Name: "uscita 5v 2", + Location: "usb avanti 2", + HasPowerMeter: false, + Command: Boardlink{ + BoardID: "47e41dc9-4a14-4b79-8644-d7442a15cb50", + Channel: 22, + }, + }, + }, + } +} diff --git a/t/mqtt.go b/t/mqtt.go new file mode 100644 index 0000000..72ae2c3 --- /dev/null +++ b/t/mqtt.go @@ -0,0 +1,13 @@ +package main + +// MQTTConfig def +type MQTTConfig struct { + BrokerIP string `json:"ip"` + BrokerPort string `json:"port"` + ClientID string `json:"clientid"` + Username string `json:"username"` + Password string `json:"password"` + CleanSession bool `json:"cleansession"` + Topic string `json:"topic"` + HomeAssistant bool `json:"homeassistant"` +} diff --git a/t/outlet.go b/t/outlet.go new file mode 100644 index 0000000..6e92601 --- /dev/null +++ b/t/outlet.go @@ -0,0 +1,49 @@ +package main + +// Outlet Initial Status +const ( + OutletInitialStatusOFF uint = 0 + OutletInitialStatusON uint = 1 + OutletInitialStatusLAST uint = 2 // if hardware supported +) + +// Outlet def +type Outlet struct { + Name string `json:"name"` + Location string `json:"location"` + HasPowerMeter bool `json:"haspowermeter"` + InitialStatus uint `json:"initialstatus"` + Command Boardlink `json:"command"` + PowerMeter Boardlink `json:"powermeter"` +} + +// PowerON def +func (o Outlet) PowerON() error { + return o.Command.PowerON() +} + +// PowerOFF def +func (o Outlet) PowerOFF() error { + return o.Command.PowerOFF() +} + +// PowerToggle def +func (o Outlet) PowerToggle() error { + return o.Command.PowerToggle() +} + +// PowerInitial def +func (o Outlet) PowerInitial() error { + switch o.InitialStatus { + case OutletInitialStatusOFF: + return o.Command.PowerOFF() + case OutletInitialStatusON: + return o.Command.PowerON() + } + return nil +} + +// PowerStatus def +func (o Outlet) PowerStatus() (bool, error) { + return o.Command.PowerStatus() +} diff --git a/t/t.go b/t/t.go deleted file mode 100644 index eab87c2..0000000 --- a/t/t.go +++ /dev/null @@ -1,270 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" -) - -// Board def -type Board struct { - ChannelCount uint `json:"channelcount"` - ID string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` - Bus uint `json:"bus"` - Address uint `json:"address"` -} - -// ChannelName - return the name of a channel, useful for onboard GPIO -func (b Board) ChannelName(num uint) string { - return string(num) -} - -// PowerON def -func (b Board) PowerON(num uint) error { - return nil -} - -// PowerOFF def -func (b Board) PowerOFF(num uint) error { - return nil -} - -// PowerToggle def -func (b Board) PowerToggle(num uint) error { - return nil -} - -// Boardlink def -type Boardlink struct { - BoardID string `json:"boardid"` - Channel uint `json:"channel"` - board Board -} - -// Board def -func (bl Boardlink) Board() Board { - fmt.Printf("\n boardlink: \n\n") - if bl.board.ID == "" { - fmt.Printf("\n board nil: \n\n") - for i := range TheConfig.Boards { - if TheConfig.Boards[i].ID == bl.BoardID { - bl.board = TheConfig.Boards[i] - break - } - } - } - return bl.board -} - -// PowerON def -func (bl Boardlink) PowerON() error { - return bl.Board().PowerON(bl.Channel) -} - -// PowerOFF def -func (bl Boardlink) PowerOFF() error { - return bl.Board().PowerOFF(bl.Channel) -} - -// PowerToggle def -func (bl Boardlink) PowerToggle() error { - return bl.Board().PowerToggle(bl.Channel) -} - -// Outlet def -type Outlet struct { - Name string `json:"name"` - Location string `json:"location"` - HasPowerMeter bool `json:"haspowermeter"` - Command Boardlink `json:"command"` - PowerMeter Boardlink `json:"powermeter"` -} - -// PowerON def -func (o Outlet) PowerON() error { - return o.Command.PowerON() -} - -// PowerOFF def -func (o Outlet) PowerOFF() error { - return o.Command.PowerOFF() -} - -// PowerToggle def -func (o Outlet) PowerToggle() error { - return o.Command.PowerToggle() -} - -// MQTTConfig def -type MQTTConfig struct { - BrokerIP string `json:"ip"` - BrokerPort string `json:"port"` - ClientID string `json:"clientid"` - Username string `json:"username"` - Password string `json:"password"` - CleanSession bool `json:"cleansession"` - Topic string `json:"topic"` - HomeAssistant bool `json:"homeassistant"` -} - -// Configuration def -type Configuration struct { - Hostname string `json:"hostname"` - Outlets map[(uint)]Outlet `json:"outlets"` - Boards []Board `json:"boards"` - MQTT MQTTConfig `json:"mqtt"` -} - -func loadConfig(filename string) (Configuration, error) { - bytes, err := ioutil.ReadFile(filename) - if err != nil { - return Configuration{}, err - } - - var c Configuration - err = json.Unmarshal(bytes, &c) - if err != nil { - return Configuration{}, err - } - - return c, nil -} - -func saveConfig(c Configuration, filename string) error { - bytes, err := json.MarshalIndent(c, "", " ") - if err != nil { - return err - } - - return ioutil.WriteFile(filename, bytes, 0644) -} - -// TheConfig def -var TheConfig Configuration - -func main() { - var err error - - var c1 Configuration - - c1 = createMockConfig() - for n, br := range c1.Boards { - fmt.Printf("A - Board %v (%v)\n", n, br.Type) - } - - err = saveConfig(c1, "t.json") - if err != nil { - panic(err) - } - - TheConfig, err = loadConfig("t.json") - if err != nil { - panic(err) - } - - err = saveConfig(TheConfig, "t1.json") - if err != nil { - panic(err) - } - - fmt.Printf("\n\nmqtt: %v\n\n", TheConfig.MQTT) - - TheConfig.Outlets[0].PowerON() -} - -func createMockConfig() Configuration { - return Configuration{ - Hostname: "maramao", - MQTT: MQTTConfig{ - BrokerIP: "192.168.2.190", - BrokerPort: "1883", - ClientID: "openpdu-123", - Username: "DVES_USER", - Password: "DVES_PASS", - CleanSession: false, - Topic: "openpdu/ok", - HomeAssistant: true, - }, - Boards: []Board{ - Board{ - ID: "6561df75-bf93-43f5-82ac-9b3dda081961", - Name: "Internal GPIO", - Type: "GPIO", - ChannelCount: 40, - }, - Board{ - Bus: 1, - Address: 0x29, - ID: "79690164-214f-41b0-93f9-e910dd54f323", - Name: "bordo1", - Type: "I2C-GPIO", - ChannelCount: 8, - }, - Board{ - Bus: 1, - Address: 0x27, - ID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713", - Name: "bordo2", - Type: "I2C-ADC", - ChannelCount: 4, - }, - }, - Outlets: map[(uint)]Outlet{ - 0: Outlet{ - Name: "uscita 0", - Location: "port 1 dx", - HasPowerMeter: true, - Command: Boardlink{ - BoardID: "79690164-214f-41b0-93f9-e910dd54f323", - Channel: 0, - }, - PowerMeter: Boardlink{ - BoardID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713", - Channel: 0, - }, - }, - 1: Outlet{ - Name: "uscita 1", - Location: "port 1 sx", - HasPowerMeter: true, - Command: Boardlink{ - BoardID: "79690164-214f-41b0-93f9-e910dd54f323", - Channel: 1, - }, - PowerMeter: Boardlink{ - BoardID: "93f446d8-59e4-4abd-8bf7-e31cd80bc713", - Channel: 1, - }, - }, - 2: Outlet{ - Name: "uscita 2", - Location: "port 2 dx", - HasPowerMeter: false, - Command: Boardlink{ - BoardID: "79690164-214f-41b0-93f9-e910dd54f323", - Channel: 2, - }, - }, - 3: Outlet{ - Name: "uscita 5v 1", - Location: "usb avanti 1", - HasPowerMeter: false, - Command: Boardlink{ - BoardID: "6561df75-bf93-43f5-82ac-9b3dda081961", - Channel: 21, - }, - }, - 4: Outlet{ - Name: "uscita 5v 2", - Location: "usb avanti 2", - HasPowerMeter: false, - Command: Boardlink{ - BoardID: "6561df75-bf93-43f5-82ac-9b3dda081961", - Channel: 22, - }, - }, - }, - } -} diff --git a/t/web.go b/t/web.go new file mode 100644 index 0000000..d449778 --- /dev/null +++ b/t/web.go @@ -0,0 +1,29 @@ +package main + +import ( + "log" + "net/http" + + "github.com/go-macaron/pongo2" + "gopkg.in/macaron.v1" +) + +func startServer() { + m := macaron.Classic() + m.Use(pongo2.Pongoer()) + m.Use(macaron.Static("static")) + // m.Get("/", myHandler) + + m.Get("/", statusPage) + m.Get("/json/status", jsonStatus) + m.Post("/json/outlet/:outlet/on", jsonOutletPowerON) + m.Post("/json/outlet/:outlet/off", jsonOutletPowerOFF) + m.Post("/json/outlet/:outlet/toggle", jsonOutletPowerToggle) + + m.Get("/boards", func(ctx *macaron.Context) { + ctx.HTML(200, "boards") // 200 is the response code. + }) + + log.Println("Server is running...") + log.Println(http.ListenAndServe("0.0.0.0:4000", m)) +} diff --git a/t/webjson.go b/t/webjson.go new file mode 100644 index 0000000..ac0b507 --- /dev/null +++ b/t/webjson.go @@ -0,0 +1,129 @@ +package main + +import ( + "fmt" + "net/http" + "strconv" + + "gopkg.in/macaron.v1" +) + +func jsonStatus(ctx *macaron.Context) { + + out := [][]string{} + + for num, o := range TheConfig.Outlets { + pwr, _ := o.PowerStatus() + pwrstr := "0" + if pwr { + pwrstr = "1" + } + out = append(out, []string{fmt.Sprintf("%d", num), o.Name, pwrstr}) + } + + ctx.JSON(http.StatusOK, Dictionary{ + "data": out, + }) +} + +func jsonOutletPowerToggle(ctx *macaron.Context) { + var outletnum64 uint64 + var err error + + outletnum64, err = strconv.ParseUint(ctx.Params(":outlet"), 10, 32) + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "No outlet specified", + }) + } + + outletnum := uint(outletnum64) + outlet, exists := TheConfig.Outlets[outletnum] + if !exists { + // error: outlet doesn't exists + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "Outlet doesn't exists", + }) + } + + err = outlet.PowerToggle() + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "Can't toggle power", + }) + } + ctx.JSON(http.StatusOK, Dictionary{ + "data": "ok", + }) +} + +func jsonOutletPowerON(ctx *macaron.Context) { + var outletnum64 uint64 + var err error + + outletnum64, err = strconv.ParseUint(ctx.Params(":outlet"), 10, 32) + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "No outlet specified", + }) + } + outletnum := uint(outletnum64) + + outlet, exists := TheConfig.Outlets[outletnum] + if !exists { + // error: outlet doesn't exists + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "Outlet doesn't exists", + }) + } + + err = outlet.PowerON() + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "Can't toggle power", + }) + } + ctx.JSON(http.StatusOK, Dictionary{ + "data": "ok", + }) +} + +func jsonOutletPowerOFF(ctx *macaron.Context) { + var outletnum64 uint64 + var err error + + outletnum64, err = strconv.ParseUint(ctx.Params(":outlet"), 10, 32) + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "No outlet specified", + }) + } + outletnum := uint(outletnum64) + + outlet, exists := TheConfig.Outlets[outletnum] + if !exists { + // error: outlet doesn't exists + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "Outlet doesn't exists", + }) + } + + err = outlet.PowerOFF() + if err != nil { + ctx.JSON(http.StatusOK, Dictionary{ + "data": "error", + "error": "Can't toggle power", + }) + } + ctx.JSON(http.StatusOK, Dictionary{ + "data": "ok", + }) +} diff --git a/t/webpages.go b/t/webpages.go new file mode 100644 index 0000000..649764f --- /dev/null +++ b/t/webpages.go @@ -0,0 +1,14 @@ +package main + +import "gopkg.in/macaron.v1" + +func statusPage(ctx *macaron.Context) { + var pluglist []Dictionary + + for num, o := range TheConfig.Outlets { + pluglist = append(pluglist, Dictionary{"id": num, "description": o.Name}) + } + + ctx.Data["pluglist"] = pluglist + ctx.HTML(200, "status") // 200 is the response code. +}