summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-11-21 16:47:08 -0500
committerSam Anthony <sam@samanthony.xyz>2024-11-21 16:47:08 -0500
commitdbc71139a5708b371ffb0b7580f562674707c558 (patch)
tree1ee13dbfa44588a723a0d1fdf4eb24f5d76a9158 /server
parenta464e144485f69fd9ae6efee3e3fe5e00590e6de (diff)
downloadsoen422-dbc71139a5708b371ffb0b7580f562674707c558.zip
server dashboard
Diffstat (limited to 'server')
-rw-r--r--server/building.go40
-rw-r--r--server/dashboard.go78
-rw-r--r--server/humidity.go41
-rw-r--r--server/server.go9
4 files changed, 126 insertions, 42 deletions
diff --git a/server/building.go b/server/building.go
new file mode 100644
index 0000000..c7d298f
--- /dev/null
+++ b/server/building.go
@@ -0,0 +1,40 @@
+package main
+
+import "log"
+
+type Building map[RoomID]Record[Humidity]
+
+func newBuilding(roomIDs []RoomID) Building {
+ b := make(Building)
+ for _, id := range roomIDs {
+ b[id] = newRecord[Humidity]()
+ }
+ return b
+}
+
+func (b Building) Close() {
+ for _, record := range b {
+ record.Close()
+ }
+}
+
+// Calculate the average humidity in the building. Returns false if there is not enough data available.
+func (b Building) average() (Humidity, bool) {
+ var sum Humidity = 0
+ nRooms := 0
+ for room, record := range b {
+ c := make(chan Humidity)
+ record.getRecent <- c
+ if humidity, ok := <-c; ok {
+ sum += humidity
+ nRooms++
+ } else {
+ log.Printf("Warning: no humidity for room '%s'\n", room)
+ }
+ }
+ if nRooms == 0 {
+ log.Println("Warning: not enough data to calculate average humidity")
+ return -1.0, false
+ }
+ return sum / Humidity(nRooms), true
+}
diff --git a/server/dashboard.go b/server/dashboard.go
new file mode 100644
index 0000000..0e9cd41
--- /dev/null
+++ b/server/dashboard.go
@@ -0,0 +1,78 @@
+package main
+
+import (
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+)
+
+const dashboardHtml = `
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>HVAC Dashboard</title>
+ </head>
+ <body>
+ <p>Average humidity: {{ printf "%.1f %%" .Average }}</p>
+ <table>
+ <tr><th>Room</th><th>Humidity</th></tr>
+ {{ range .Rooms }}
+ <tr><td>{{ .RoomID }}</td><td>{{ printf "%.1f %%" .Humidity }}</td></tr>
+ {{ end }}
+ </table>
+ </body>
+</html>`
+
+var dashboard = template.Must(template.New("dashboard").Parse(dashboardHtml))
+
+type Dashboard struct {
+ Average Humidity
+ Rooms []Room
+}
+
+type Room struct {
+ RoomID
+ Humidity
+}
+
+type DashboardHandler struct {
+ Building
+}
+
+func (h DashboardHandler) 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
+ }
+
+ db := newDashboard(h.Building)
+ err := dashboard.Execute(w, db)
+ if err != nil {
+ log.Println(err)
+ }
+}
+
+func newDashboard(b Building) Dashboard {
+ average, ok := b.average()
+ if !ok {
+ average = -1
+ }
+
+ // TODO: sort by room ID.
+ rooms := make([]Room, 0, len(b))
+ for id, record := range b {
+ c := make(chan Humidity)
+ record.getRecent <- c
+ humidity, ok := <-c
+ if !ok {
+ humidity = -1
+ }
+ rooms = append(rooms, Room{id, humidity})
+ }
+
+ return Dashboard{average, rooms}
+}
diff --git a/server/humidity.go b/server/humidity.go
index 3982545..8cffccc 100644
--- a/server/humidity.go
+++ b/server/humidity.go
@@ -11,21 +11,7 @@ import (
type Humidity float32
type HumidityHandler struct {
- rooms map[RoomID]Record[Humidity]
-}
-
-func newHumidityHandler(rooms []RoomID) HumidityHandler {
- h := HumidityHandler{make(map[RoomID]Record[Humidity])}
- for _, id := range rooms {
- h.rooms[id] = newRecord[Humidity]()
- }
- return h
-}
-
-func (h HumidityHandler) Close() {
- for _, record := range h.rooms {
- record.Close()
- }
+ Building
}
func (h HumidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -42,7 +28,7 @@ func (h HumidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func (h HumidityHandler) get(w http.ResponseWriter, r *http.Request) {
- if humidity, ok := h.average(); ok {
+ if humidity, ok := h.Building.average(); ok {
fmt.Fprintf(w, "%.2f", humidity)
} else {
w.WriteHeader(http.StatusGone)
@@ -65,7 +51,7 @@ func (h HumidityHandler) post(w http.ResponseWriter, r *http.Request) {
return
}
- record, ok := h.rooms[room]
+ record, ok := h.Building[room]
if !ok {
badRequest(w, "invalid room ID: '%s'", room)
return
@@ -74,27 +60,6 @@ func (h HumidityHandler) post(w http.ResponseWriter, r *http.Request) {
record.put <- Humidity(humidity)
}
-// Calculate the average humidity in the building. Returns false if there is not enough data available.
-func (h HumidityHandler) average() (Humidity, bool) {
- var sum Humidity = 0
- nRooms := 0
- for room, record := range h.rooms {
- c := make(chan Humidity)
- record.getRecent <- c
- if humidity, ok := <-c; ok {
- sum += humidity
- nRooms++
- } else {
- log.Printf("Warning: no humidity for room '%s'\n", room)
- }
- }
- if nRooms == 0 {
- log.Println("Warning: not enough data to calculate average humidity")
- return -1.0, false
- }
- return sum / Humidity(nRooms), true
-}
-
// Parse the value associated with each key in the query string. Returns a map of
// keys and values, or error if one of the keys is missing or if there is no value
// associated with one of the keys.
diff --git a/server/server.go b/server/server.go
index 31d53f4..7d5e977 100644
--- a/server/server.go
+++ b/server/server.go
@@ -8,7 +8,7 @@ import (
const addr = ":9090"
-var rooms = []RoomID{
+var roomIDs = []RoomID{
"SNbeEcs7XVWMEvjeEYgwZnp9XYjToVhh",
"rEKKa5TW5xjArmR25wT4Uiw7tksk4noE",
}
@@ -16,10 +16,11 @@ var rooms = []RoomID{
type RoomID string
func main() {
- humidityHandler := newHumidityHandler(rooms)
- defer humidityHandler.Close()
+ building := newBuilding(roomIDs)
+ defer building.Close()
- http.Handle("/humidity", humidityHandler)
+ http.Handle("/", DashboardHandler{building})
+ http.Handle("/humidity", HumidityHandler{building})
http.Handle("/target_humidity", new(TargetHumidityHandler))
http.Handle("/duty_cycle", new(DutyCycleHandler))