|
@ -1,16 +1,27 @@ |
|
|
package mill |
|
|
package mill |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
|
|
|
"bytes" |
|
|
|
|
|
"encoding/json" |
|
|
|
|
|
"fmt" |
|
|
lucifer3 "git.aiterp.net/lucifer3/server" |
|
|
lucifer3 "git.aiterp.net/lucifer3/server" |
|
|
"git.aiterp.net/lucifer3/server/device" |
|
|
"git.aiterp.net/lucifer3/server/device" |
|
|
|
|
|
"git.aiterp.net/lucifer3/server/events" |
|
|
|
|
|
"git.aiterp.net/lucifer3/server/internal/gentools" |
|
|
|
|
|
"log" |
|
|
|
|
|
"math" |
|
|
|
|
|
"net/http" |
|
|
"strings" |
|
|
"strings" |
|
|
"sync" |
|
|
"sync" |
|
|
|
|
|
"time" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
type WifiBridge struct { |
|
|
type WifiBridge struct { |
|
|
ID string |
|
|
ID string |
|
|
IP string |
|
|
IP string |
|
|
|
|
|
|
|
|
|
|
|
state *device.State |
|
|
|
|
|
|
|
|
mx sync.Mutex |
|
|
mx sync.Mutex |
|
|
started bool |
|
|
started bool |
|
|
bus *lucifer3.EventBus |
|
|
bus *lucifer3.EventBus |
|
@ -21,7 +32,7 @@ func (w *WifiBridge) SetBus(bus *lucifer3.EventBus) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (w *WifiBridge) SetState(id string, state device.State) bool { |
|
|
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 |
|
|
return false |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -29,11 +40,149 @@ func (w *WifiBridge) SetState(id string, state device.State) bool { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (w *WifiBridge) Start() { |
|
|
func (w *WifiBridge) Start() { |
|
|
|
|
|
if err := w.refresh(); err != nil { |
|
|
|
|
|
w.bus.RunEvent(deviceFailed(w.ID, err)) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
w.started = true |
|
|
go func() { |
|
|
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 { |
|
|
func (w *WifiBridge) IsStarted() bool { |
|
|
return w.started |
|
|
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"` |
|
|
|
|
|
} |