summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-11-26 18:51:15 -0500
committerSam Anthony <sam@samanthony.xyz>2024-11-26 18:51:15 -0500
commita840405f3671bff286ea68f1f6eb0e43975b1a44 (patch)
tree92471b84eff8d922e4c7fff3496d3bbf1babb5be /server
parentd40dee9b7b5327b30e6bcf770dfda14a2e6fed02 (diff)
downloadsoen422-a840405f3671bff286ea68f1f6eb0e43975b1a44.zip
server: chart of humidity vs time
Diffstat (limited to 'server')
-rw-r--r--server/building.go6
-rw-r--r--server/chart.go55
-rw-r--r--server/dashboard.go8
-rw-r--r--server/dashboard.html4
-rw-r--r--server/record.go18
-rw-r--r--server/server.go1
6 files changed, 77 insertions, 15 deletions
diff --git a/server/building.go b/server/building.go
index 8772374..e275c65 100644
--- a/server/building.go
+++ b/server/building.go
@@ -23,10 +23,10 @@ func (b Building) average() (Humidity, bool) {
var sum Humidity = 0
nRooms := 0
for room, record := range b {
- c := make(chan Humidity)
+ c := make(chan Entry[Humidity])
record.getRecent <- c
- if humidity, ok := <-c; ok {
- sum += humidity
+ if e, ok := <-c; ok {
+ sum += e.v
nRooms++
} else {
log.Printf("Warning: no humidity for room '%s'\n", room)
diff --git a/server/chart.go b/server/chart.go
new file mode 100644
index 0000000..1f20d3c
--- /dev/null
+++ b/server/chart.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "log"
+ "net/http"
+ "fmt"
+ "time"
+ "github.com/wcharczuk/go-chart/v2"
+)
+
+type ChartHandler struct {
+ building Building
+}
+
+func (h ChartHandler) 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 series []chart.Series
+ for room, record := range h.building {
+ var x []time.Time
+ var y []float64
+ c := make(chan Entry[Humidity])
+ record.get <- c
+ for e := range c {
+ x = append(x, e.t)
+ y = append(y, float64(e.v))
+ }
+ series = append(series, chart.TimeSeries{
+ Name: string(room),
+ XValues: x,
+ YValues: y,
+ })
+ }
+
+ graph := chart.Chart{
+ Background: chart.Style{
+ Padding: chart.Box{Top: 20, Left: 20},
+ },
+ Series: series,
+ }
+ graph.Elements = []chart.Renderable{
+ chart.Legend(&graph),
+ }
+
+ w.Header().Set("Content-Type", "image/png")
+ if err := graph.Render(chart.PNG, w); err != nil {
+ log.Println(err)
+ }
+}
diff --git a/server/dashboard.go b/server/dashboard.go
index 48a9423..1dca024 100644
--- a/server/dashboard.go
+++ b/server/dashboard.go
@@ -65,10 +65,12 @@ func (h DashboardHandler) buildDashboard() Dashboard {
rooms := make(map[RoomID]Humidity)
for id, record := range h.building {
- c := make(chan Humidity)
+ c := make(chan Entry[Humidity])
record.getRecent <- c
- humidity, ok := <-c
- if !ok {
+ var humidity Humidity
+ if e, ok := <-c; ok {
+ humidity = e.v
+ } else {
humidity = -1
}
rooms[id] = humidity
diff --git a/server/dashboard.html b/server/dashboard.html
index 23e1d97..50ad682 100644
--- a/server/dashboard.html
+++ b/server/dashboard.html
@@ -21,6 +21,7 @@
unknown
{{- end -}}
</p>
+
<table>
<tr><th>Room</th><th>Humidity</th></tr>
{{ range $id, $humidity := .Rooms }}
@@ -37,5 +38,8 @@
</tr>
{{ end }}
</table>
+
+ <h4 style="text-align: center;">Humidity per Room vs. Time</h4>
+ <img src="/chart.png" alt="chart of humidity vs time"/>
</body>
</html>
diff --git a/server/record.go b/server/record.go
index c2f38eb..407dcd7 100644
--- a/server/record.go
+++ b/server/record.go
@@ -6,11 +6,11 @@ import (
type Record[T any] struct {
put chan<- T
- get chan<- chan T
- getRecent chan<- chan T
+ get chan<- chan Entry[T]
+ getRecent chan<- chan Entry[T]
}
-type entry[T any] struct {
+type Entry[T any] struct {
t time.Time
v T
}
@@ -19,11 +19,11 @@ type entry[T any] struct {
// If the capacity is exceeded, old entires will be discarded and new ones kept.
func newRecord[T any](capacity int) Record[T] {
put := make(chan T)
- get := make(chan chan T)
- getRecent := make(chan chan T)
+ get := make(chan chan Entry[T])
+ getRecent := make(chan chan Entry[T])
go func() {
- entries := make([]entry[T], 0, capacity)
+ entries := make([]Entry[T], 0, capacity)
for {
select {
@@ -31,7 +31,7 @@ func newRecord[T any](capacity int) Record[T] {
if !ok {
return
}
- entries = append(entries, entry[T]{time.Now(), v})
+ entries = append(entries, Entry[T]{time.Now(), v})
if len(entries) > capacity {
entries = entries[1:]
}
@@ -40,7 +40,7 @@ func newRecord[T any](capacity int) Record[T] {
return
}
for _, e := range entries {
- c <- e.v
+ c <- e
}
close(c)
case c, ok := <-getRecent:
@@ -48,7 +48,7 @@ func newRecord[T any](capacity int) Record[T] {
return
}
if len(entries) > 0 {
- c <- entries[len(entries)-1].v
+ c <- entries[len(entries)-1]
}
close(c)
}
diff --git a/server/server.go b/server/server.go
index 4ef5151..8cfb1b0 100644
--- a/server/server.go
+++ b/server/server.go
@@ -33,6 +33,7 @@ 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})
fmt.Printf("Listening on %s...\n", addr)
log.Fatal(http.ListenAndServe(addr, nil))