From e0baf673a02dce1b358d776595428662cf75806b Mon Sep 17 00:00:00 2001 From: Tim Rice Date: Wed, 5 Jun 2019 12:59:15 -0700 Subject: [PATCH 1/4] Add power usage reporting --- main.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 3189620..1a2c7d2 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,8 @@ import ( "log" "net/http" "time" + "strconv" + "strings" MQTT "github.com/eclipse/paho.mqtt.golang" "github.com/gorilla/websocket" @@ -34,6 +36,14 @@ func (o outlet) StateTopic() string { return o.CommandTopic() + "/state" } +func (o outlet) EnergyTopic() string { + return o.CommandTopic() + "/energy" +} + +func (o outlet) InstantEnergyTopic() string { + return o.CommandTopic() + "/instantenergy" +} + var subscribes = make(chan outlet) var unsubscribes = make(chan outlet) @@ -47,6 +57,16 @@ type RelayMessage struct { Action string `json:"action"` } +type EnergyMessage struct { + Seconds int `json:"seconds"` + Watts float64 `json:"watts"` +} + +type InstantEnergyMessage struct { + Instant float64 `json:"instant"` + Avg30s float64 `json:"avg30s"` +} + type LoginReplyMessage struct { Uri string `json:"uri"` Error int `json:"error"` @@ -70,6 +90,13 @@ func (writer logWriter) Write(bytes []byte) (int, error) { return fmt.Print(time.Now().UTC().Format("15:04:05.999Z") + " " + string(bytes)) } +func ParsePower(power string) (uint64, uint64, error) { + powers := strings.Split(power, ":") + instant, e := strconv.ParseUint(powers[0], 16, 64) + avg30s, e := strconv.ParseUint(powers[1], 16, 64) + return instant, avg30s, e +} + func websocketRequest(w http.ResponseWriter, r *http.Request) { c, err := upgrader.Upgrade(w, r, nil) if err != nil { @@ -115,7 +142,7 @@ outer: case <-ticker.C: log.Printf("[%s] ping", o.id) if !pendingCommand { - err := c.WriteMessage(websocket.TextMessage, []byte("{\"uri\":\"/ka\"}")) + err := c.WriteMessage(websocket.TextMessage, []byte("{\"uri\":\"/getRuntime\"}")) if err != nil { log.Println("ping err:", err) } @@ -163,13 +190,29 @@ outer: log.Printf("[%s] send: %s", o.id, msg) err = c.WriteMessage(websocket.TextMessage, msg) } - if m["uri"] == "/runtimeInfo" { if m["relay"] == "open" { messages <- message{o.StateTopic(), "true"} } else { messages <- message{o.StateTopic(), "false"} } + + if m["power"] != nil { + powers := strings.Split(m["power"].(string), ":") + if len(powers) == 2 { + if instant, err := strconv.ParseUint(powers[0], 16, 64); err == nil { + if avg30s, err := strconv.ParseUint(powers[1], 16, 64); err == nil { + msg, _ := json.Marshal(InstantEnergyMessage{ + Instant: float64(instant) / 4096, + Avg30s: float64(avg30s) / 4096, + }) + messages <- message{o.InstantEnergyTopic(), string(msg)} + log.Printf("[%s] report: %s", o.id, msg) + } + } + } + } + } if m["uri"] == "/state" { if m["relay"] == "open" { @@ -178,6 +221,17 @@ outer: messages <- message{o.StateTopic(), "false"} } } + if m["uri"] == "/report" && m["e"] != nil && m["t"] != nil { + if energy, err := strconv.ParseUint(m["e"].(string), 16, 64); err == nil { + secs, _ := strconv.ParseInt(m["t"].(string), 16, 64) + msg, _ := json.Marshal(EnergyMessage{ + Seconds: int(secs), + Watts: float64(energy) / 4096, + }) + messages <- message{o.EnergyTopic(), string(msg)} + log.Printf("[%s] report: %s", o.id, msg) + } + } case command := <-mqtt: log.Printf("[%s] command: %s", o.id, command) var err error From 2cd0104ceec90c95d7b6c079065c3c6e9cfdf7cb Mon Sep 17 00:00:00 2001 From: John Wice Date: Tue, 19 May 2020 09:00:22 -0400 Subject: [PATCH 2/4] It appears that sometimes the values reported back aren't within the realm of reasonable. Filtering them out until more information is found --- main.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 1a2c7d2..5a86d73 100644 --- a/main.go +++ b/main.go @@ -202,12 +202,17 @@ outer: if len(powers) == 2 { if instant, err := strconv.ParseUint(powers[0], 16, 64); err == nil { if avg30s, err := strconv.ParseUint(powers[1], 16, 64); err == nil { - msg, _ := json.Marshal(InstantEnergyMessage{ - Instant: float64(instant) / 4096, - Avg30s: float64(avg30s) / 4096, - }) - messages <- message{o.InstantEnergyTopic(), string(msg)} - log.Printf("[%s] report: %s", o.id, msg) + // this is a 15 amp rated device, give ourselves a bunch of headroom, even on 240v + if instant > 4000 or avg30s > 4000 { + log.Printf("[%s] skipping power report, value(s) out of range: instant %dw, avg30s %dw", o.id, msg) + } else { + msg, _ := json.Marshal(InstantEnergyMessage{ + Instant: float64(instant) / 4096, + Avg30s: float64(avg30s) / 4096, + }) + messages <- message{o.InstantEnergyTopic(), string(msg)} + log.Printf("[%s] report: %s", o.id, msg) + } } } } From 383b0f04194992633af5708c2ca659a332284ee6 Mon Sep 17 00:00:00 2001 From: John Wice Date: Tue, 19 May 2020 09:12:42 -0400 Subject: [PATCH 3/4] python habits --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 5a86d73..b44a8ed 100644 --- a/main.go +++ b/main.go @@ -203,8 +203,8 @@ outer: if instant, err := strconv.ParseUint(powers[0], 16, 64); err == nil { if avg30s, err := strconv.ParseUint(powers[1], 16, 64); err == nil { // this is a 15 amp rated device, give ourselves a bunch of headroom, even on 240v - if instant > 4000 or avg30s > 4000 { - log.Printf("[%s] skipping power report, value(s) out of range: instant %dw, avg30s %dw", o.id, msg) + if instant > 4000 || avg30s > 4000 { + log.Printf("[%s] skipping power report, value(s) out of range: instant %dw, avg30s %dw", o.id, instant, avg30s) } else { msg, _ := json.Marshal(InstantEnergyMessage{ Instant: float64(instant) / 4096, From f28489855c10ef6fb934ee6af025e0c66d688b25 Mon Sep 17 00:00:00 2001 From: John Wice Date: Tue, 19 May 2020 09:24:43 -0400 Subject: [PATCH 4/4] comparing before the division --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index b44a8ed..6d5f47c 100644 --- a/main.go +++ b/main.go @@ -203,7 +203,7 @@ outer: if instant, err := strconv.ParseUint(powers[0], 16, 64); err == nil { if avg30s, err := strconv.ParseUint(powers[1], 16, 64); err == nil { // this is a 15 amp rated device, give ourselves a bunch of headroom, even on 240v - if instant > 4000 || avg30s > 4000 { + if instant > 4000*4096 || avg30s > 4000*4096 { log.Printf("[%s] skipping power report, value(s) out of range: instant %dw, avg30s %dw", o.id, instant, avg30s) } else { msg, _ := json.Marshal(InstantEnergyMessage{