summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-11-07 18:41:53 -0500
committerSam Anthony <sam@samanthony.xyz>2024-11-07 18:41:53 -0500
commit3685ec6c933fe0a6d22df0e41c16f13d7be075cf (patch)
treed4d83fab9be07fa43e595509d73694b41d1517d7
parent4e55b06016f254947a21b3de3eb93392c0b627dc (diff)
downloadsoen422-3685ec6c933fe0a6d22df0e41c16f13d7be075cf.zip
server: refactor
-rw-r--r--Makefile2
-rw-r--r--server/duty.go36
-rw-r--r--server/humidity.go95
-rw-r--r--server/server.go150
-rw-r--r--server/target.go45
5 files changed, 177 insertions, 151 deletions
diff --git a/Makefile b/Makefile
index 91b6c05..cf4ae0d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
SENSOR_SRC = SensorStation/SensorStation.ino
HVAC_SRC = HvacStation/HvacStation.ino
-SERVER_SRC = server/server.go server/record.go
+SERVER_SRC = server/*.go
BOARD = esp32:esp32:lilygo_t_display
PORT = /dev/ttyACM0
diff --git a/server/duty.go b/server/duty.go
new file mode 100644
index 0000000..ae32ecb
--- /dev/null
+++ b/server/duty.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "strconv"
+ "sync"
+)
+
+type DutyCycle float32
+
+type DutyCycleHandler struct {
+ mu sync.Mutex
+ dc DutyCycle
+}
+
+func (h *DutyCycleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ log.Println(r.Method, r.URL)
+
+ if r.Method != http.MethodPost {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ fmt.Fprintf(w, "invalid method: '%s'", r.Method)
+ return
+ }
+
+ dc, err := strconv.ParseFloat(r.URL.RawQuery, 32)
+ if err != nil {
+ badRequest(w, "invalid duty cycle: '%s'", r.URL.RawQuery)
+ return
+ }
+
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ h.dc = DutyCycle(dc)
+}
diff --git a/server/humidity.go b/server/humidity.go
new file mode 100644
index 0000000..079c9bf
--- /dev/null
+++ b/server/humidity.go
@@ -0,0 +1,95 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "strconv"
+)
+
+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()
+ }
+}
+
+func (h HumidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ log.Println(r.Method, r.URL)
+ switch r.Method {
+ case http.MethodGet:
+ h.get(w, r)
+ case http.MethodPost:
+ h.post(w, r)
+ default:
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ fmt.Fprintf(w, "invalid method: '%s'", r.Method)
+ }
+}
+
+func (h HumidityHandler) get(w http.ResponseWriter, r *http.Request) {
+ if humidity, ok := h.average(); ok {
+ fmt.Fprintf(w, "%.2f", humidity)
+ } else {
+ w.WriteHeader(http.StatusGone)
+ fmt.Fprintf(w, "no humidity data stored on server")
+ }
+}
+
+func (h HumidityHandler) post(w http.ResponseWriter, r *http.Request) {
+ queryVals, err := parseQuery(r.URL.RawQuery, []string{"room", "humidity"})
+ if err != nil {
+ badRequest(w, "invalid query: %v", err)
+ return
+ }
+ room := RoomID(queryVals["room"])
+ humidityStr := queryVals["humidity"]
+
+ humidity, err := strconv.ParseFloat(humidityStr, 32)
+ if err != nil {
+ badRequest(w, "invalid humidity: '%s'", humidityStr)
+ return
+ }
+
+ record, ok := h.rooms[room]
+ if !ok {
+ badRequest(w, "invalid room ID: '%s'", room)
+ return
+ }
+
+ 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
+}
diff --git a/server/server.go b/server/server.go
index 88bfaa3..7a70cc6 100644
--- a/server/server.go
+++ b/server/server.go
@@ -5,8 +5,6 @@ import (
"log"
"net/http"
"net/url"
- "strconv"
- "sync"
)
const addr = ":9090"
@@ -16,23 +14,7 @@ var rooms = []RoomID{
"rEKKa5TW5xjArmR25wT4Uiw7tksk4noE",
}
-type Humidity float32
type RoomID string
-type DutyCycle float32
-
-type HumidityHandler struct {
- rooms map[RoomID]Record[Humidity]
-}
-
-type TargetHumidityHandler struct {
- mu sync.Mutex
- target Humidity
-}
-
-type DutyCycleHandler struct {
- mu sync.Mutex
- dc DutyCycle
-}
func main() {
humidityHandler := newHumidityHandler(rooms)
@@ -46,138 +28,6 @@ func main() {
log.Fatal(http.ListenAndServe(addr, nil))
}
-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()
- }
-}
-
-func (h HumidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- log.Println(r.Method, r.URL)
- switch r.Method {
- case http.MethodGet:
- h.get(w, r)
- case http.MethodPost:
- h.post(w, r)
- default:
- w.WriteHeader(http.StatusMethodNotAllowed)
- fmt.Fprintf(w, "invalid method: '%s'", r.Method)
- }
-}
-
-func (h HumidityHandler) get(w http.ResponseWriter, r *http.Request) {
- if humidity, ok := h.average(); ok {
- fmt.Fprintf(w, "%.2f", humidity)
- } else {
- w.WriteHeader(http.StatusGone)
- fmt.Fprintf(w, "no humidity data stored on server")
- }
-}
-
-func (h HumidityHandler) post(w http.ResponseWriter, r *http.Request) {
- queryVals, err := parseQuery(r.URL.RawQuery, []string{"room", "humidity"})
- if err != nil {
- badRequest(w, "invalid query: %v", err)
- return
- }
- room := RoomID(queryVals["room"])
- humidityStr := queryVals["humidity"]
-
- humidity, err := strconv.ParseFloat(humidityStr, 32)
- if err != nil {
- badRequest(w, "invalid humidity: '%s'", humidityStr)
- return
- }
-
- record, ok := h.rooms[room]
- if !ok {
- badRequest(w, "invalid room ID: '%s'", room)
- return
- }
-
- 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
-}
-
-func (h *TargetHumidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- log.Println(r.Method, r.URL)
- switch r.Method {
- case http.MethodGet:
- h.get(w, r)
- case http.MethodPost:
- h.post(w, r)
- default:
- w.WriteHeader(http.StatusMethodNotAllowed)
- fmt.Fprintf(w, "invalid method: '%s'", r.Method)
- }
-}
-
-func (h *TargetHumidityHandler) get(w http.ResponseWriter, r *http.Request) {
- h.mu.Lock()
- defer h.mu.Unlock()
- fmt.Fprintf(w, "%.2f", h.target)
-}
-
-func (h *TargetHumidityHandler) post(w http.ResponseWriter, r *http.Request) {
- target, err := strconv.ParseFloat(r.URL.RawQuery, 32)
- if err != nil {
- badRequest(w, "invalid humidity: '%s'", r.URL.RawQuery)
- return
- }
-
- h.mu.Lock()
- defer h.mu.Unlock()
- h.target = Humidity(target)
-}
-
-func (h *DutyCycleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- log.Println(r.Method, r.URL)
-
- if r.Method != http.MethodPost {
- w.WriteHeader(http.StatusMethodNotAllowed)
- fmt.Fprintf(w, "invalid method: '%s'", r.Method)
- return
- }
-
- dc, err := strconv.ParseFloat(r.URL.RawQuery, 32)
- if err != nil {
- badRequest(w, "invalid duty cycle: '%s'", r.URL.RawQuery)
- return
- }
-
- h.mu.Lock()
- defer h.mu.Unlock()
- h.dc = DutyCycle(dc)
-}
-
// 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/target.go b/server/target.go
new file mode 100644
index 0000000..4c58f1d
--- /dev/null
+++ b/server/target.go
@@ -0,0 +1,45 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "strconv"
+ "sync"
+)
+
+type TargetHumidityHandler struct {
+ mu sync.Mutex
+ target Humidity
+}
+
+func (h *TargetHumidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ log.Println(r.Method, r.URL)
+ switch r.Method {
+ case http.MethodGet:
+ h.get(w, r)
+ case http.MethodPost:
+ h.post(w, r)
+ default:
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ fmt.Fprintf(w, "invalid method: '%s'", r.Method)
+ }
+}
+
+func (h *TargetHumidityHandler) get(w http.ResponseWriter, r *http.Request) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ fmt.Fprintf(w, "%.2f", h.target)
+}
+
+func (h *TargetHumidityHandler) post(w http.ResponseWriter, r *http.Request) {
+ target, err := strconv.ParseFloat(r.URL.RawQuery, 32)
+ if err != nil {
+ badRequest(w, "invalid humidity: '%s'", r.URL.RawQuery)
+ return
+ }
+
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ h.target = Humidity(target)
+}