diff --git a/cmd/invertergui/main.go b/cmd/invertergui/main.go
index c26f44f..519bddd 100644
--- a/cmd/invertergui/main.go
+++ b/cmd/invertergui/main.go
@@ -32,23 +32,54 @@ package main
import (
"flag"
- "github.com/hpdvanwyk/invertergui/datasource"
+ "github.com/hpdvanwyk/invertergui/mk2if"
"github.com/hpdvanwyk/invertergui/webgui"
+ "github.com/mikepb/go-serial"
"github.com/prometheus/client_golang/prometheus/promhttp"
+ "io"
"log"
+ "net"
"net/http"
- "time"
)
func main() {
- url := flag.String("url", "http://localhost:9005", "The url of the multiplus JSON interface.")
- capacity := flag.Float64("capacity", 100, "The capacity of the batteries in the system.")
addr := flag.String("addr", ":8080", "TCP address to listen on.")
+
+ tcp := flag.Bool("tcp", false, "Use TCP instead of TTY")
+ ip := flag.String("ip", "localhost:8139", "IP to connect when using tcp connection.")
+ dev := flag.String("dev", "/dev/ttyUSB0", "TTY device to use.")
flag.Parse()
- source := datasource.NewJSONSource(*url)
- poller := datasource.NewDataPoller(source, 10*time.Second)
- gui := webgui.NewWebGui(poller, *capacity)
+ var p io.ReadWriteCloser
+ var err error
+ var tcpAddr *net.TCPAddr
+
+ if *tcp {
+ tcpAddr, err = net.ResolveTCPAddr("tcp", *ip)
+ if err != nil {
+ panic(err)
+ }
+ p, err = net.DialTCP("tcp", nil, tcpAddr)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ options := serial.RawOptions
+ options.BitRate = 2400
+ options.Mode = serial.MODE_READ_WRITE
+ p, err = options.Open(*dev)
+ if err != nil {
+ panic(err)
+ }
+ }
+ defer p.Close()
+ mk2, err := mk2if.NewMk2Connection(p)
+ defer mk2.Close()
+ if err != nil {
+ panic(err)
+ }
+
+ gui := webgui.NewWebGui(mk2)
http.Handle("/", gui)
http.Handle("/munin", http.HandlerFunc(gui.ServeMuninHTTP))
http.Handle("/muninconfig", http.HandlerFunc(gui.ServeMuninConfigHTTP))
diff --git a/datasource/datapoller.go b/datasource/datapoller.go
deleted file mode 100644
index c1cdf30..0000000
--- a/datasource/datapoller.go
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-Copyright (c) 2015, Hendrik van Wyk
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-* Neither the name of invertergui nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package datasource
-
-import (
- "sync"
- "time"
-)
-
-type DataPoller interface {
- C() chan *Status
- Stop()
-}
-
-type Status struct {
- MpStatus MultiplusStatus
- Time time.Time
- Err error
-}
-
-type poller struct {
- source DataSource
- rate time.Duration
- statusChan chan *Status
- stop chan struct{}
- wg sync.WaitGroup
-}
-
-func NewDataPoller(source DataSource, pollRate time.Duration) DataPoller {
- this := &poller{
- source: source,
- rate: pollRate,
- statusChan: make(chan *Status),
- stop: make(chan struct{}),
- }
- this.wg.Add(1)
- go this.poll()
- return this
-}
-
-func (this *poller) C() chan *Status {
- return this.statusChan
-}
-
-func (this *poller) Stop() {
- close(this.stop)
- this.wg.Wait()
-}
-
-func (this *poller) poll() {
- ticker := time.NewTicker(this.rate)
- this.doPoll()
- for {
- select {
- case <-ticker.C:
- this.doPoll()
- case <-this.stop:
- ticker.Stop()
- close(this.statusChan)
- this.wg.Done()
- return
- }
- }
-}
-
-func (this *poller) doPoll() {
- tmp := new(Status)
- tmp.Err = this.source.GetData(&tmp.MpStatus)
- tmp.Time = time.Now()
- this.statusChan <- tmp
-}
diff --git a/datasource/decode_test.go b/datasource/decode_test.go
deleted file mode 100644
index 1471e16..0000000
--- a/datasource/decode_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-Copyright (c) 2015, Hendrik van Wyk
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-* Neither the name of invertergui nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package datasource
-
-import (
- "net/http"
- "net/http/httptest"
- "reflect"
- "testing"
-)
-
-var sampleJSON string = `{"outCurrent": 1.19,
-"leds": [0, 0, 0, 0, 1, 0, 0, 1],
-"batVoltage": 26.63,
-"inCurrent": 1.39,
-"outVoltage": 235.3,
-"inVoltage": 235.3,
-"inFreq": 51.3,
-"batCurrent": 0.0,
-"outFreq": 735.3}`
-
-func returnJson(resp http.ResponseWriter, req *http.Request) {
- resp.Write([]byte(sampleJSON))
-}
-
-func TestFetchStatus(t *testing.T) {
- //setup test server
- testServer := httptest.NewServer(http.HandlerFunc(returnJson))
-
- var status MultiplusStatus
- source := NewJSONSource(testServer.URL)
- err := source.GetData(&status)
- if err != nil {
- t.Errorf("Unmarshal gave: %v", err)
- }
- expected := MultiplusStatus{1.19, 1.39, 235.3, 235.3, 26.63, 0, 51.3, 735.3, []int{0, 0, 0, 0, 1, 0, 0, 1}}
- if !reflect.DeepEqual(status, expected) {
- t.Errorf("JSON string did not decode as expected.")
- }
- testServer.Close()
-}
diff --git a/datasource/jsondecode.go b/datasource/jsondecode.go
deleted file mode 100644
index 0505a7c..0000000
--- a/datasource/jsondecode.go
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-Copyright (c) 2015, Hendrik van Wyk
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-* Neither the name of invertergui nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package datasource
-
-import (
- "encoding/json"
- "net/http"
-)
-
-type DataSource interface {
- GetData(*MultiplusStatus) error
-}
-
-type MultiplusStatus struct {
- OutCurrent float64 `json:"outCurrent"`
- InCurrent float64 `json:"inCurrent"`
- OutVoltage float64 `json:"outVoltage"`
- InVoltage float64 `json:"inVoltage"`
- BatVoltage float64 `json:"batVoltage"`
- BatCurrent float64 `json:"batCurrent"`
- InFreq float64 `json:"inFreq"`
- OutFreq float64 `json:"outFreq"`
- Leds []int `json:"leds"`
-}
-
-type source struct {
- url string
-}
-
-func NewJSONSource(url string) DataSource {
- return &source{url: url}
-}
-
-func (s *source) GetData(status *MultiplusStatus) error {
- resp, err := http.Get(s.url)
- if err != nil {
- return err
- }
- dec := json.NewDecoder(resp.Body)
- err = dec.Decode(status)
- if err != nil {
- return err
- }
- err = resp.Body.Close()
- if err != nil {
- return err
- }
- return nil
-}
diff --git a/datasource/poller_test.go b/datasource/poller_test.go
deleted file mode 100644
index 1cd8897..0000000
--- a/datasource/poller_test.go
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-Copyright (c) 2015, Hendrik van Wyk
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-* Neither the name of invertergui nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package datasource
-
-import (
- "errors"
- "testing"
- "time"
-)
-
-type mockDataSource struct {
- currentMock int
- shouldBreak bool
-}
-
-func (this *mockDataSource) GetData(data *MultiplusStatus) error {
- if this.shouldBreak {
- return errors.New("Do not be alarmed. This is only a test.")
- }
- data.BatCurrent = float64(this.currentMock)
- this.currentMock++
- return nil
-}
-
-func TestOnePoll(t *testing.T) {
- poller := NewDataPoller(&mockDataSource{currentMock: 100}, 1*time.Millisecond)
- statChan := poller.C()
- status := <-statChan
- if status.MpStatus.BatCurrent != 100 {
- t.Errorf("Incorrect data passed from data source.")
- }
- if status.Time.IsZero() {
- t.Errorf("Time not set.")
- }
- poller.Stop()
-}
-
-func TestMultiplePolls(t *testing.T) {
- poller := NewDataPoller(&mockDataSource{currentMock: 100}, 1*time.Millisecond)
- statChan := poller.C()
- expect := 100
- for i := 0; i < 100; i++ {
- status := <-statChan
- if status.MpStatus.BatCurrent != float64(expect) {
- t.Errorf("Incorrect data passed from data source.")
- }
- expect++
- if status.Time.IsZero() {
- t.Errorf("Time not set.")
- }
- }
- poller.Stop()
-}
-
-func TestError(t *testing.T) {
- poller := NewDataPoller(&mockDataSource{shouldBreak: true}, 1*time.Millisecond)
- statChan := poller.C()
- status := <-statChan
- if status.Err == nil {
- t.Errorf("Error not correctly propagated.")
- }
- poller.Stop()
-}
diff --git a/webgui/htmltemplate.go b/webgui/htmltemplate.go
index 56be4db..e11fcbb 100644
--- a/webgui/htmltemplate.go
+++ b/webgui/htmltemplate.go
@@ -40,7 +40,11 @@ var htmlTemplate string = `
- {{if .Error}} Error encountered: {{.Error}}
{{end}}
+ {{if .Error}} Errors encountered:
+ {{range .Error}}
+ {{.}}
+ {{end}}
+ {{end}}
- Date: {{.Date}}
@@ -55,6 +59,7 @@ var htmlTemplate string = `
- Output Current: {{.OutCurrent}} A
- Output Voltage: {{.OutVoltage}} V
+ - Output Frequency: {{.OutFreq}} Hz
- Output Power: {{.OutPower}} VA
@@ -68,7 +73,7 @@ var htmlTemplate string = `
- Battery Current: {{.BatCurrent}} A
- Battery Voltage: {{.BatVoltage}} V
- Battery Power: {{.BatPower}} W
- - Battery Charge: {{.BatCharge}} A h
+ - Battery Charge: {{.BatCharge}} %
`
diff --git a/webgui/munin.go b/webgui/munin.go
index 3db13f1..161f09e 100644
--- a/webgui/munin.go
+++ b/webgui/munin.go
@@ -33,12 +33,12 @@ package webgui
import (
"bytes"
"fmt"
+ "github.com/hpdvanwyk/invertergui/mk2if"
"net/http"
- "time"
)
type muninData struct {
- statusP statusProcessed
+ status mk2if.Mk2Info
timesUpdated int
}
@@ -51,8 +51,8 @@ func (w *WebGui) ServeMuninHTTP(rw http.ResponseWriter, r *http.Request) {
}
calcMuninAverages(&muninDat)
- statusP := &muninDat.statusP
- tmpInput := buildTemplateInput(statusP, time.Now())
+ status := muninDat.status
+ tmpInput := buildTemplateInput(&status)
outputBuf := &bytes.Buffer{}
fmt.Fprintf(outputBuf, "multigraph in_batvolt\n")
fmt.Fprintf(outputBuf, "volt.value %s\n", tmpInput.BatVoltage)
@@ -72,7 +72,8 @@ func (w *WebGui) ServeMuninHTTP(rw http.ResponseWriter, r *http.Request) {
fmt.Fprintf(outputBuf, "powerin.value %s\n", tmpInput.InPower)
fmt.Fprintf(outputBuf, "powerout.value %s\n", tmpInput.OutPower)
fmt.Fprintf(outputBuf, "multigraph in_mainsfreq\n")
- fmt.Fprintf(outputBuf, "freq.value %s\n", tmpInput.InFreq)
+ fmt.Fprintf(outputBuf, "freqin.value %s\n", tmpInput.InFreq)
+ fmt.Fprintf(outputBuf, "freqout.value %s\n", tmpInput.OutFreq)
_, err := rw.Write([]byte(outputBuf.String()))
if err != nil {
@@ -92,12 +93,12 @@ volt.label Voltage of battery (V)
multigraph in_batcharge
graph_title Battery Charge
-graph_vlabel Charge (A h)
+graph_vlabel Charge (%)
graph_category inverter
graph_info Battery charge
charge.info Estimated charge of battery
-charge.label Battery charge (A h)
+charge.label Battery charge (%)
multigraph in_batcurrent
graph_title Battery Current
@@ -156,8 +157,10 @@ graph_vlabel Frequency (Hz)
graph_category inverter
graph_info Mains frequency
-freq.info Input frequency
-freq.label Input frequency (Hz)
+freqin.info In frequency
+freqin.label In frequency (Hz)
+freqout.info Out frequency
+freqout.label Out frequency (Hz)
`
_, err := rw.Write([]byte(output))
@@ -167,46 +170,47 @@ freq.label Input frequency (Hz)
}
//Munin only samples once every 5 minutes so averages have to be calculated for some values.
-func calcMuninValues(muninDat *muninData, newStatus *statusProcessed) {
+func calcMuninValues(muninDat *muninData, newStatus *mk2if.Mk2Info) {
muninDat.timesUpdated += 1
- muninVal := &muninDat.statusP
- muninVal.status.OutCurrent += newStatus.status.OutCurrent
- muninVal.status.InCurrent += newStatus.status.InCurrent
- muninVal.status.BatCurrent += newStatus.status.BatCurrent
+ muninVal := &muninDat.status
+ muninVal.OutCurrent += newStatus.OutCurrent
+ muninVal.InCurrent += newStatus.InCurrent
+ muninVal.BatCurrent += newStatus.BatCurrent
- muninVal.status.OutVoltage += newStatus.status.OutVoltage
- muninVal.status.InVoltage += newStatus.status.InVoltage
- muninVal.status.BatVoltage += newStatus.status.BatVoltage
+ muninVal.OutVoltage += newStatus.OutVoltage
+ muninVal.InVoltage += newStatus.InVoltage
+ muninVal.BatVoltage += newStatus.BatVoltage
- muninVal.status.InFreq = newStatus.status.InFreq
+ muninVal.InFrequency = newStatus.InFrequency
+ muninVal.OutFrequency = newStatus.OutFrequency
- muninVal.chargeLevel = newStatus.chargeLevel
- muninVal.status.Leds = newStatus.status.Leds
+ muninVal.ChargeState = newStatus.ChargeState
}
func calcMuninAverages(muninDat *muninData) {
- muninVal := &muninDat.statusP
- muninVal.status.OutCurrent /= float64(muninDat.timesUpdated)
- muninVal.status.InCurrent /= float64(muninDat.timesUpdated)
- muninVal.status.BatCurrent /= float64(muninDat.timesUpdated)
+ muninVal := &muninDat.status
+ muninVal.OutCurrent /= float64(muninDat.timesUpdated)
+ muninVal.InCurrent /= float64(muninDat.timesUpdated)
+ muninVal.BatCurrent /= float64(muninDat.timesUpdated)
- muninVal.status.OutVoltage /= float64(muninDat.timesUpdated)
- muninVal.status.InVoltage /= float64(muninDat.timesUpdated)
- muninVal.status.BatVoltage /= float64(muninDat.timesUpdated)
+ muninVal.OutVoltage /= float64(muninDat.timesUpdated)
+ muninVal.InVoltage /= float64(muninDat.timesUpdated)
+ muninVal.BatVoltage /= float64(muninDat.timesUpdated)
}
func zeroMuninValues(muninDat *muninData) {
muninDat.timesUpdated = 0
- muninVal := &muninDat.statusP
- muninVal.status.OutCurrent = 0
- muninVal.status.InCurrent = 0
- muninVal.status.BatCurrent = 0
+ muninVal := &muninDat.status
+ muninVal.OutCurrent = 0
+ muninVal.InCurrent = 0
+ muninVal.BatCurrent = 0
- muninVal.status.OutVoltage = 0
- muninVal.status.InVoltage = 0
- muninVal.status.BatVoltage = 0
+ muninVal.OutVoltage = 0
+ muninVal.InVoltage = 0
+ muninVal.BatVoltage = 0
- muninVal.status.InFreq = 0
+ muninVal.InFrequency = 0
+ muninVal.OutFrequency = 0
- muninVal.chargeLevel = 0
+ muninVal.ChargeState = 0
}
diff --git a/webgui/prometheus.go b/webgui/prometheus.go
index 35b0264..ab624b1 100644
--- a/webgui/prometheus.go
+++ b/webgui/prometheus.go
@@ -31,6 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package webgui
import (
+ "github.com/hpdvanwyk/invertergui/mk2if"
"github.com/prometheus/client_golang/prometheus"
)
@@ -116,10 +117,10 @@ func newPrometheusUpdater() *prometheusUpdater {
return tmp
}
-func (pu *prometheusUpdater) updatePrometheus(newStatus *statusProcessed) {
- s := newStatus.status
+func (pu *prometheusUpdater) updatePrometheus(newStatus *mk2if.Mk2Info) {
+ s := newStatus
pu.batteryVoltage.Set(s.BatVoltage)
- pu.batteryCharge.Set(newStatus.chargeLevel)
+ pu.batteryCharge.Set(newStatus.ChargeState * 100)
pu.batteryCurrent.Set(s.BatCurrent)
pu.batteryCurrent.Set(s.BatVoltage * s.BatCurrent)
pu.mainsCurrentIn.Set(s.InCurrent)
@@ -128,7 +129,6 @@ func (pu *prometheusUpdater) updatePrometheus(newStatus *statusProcessed) {
pu.mainsVoltageOut.Set(s.OutVoltage)
pu.mainsPowerIn.Set(s.InVoltage * s.InCurrent)
pu.mainsPowerOut.Set(s.OutVoltage * s.OutCurrent)
- pu.mainsFreqIn.Set(s.InFreq)
- pu.mainsFreqIn.Set(s.OutFreq)
-
+ pu.mainsFreqIn.Set(s.InFrequency)
+ pu.mainsFreqOut.Set(s.OutFrequency)
}
diff --git a/webgui/webgui.go b/webgui/webgui.go
index d7fa36f..2b2ad05 100644
--- a/webgui/webgui.go
+++ b/webgui/webgui.go
@@ -32,50 +32,28 @@ package webgui
import (
"fmt"
- "github.com/hpdvanwyk/invertergui/datasource"
+ "github.com/hpdvanwyk/invertergui/mk2if"
"html/template"
"net/http"
"sync"
"time"
)
-const (
- Temperature = iota
- Low_battery
- Overload
- Inverter
- Float
- Bulk
- Absorption
- Mains
-)
-
-var leds = map[int]string{
- 0: "Temperature",
- 1: "Low battery",
- 2: "Overload",
- 3: "Inverter",
- 4: "Float",
- 5: "Bulk",
- 6: "Absorption",
- 7: "Mains",
-}
-
type WebGui struct {
- respChan chan statusProcessed
+ respChan chan *mk2if.Mk2Info
stopChan chan struct{}
template *template.Template
muninRespChan chan muninData
- poller datasource.DataPoller
+ poller mk2if.Mk2If
wg sync.WaitGroup
pu *prometheusUpdater
}
-func NewWebGui(source datasource.DataPoller, batteryCapacity float64) *WebGui {
+func NewWebGui(source mk2if.Mk2If) *WebGui {
w := new(WebGui)
- w.respChan = make(chan statusProcessed)
+ w.respChan = make(chan *mk2if.Mk2Info)
w.muninRespChan = make(chan muninData)
w.stopChan = make(chan struct{})
var err error
@@ -87,12 +65,12 @@ func NewWebGui(source datasource.DataPoller, batteryCapacity float64) *WebGui {
w.pu = newPrometheusUpdater()
w.wg.Add(1)
- go w.dataPoll(batteryCapacity)
+ go w.dataPoll()
return w
}
type templateInput struct {
- Error error
+ Error []error
Date string
@@ -111,7 +89,8 @@ type templateInput struct {
BatPower string
BatCharge string
- InFreq string
+ InFreq string
+ OutFreq string
Leds []string
}
@@ -119,7 +98,7 @@ type templateInput struct {
func (w *WebGui) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
statusErr := <-w.respChan
- tmpInput := buildTemplateInput(&statusErr, statusErr.timestamp)
+ tmpInput := buildTemplateInput(statusErr)
err := w.template.Execute(rw, tmpInput)
if err != nil {
@@ -127,20 +106,28 @@ func (w *WebGui) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
}
}
-func buildTemplateInput(statusErr *statusProcessed, now time.Time) *templateInput {
- status := statusErr.status
+func ledName(nameInt int) string {
+ name, ok := mk2if.LedNames[nameInt]
+ if !ok {
+ return "Unknown led"
+ }
+ return name
+}
+
+func buildTemplateInput(status *mk2if.Mk2Info) *templateInput {
outPower := status.OutVoltage * status.OutCurrent
inPower := status.InCurrent * status.InVoltage
tmpInput := &templateInput{
- Error: statusErr.err,
- Date: now.Format(time.RFC1123Z),
+ Error: status.Errors,
+ Date: status.Timestamp.Format(time.RFC1123Z),
OutCurrent: fmt.Sprintf("%.3f", status.OutCurrent),
OutVoltage: fmt.Sprintf("%.3f", status.OutVoltage),
OutPower: fmt.Sprintf("%.3f", outPower),
InCurrent: fmt.Sprintf("%.3f", status.InCurrent),
InVoltage: fmt.Sprintf("%.3f", status.InVoltage),
- InFreq: fmt.Sprintf("%.3f", status.InFreq),
+ InFreq: fmt.Sprintf("%.3f", status.InFrequency),
+ OutFreq: fmt.Sprintf("%.3f", status.OutFrequency),
InPower: fmt.Sprintf("%.3f", inPower),
InMinOut: fmt.Sprintf("%.3f", inPower-outPower),
@@ -148,56 +135,33 @@ func buildTemplateInput(statusErr *statusProcessed, now time.Time) *templateInpu
BatCurrent: fmt.Sprintf("%.3f", status.BatCurrent),
BatVoltage: fmt.Sprintf("%.3f", status.BatVoltage),
BatPower: fmt.Sprintf("%.3f", status.BatVoltage*status.BatCurrent),
- BatCharge: fmt.Sprintf("%.3f", statusErr.chargeLevel),
+ BatCharge: fmt.Sprintf("%.3f", status.ChargeState*100),
}
- if len(status.Leds) == 8 {
- for i := 7; i >= 0; i-- {
- if status.Leds[i] == 1 {
- tmpInput.Leds = append(tmpInput.Leds, leds[i])
- }
- }
+ for i := range status.LedListOn {
+ tmpInput.Leds = append(tmpInput.Leds, ledName(status.LedListOn[i]))
}
return tmpInput
}
func (w *WebGui) Stop() {
- w.poller.Stop()
close(w.stopChan)
w.wg.Wait()
}
-type statusProcessed struct {
- status datasource.MultiplusStatus
- chargeLevel float64
- err error
- timestamp time.Time
-}
-
// dataPoll waits for data from the w.poller channel. It will send its currently stored status
// to respChan if anything reads from it.
-func (w *WebGui) dataPoll(batteryCapacity float64) {
- tracker := NewChargeTracker(batteryCapacity)
+func (w *WebGui) dataPoll() {
pollChan := w.poller.C()
- var statusP statusProcessed
var muninValues muninData
+ s := &mk2if.Mk2Info{}
for {
select {
- case s := <-pollChan:
- if s.Err != nil {
- statusP.err = s.Err
- } else {
- statusP.status = s.MpStatus
- statusP.err = nil
- statusP.timestamp = s.Time
- tracker.Update(s.MpStatus.BatCurrent, s.Time)
- if s.MpStatus.Leds[Float] == 1 {
- tracker.Reset()
- }
- statusP.chargeLevel = tracker.CurrentLevel()
- calcMuninValues(&muninValues, &statusP)
- w.pu.updatePrometheus(&statusP)
+ case s = <-pollChan:
+ if s.Valid {
+ calcMuninValues(&muninValues, s)
+ w.pu.updatePrometheus(s)
}
- case w.respChan <- statusP:
+ case w.respChan <- s:
case w.muninRespChan <- muninValues:
zeroMuninValues(&muninValues)
case <-w.stopChan:
diff --git a/webgui/webgui_test.go b/webgui/webgui_test.go
index 09e55ac..dc7c019 100644
--- a/webgui/webgui_test.go
+++ b/webgui/webgui_test.go
@@ -31,57 +31,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package webgui
import (
- "github.com/hpdvanwyk/invertergui/datasource"
+ "fmt"
+ "github.com/hpdvanwyk/invertergui/mk2if"
"reflect"
"testing"
"time"
)
-type mockSource struct {
-}
-
-func NewMockSource() datasource.DataSource {
- return &mockSource{}
-}
-
-func (s *mockSource) GetData(status *datasource.MultiplusStatus) error {
- status.OutCurrent = 2.0
- status.InCurrent = 2.3
- status.OutVoltage = 230.0
- status.InVoltage = 230.1
- status.BatVoltage = 25
- status.BatCurrent = -10
- status.InFreq = 50
- status.OutFreq = 50
- status.Leds = []int{0, 0, 0, 0, 1, 0, 0, 1}
- return nil
-}
-
func TestWebGui(t *testing.T) {
t.Skip("Not yet implimented")
//TODO figure out how to test template output.
}
type templateTest struct {
- input *statusProcessed
+ input *mk2if.Mk2Info
output *templateInput
}
var fakenow = time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC)
var templateInputTests = []templateTest{
{
- input: &statusProcessed{
- status: datasource.MultiplusStatus{
- OutCurrent: 2.0,
- InCurrent: 2.3,
- OutVoltage: 230.0,
- InVoltage: 230.1,
- BatVoltage: 25,
- BatCurrent: -10,
- InFreq: 50,
- OutFreq: 50,
- Leds: []int{0, 0, 0, 0, 1, 0, 0, 1}},
- err: nil,
+ input: &mk2if.Mk2Info{
+ OutCurrent: 2.0,
+ InCurrent: 2.3,
+ OutVoltage: 230.0,
+ InVoltage: 230.1,
+ BatVoltage: 25,
+ BatCurrent: -10,
+ InFrequency: 50,
+ OutFrequency: 50,
+ ChargeState: 1,
+ LedListOn: []int{mk2if.LED_MAIN, mk2if.LED_FLOAT},
+ Errors: nil,
+ Timestamp: fakenow,
},
output: &templateInput{
Error: nil,
@@ -97,16 +79,18 @@ var templateInputTests = []templateTest{
BatCurrent: "-10.000",
BatPower: "-250.000",
InFreq: "50.000",
- BatCharge: "0.000",
+ OutFreq: "50.000",
+ BatCharge: "100.000",
Leds: []string{"Mains", "Float"}},
},
}
func TestTemplateInput(t *testing.T) {
for i := range templateInputTests {
- templateInput := buildTemplateInput(templateInputTests[i].input, fakenow)
+ templateInput := buildTemplateInput(templateInputTests[i].input)
if !reflect.DeepEqual(templateInput, templateInputTests[i].output) {
t.Errorf("buildTemplateInput not producing expected results")
+ fmt.Printf("%v\n%v\n", templateInput, templateInputTests[i].output)
}
}
}