diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2024-11-29 15:17:06 -0500 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2024-11-29 15:17:06 -0500 |
| commit | cee1d301809ec0b517962816b1b232c22a41eb3b (patch) | |
| tree | 767c424653b71555919ae81261d0300aefc1faf0 | |
| parent | 6c8ae5c3a0d40c34a8db1aa4eac27734c321ca7b (diff) | |
| download | soen422-cee1d301809ec0b517962816b1b232c22a41eb3b.zip | |
server: record duty cycle over time
| -rw-r--r-- | server/chart.go | 49 | ||||
| -rw-r--r-- | server/dashboard.go | 10 | ||||
| -rw-r--r-- | server/dashboard.html | 15 | ||||
| -rw-r--r-- | server/duty.go | 5 | ||||
| -rw-r--r-- | server/server.go | 5 |
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)) |