You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

190 lines
3.6 KiB

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
}
func (w *WifiBridge) SetBus(bus *lucifer3.EventBus) {
w.bus = bus
}
func (w *WifiBridge) SetState(id string, state device.State) bool {
if !strings.HasPrefix(id, w.ID) {
return false
}
return true
}
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", w.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
}
}
return nil
}
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",
fmt.Sprintf("http://%s/set-temperature", w.IP),
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",
fmt.Sprintf("http://%s/set-temperature", w.IP),
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"`
}