Added a primitive battery charge monitor.
This commit is contained in:
@@ -44,7 +44,7 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
source := datasource.NewJSONSource(*url)
|
source := datasource.NewJSONSource(*url)
|
||||||
gui := webgui.NewWebGui(source, 10*time.Second)
|
gui := webgui.NewWebGui(source, 10*time.Second, 100)
|
||||||
http.Handle("/", gui)
|
http.Handle("/", gui)
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
}
|
}
|
||||||
|
|||||||
35
webgui/charge_tracker.go
Normal file
35
webgui/charge_tracker.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package webgui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChargeTracker struct {
|
||||||
|
fullLevel float64
|
||||||
|
currentLevel float64
|
||||||
|
lastUpdate time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new charge tracker. fullLevel is in A h.
|
||||||
|
func NewChargeTracker(fullLevel float64) *ChargeTracker {
|
||||||
|
return &ChargeTracker{
|
||||||
|
fullLevel: fullLevel,
|
||||||
|
currentLevel: fullLevel, // Have to start somewhere.
|
||||||
|
lastUpdate: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChargeTracker) Update(amp float64) {
|
||||||
|
newNow := time.Now()
|
||||||
|
elapsed := newNow.Sub(c.lastUpdate).Hours()
|
||||||
|
c.lastUpdate = newNow
|
||||||
|
c.currentLevel -= elapsed * amp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChargeTracker) CurrentLevel() float64 {
|
||||||
|
return c.currentLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChargeTracker) Reset() {
|
||||||
|
c.currentLevel = c.fullLevel
|
||||||
|
}
|
||||||
@@ -65,6 +65,7 @@ var htmlTemplate string = `<html>
|
|||||||
<dt> Battery Current: {{.BatCurrent}} A</dt>
|
<dt> Battery Current: {{.BatCurrent}} A</dt>
|
||||||
<dt> Battery Voltage: {{.BatVoltage}} V</dt>
|
<dt> Battery Voltage: {{.BatVoltage}} V</dt>
|
||||||
<dt> Battery Power: {{.BatPower}} W</dt>
|
<dt> Battery Power: {{.BatPower}} W</dt>
|
||||||
|
<dt> Battery Charge: {{.BatCharge}} A h</dt>
|
||||||
</dl>
|
</dl>
|
||||||
</body>
|
</body>
|
||||||
</html>`
|
</html>`
|
||||||
|
|||||||
@@ -38,6 +38,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Temperature = iota
|
||||||
|
Low_battery
|
||||||
|
Overload
|
||||||
|
Inverter
|
||||||
|
Float
|
||||||
|
Bulk
|
||||||
|
Absorption
|
||||||
|
Mains
|
||||||
|
)
|
||||||
|
|
||||||
var leds = map[int]string{
|
var leds = map[int]string{
|
||||||
0: "Temperature",
|
0: "Temperature",
|
||||||
1: "Low battery",
|
1: "Low battery",
|
||||||
@@ -57,7 +68,7 @@ type WebGui struct {
|
|||||||
template *template.Template
|
template *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebGui(source datasource.DataSource, pollRate time.Duration) *WebGui {
|
func NewWebGui(source datasource.DataSource, pollRate time.Duration, batteryCapacity float64) *WebGui {
|
||||||
wg := new(WebGui)
|
wg := new(WebGui)
|
||||||
wg.source = source
|
wg.source = source
|
||||||
wg.reqChan = make(chan *statusError)
|
wg.reqChan = make(chan *statusError)
|
||||||
@@ -68,7 +79,7 @@ func NewWebGui(source datasource.DataSource, pollRate time.Duration) *WebGui {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
go wg.dataPoll(pollRate)
|
go wg.dataPoll(pollRate, batteryCapacity)
|
||||||
return wg
|
return wg
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +100,7 @@ type TemplateInput struct {
|
|||||||
BatVoltage string
|
BatVoltage string
|
||||||
BatCurrent string
|
BatCurrent string
|
||||||
BatPower string
|
BatPower string
|
||||||
|
BatCharge string
|
||||||
|
|
||||||
InFreq string
|
InFreq string
|
||||||
|
|
||||||
@@ -126,6 +138,7 @@ func buildTemplateInput(statusErr *statusError) *TemplateInput {
|
|||||||
BatCurrent: fmt.Sprintf("%.3f", status.BatCurrent),
|
BatCurrent: fmt.Sprintf("%.3f", status.BatCurrent),
|
||||||
BatVoltage: fmt.Sprintf("%.3f", status.BatVoltage),
|
BatVoltage: fmt.Sprintf("%.3f", status.BatVoltage),
|
||||||
BatPower: fmt.Sprintf("%.3f", status.BatVoltage*status.BatCurrent),
|
BatPower: fmt.Sprintf("%.3f", status.BatVoltage*status.BatCurrent),
|
||||||
|
BatCharge: fmt.Sprintf("%.3f", statusErr.chargeLevel),
|
||||||
}
|
}
|
||||||
for i := 7; i >= 0; i-- {
|
for i := 7; i >= 0; i-- {
|
||||||
if status.Leds[i] == 1 {
|
if status.Leds[i] == 1 {
|
||||||
@@ -140,14 +153,16 @@ func (w *WebGui) Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type statusError struct {
|
type statusError struct {
|
||||||
status datasource.MultiplusStatus
|
status datasource.MultiplusStatus
|
||||||
err error
|
chargeLevel float64
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// dataPoll will issue a request for a new status every pollRate. It will send its currently stored status
|
// dataPoll will issue a request for a new status every pollRate. It will send its currently stored status
|
||||||
// to respChan if anything reads from it.
|
// to respChan if anything reads from it.
|
||||||
func (w *WebGui) dataPoll(pollRate time.Duration) {
|
func (w *WebGui) dataPoll(pollRate time.Duration, batteryCapacity float64) {
|
||||||
ticker := time.NewTicker(pollRate)
|
ticker := time.NewTicker(pollRate)
|
||||||
|
tracker := NewChargeTracker(batteryCapacity)
|
||||||
var statusErr statusError
|
var statusErr statusError
|
||||||
go w.getStatus()
|
go w.getStatus()
|
||||||
gettingStatus := true
|
gettingStatus := true
|
||||||
@@ -164,6 +179,11 @@ func (w *WebGui) dataPoll(pollRate time.Duration) {
|
|||||||
} else {
|
} else {
|
||||||
statusErr.status = s.status
|
statusErr.status = s.status
|
||||||
statusErr.err = nil
|
statusErr.err = nil
|
||||||
|
tracker.Update(s.status.BatCurrent)
|
||||||
|
if s.status.Leds[Float] == 1 {
|
||||||
|
tracker.Reset()
|
||||||
|
}
|
||||||
|
statusErr.chargeLevel = tracker.CurrentLevel()
|
||||||
}
|
}
|
||||||
gettingStatus = false
|
gettingStatus = false
|
||||||
case w.respChan <- statusErr:
|
case w.respChan <- statusErr:
|
||||||
|
|||||||
Reference in New Issue
Block a user