summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-11-29 15:17:06 -0500
committerSam Anthony <sam@samanthony.xyz>2024-11-29 15:17:06 -0500
commitcee1d301809ec0b517962816b1b232c22a41eb3b (patch)
tree767c424653b71555919ae81261d0300aefc1faf0
parent6c8ae5c3a0d40c34a8db1aa4eac27734c321ca7b (diff)
downloadsoen422-cee1d301809ec0b517962816b1b232c22a41eb3b.zip
server: record duty cycle over time
-rw-r--r--server/chart.go49
-rw-r--r--server/dashboard.go10
-rw-r--r--server/dashboard.html15
-rw-r--r--server/duty.go5
-rw-r--r--server/server.go5
5 files changed, 70 insertions, 14 deletions
diff --git a/server/chart.go b/server/chart.go
index d417021..4d7298b 100644
--- a/server/chart.go
+++ b/server/chart.go
@@ -11,11 +11,15 @@ import (
"time"
)
-type ChartHandler struct {
+type HumidityChartHandler struct {
building Building
}
-func (h ChartHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+type DutyCycleChartHandler struct {
+ dc Record[DutyCycle]
+}
+
+func (h HumidityChartHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println(r.Method, r.URL)
if r.Method != http.MethodGet {
@@ -33,7 +37,7 @@ func (h ChartHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ValueFormatter: chart.TimeMinuteValueFormatter,
},
YAxis: chart.YAxis{
- Range: &chart.ContinuousRange{Min: 0.0, Max: 100.0},
+ Range: &chart.ContinuousRange{Min: minHumidity, Max: maxHumidity},
},
}
graph.Elements = []chart.Renderable{
@@ -46,6 +50,45 @@ func (h ChartHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
+func (h DutyCycleChartHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ log.Println(r.Method, r.URL)
+
+ if r.Method != http.MethodGet {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ fmt.Fprintf(w, "invalid method: '%s'", r.Method)
+ return
+ }
+
+ var x []time.Time
+ var y []float64
+ c := make(chan Entry[DutyCycle])
+ h.dc.get <- c
+ for e := range c {
+ x = append(x, e.t)
+ y = append(y, float64(e.v))
+ }
+
+ graph := chart.Chart{
+ Background: chart.Style{
+ Padding: chart.Box{Top: 20, Left: 20},
+ },
+ Series: []chart.Series{
+ chart.TimeSeries{XValues: x, YValues: y},
+ },
+ XAxis: chart.XAxis{
+ ValueFormatter: chart.TimeMinuteValueFormatter,
+ },
+ YAxis: chart.YAxis{
+ Range: &chart.ContinuousRange{Min: minDutyCycle, Max: maxDutyCycle},
+ },
+ }
+
+ w.Header().Set("Content-Type", "image/png")
+ if err := graph.Render(chart.PNG, w); err != nil {
+ log.Println(err)
+ }
+}
+
// Build a time series for each humidity record in the building.
// The returned series' are sorted by room name.
func buildSortedSeries(building Building) []chart.Series {
diff --git a/server/dashboard.go b/server/dashboard.go
index 1dca024..a31625b 100644
--- a/server/dashboard.go
+++ b/server/dashboard.go
@@ -24,7 +24,7 @@ type Dashboard struct {
type DashboardHandler struct {
target share.Val[Humidity]
building Building
- dutyCycle share.Val[DutyCycle]
+ dutyCycle Record[DutyCycle]
}
func (h DashboardHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -56,10 +56,12 @@ func (h DashboardHandler) buildDashboard() Dashboard {
average = -1
}
+ c := make(chan Entry[DutyCycle])
+ h.dutyCycle.getRecent <- c
var duty DutyCycle
- if dutyp, ok := h.dutyCycle.TryGet(); ok {
- duty = *dutyp
- } else {
+ if e, ok := <-c; ok {
+ duty = e.v
+ } else {
duty = -1
}
diff --git a/server/dashboard.html b/server/dashboard.html
index f208758..cac92d1 100644
--- a/server/dashboard.html
+++ b/server/dashboard.html
@@ -2,6 +2,15 @@
<html>
<head>
<title>HVAC Dashboard</title>
+ <style>
+.center {
+ text-align: center;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ width: 90%;
+}
+ </style>
</head>
<body>
<p>Target humidity: {{ printf "%.1f%%" .Target }}</p>
@@ -39,7 +48,9 @@
{{ end }}
</table>
<hr/>
- <h4 style="text-align: center;">Humidity per Room vs. Time</h4>
- <img src="/chart.png" alt="chart of humidity vs time"/>
+ <h4 class="center">Humidity per Room vs. Time</h4>
+ <img src="/humidity_chart.png" alt="chart of humidity vs time" class="center"/>
+ <h4 class="center">Duty Cycle vs. Time</h4>
+ <img src="/duty_cycle_chart.png" alt="chart of duty cycle vs time" class="center"/>
</body>
</html>
diff --git a/server/duty.go b/server/duty.go
index 55022f3..532bfbc 100644
--- a/server/duty.go
+++ b/server/duty.go
@@ -2,7 +2,6 @@ package main
import (
"fmt"
- "github.com/sam-rba/share"
"log"
"net/http"
"strconv"
@@ -16,7 +15,7 @@ const (
type DutyCycle float32
type DutyCycleHandler struct {
- dc share.Val[DutyCycle]
+ dc Record[DutyCycle]
}
func (h DutyCycleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -34,7 +33,7 @@ func (h DutyCycleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
- h.dc.Set <- DutyCycle(dc)
+ h.dc.put <- DutyCycle(dc)
}
func isValidDutyCycle(dc float64) bool {
diff --git a/server/server.go b/server/server.go
index a9a8b2e..217801a 100644
--- a/server/server.go
+++ b/server/server.go
@@ -24,7 +24,7 @@ func main() {
target := share.NewVal[Humidity]()
target.Set <- targetHumidityDefault
building := newBuilding(roomIDs)
- dutyCycle := share.NewVal[DutyCycle]()
+ dutyCycle := newRecord[DutyCycle](historySize)
defer target.Close()
defer building.Close()
defer dutyCycle.Close()
@@ -33,7 +33,8 @@ func main() {
http.Handle("/humidity", HumidityHandler{building})
http.Handle("/target_humidity", TargetHumidityHandler{target})
http.Handle("/duty_cycle", DutyCycleHandler{dutyCycle})
- http.Handle("/chart.png", ChartHandler{building})
+ http.Handle("/humidity_chart.png", HumidityChartHandler{building})
+ http.Handle("/duty_cycle_chart.png", DutyCycleChartHandler{dutyCycle})
fmt.Printf("Listening on %s...\n", addr)
log.Fatal(http.ListenAndServe(addr, nil))