From 865dd1994a19578cd4f9be70d67c185cb4359ef7 Mon Sep 17 00:00:00 2001 From: Stian Fredrik Aune Date: Sun, 1 Jan 2023 01:03:13 +0100 Subject: [PATCH] Mill: maybe wifi? --- services/mill/online.go | 2 + services/mill/wifi.go | 151 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 152 insertions(+), 1 deletion(-) diff --git a/services/mill/online.go b/services/mill/online.go index 62c709a..0bbd789 100644 --- a/services/mill/online.go +++ b/services/mill/online.go @@ -85,6 +85,8 @@ func (o *OnlineBridge) Start() { o.started = true go func() { defer func() { + recover() + log.Printf("Mill: %s stopped unexpectedly", o.ID) o.started = false }() diff --git a/services/mill/wifi.go b/services/mill/wifi.go index 84c3d3a..5bd2532 100644 --- a/services/mill/wifi.go +++ b/services/mill/wifi.go @@ -1,16 +1,27 @@ package mill import ( + "bytes" + "encoding/json" + "fmt" lucifer3 "git.aiterp.net/lucifer3/server" "git.aiterp.net/lucifer3/server/device" + "git.aiterp.net/lucifer3/server/events" + "git.aiterp.net/lucifer3/server/internal/gentools" + "log" + "math" + "net/http" "strings" "sync" + "time" ) type WifiBridge struct { ID string IP string + state *device.State + mx sync.Mutex started bool bus *lucifer3.EventBus @@ -21,7 +32,7 @@ func (w *WifiBridge) SetBus(bus *lucifer3.EventBus) { } func (w *WifiBridge) SetState(id string, state device.State) bool { - if !strings.HasPrefix(id, "mill:3:"+w.IP) { + if !strings.HasPrefix(id, w.ID) { return false } @@ -29,11 +40,149 @@ func (w *WifiBridge) SetState(id string, state device.State) bool { } func (w *WifiBridge) Start() { + if err := w.refresh(); err != nil { + w.bus.RunEvent(deviceFailed(w.ID, err)) + return + } + + w.started = true go func() { + defer func() { + recover() + log.Printf("Mill: %s stopped unexpectedly", o.ID) + w.started = false + }() + + for { + time.Sleep(1 * time.Minute) + + if err := w.refresh(); err != nil { + w.bus.RunEvent(deviceFailed(w.ID, err)) + break + } + } }() } func (w *WifiBridge) IsStarted() bool { return w.started } + +func (w *WifiBridge) refresh() error { + w.mx.Lock() + defer w.mx.Unlock() + + temp, err := w.getTemperature() + if err != nil { + return err + } + + if w.state != nil { + w.state = &device.State{ + Temperature: gentools.Ptr(temp), + } + + w.bus.RunEvent(events.DeviceReady{ID: w.ID}) + w.bus.RunEvent(events.HardwareMetadata{ID: w.ID, Icon: "heater"}) + w.bus.RunEvent(events.HardwareState{ + ID: w.ID, + InternalName: "Mill heater @ " + w.IP, + SupportFlags: device.SFlagTemperature, + State: *w.state, + }) + } + + w.state.Temperature = gentools.Ptr(*w.state.Temperature - math.Mod(*w.state.Temperature, 0.5)) + + if math.Abs(temp-*w.state.Temperature) >= 0.1 { + if err := w.writeTemperature(); err != nil { + return err + } + } +} + +func (w *WifiBridge) getTemperature() (float64, error) { + body, err := json.Marshal(getSetTemperatureBody{Type: "Normal"}) + if err != nil { + return 0.0, err + } + + req, err := http.NewRequest( + "GET", + "http://%s/set-temperature", + bytes.NewReader(body), + ) + if err != nil { + return 0.0, err + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + return 0.0, err + } + + var resBody getSetTemperatureResponse + err = json.NewDecoder(res.Body).Decode(&resBody) + if err != nil || resBody.Status != "ok" { + return 0.0, fmt.Errorf("refresh failed %s (bad response from query)", w.ID) + } + + return resBody.Value, nil +} + +func (w *WifiBridge) writeTemperature() error { + body, err := json.Marshal(postSetTemperatureBody{ + Type: "Normal", + Value: *w.state.Temperature, + }) + if err != nil { + return err + } + + req, err := http.NewRequest( + "POST", + "http://%s/set-temperature", + bytes.NewReader(body), + ) + if err != nil { + return err + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + + var resBody postSetTemperatureResponse + err = json.NewDecoder(res.Body).Decode(&resBody) + if err != nil || resBody.Status != "ok" { + return fmt.Errorf("refresh failed %s (bad response from query)", w.ID) + } + + w.bus.RunEvent(events.HardwareState{ + ID: w.ID, + InternalName: "Mill heater @ " + w.IP, + SupportFlags: device.SFlagTemperature, + State: *w.state, + }) + return nil +} + +type getSetTemperatureBody struct { + Type string `json:"type"` +} + +type postSetTemperatureBody struct { + Type string `json:"type"` + Value float64 `json:"value"` +} + +type getSetTemperatureResponse struct { + Value float64 `json:"value"` + Status string `json:"status"` +} + +type postSetTemperatureResponse struct { + Status string `json:"status"` +}