Implement manual mode controls and thread manual mode status logic from the controller to the front end
This commit is contained in:
parent
251d23446a
commit
3baa19d145
100
dev/admin.htm
100
dev/admin.htm
|
@ -6,14 +6,13 @@ function status(msg) {
|
||||||
document.getElementById('status').textContent = msg
|
document.getElementById('status').textContent = msg
|
||||||
}
|
}
|
||||||
async function queryParams() {
|
async function queryParams() {
|
||||||
const req = await fetch('/api/params')
|
const resp = await fetch('/api/params')
|
||||||
const json = await req.json()
|
|
||||||
//console.log(json)
|
//console.log(json)
|
||||||
//console.log(Object.keys(json))
|
//console.log(Object.keys(json))
|
||||||
if (!req.ok) {
|
if (!resp.ok) {
|
||||||
var err_msg = null
|
var err_msg = null
|
||||||
if (req.body != null) {
|
if (resp.body != null) {
|
||||||
err_msg = await req.text()
|
err_msg = await resp.text()
|
||||||
}
|
}
|
||||||
if (err_msg != null) {
|
if (err_msg != null) {
|
||||||
status("query failed: " + resp.status + " " + err_msg)
|
status("query failed: " + resp.status + " " + err_msg)
|
||||||
|
@ -21,6 +20,7 @@ async function queryParams() {
|
||||||
status("query failed: " + resp.status)
|
status("query failed: " + resp.status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const json = await resp.json()
|
||||||
status('parameter query successful!')
|
status('parameter query successful!')
|
||||||
const paramList = document.getElementById('param-list')
|
const paramList = document.getElementById('param-list')
|
||||||
while (paramList.firstChild) {
|
while (paramList.firstChild) {
|
||||||
|
@ -43,12 +43,10 @@ async function setParam(auth, name, value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log('set param fetch pre')
|
|
||||||
const resp = await fetch('/api/admin', {
|
const resp = await fetch('/api/admin', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: msg
|
body: msg
|
||||||
})
|
})
|
||||||
console.log('set param fetch post')
|
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
var err_msg = null
|
var err_msg = null
|
||||||
if (resp.body != null) {
|
if (resp.body != null) {
|
||||||
|
@ -65,6 +63,78 @@ async function setParam(auth, name, value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var manual_mode = false
|
||||||
|
var manual_loop_running = false
|
||||||
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms))
|
||||||
|
async function manualModeLoop(auth) {
|
||||||
|
if (manual_loop_running) return
|
||||||
|
manual_loop_running = true
|
||||||
|
try {
|
||||||
|
while (manual_mode) {
|
||||||
|
await sleep(60*1000)
|
||||||
|
if (manual_mode) await manualMode(auth, manual_mode)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
manual_loop_running = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function manualMode(auth, on) {
|
||||||
|
const msg = JSON.stringify({
|
||||||
|
auth: auth,
|
||||||
|
data: {
|
||||||
|
manual_mode: on
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const resp = await fetch('/api/admin', {
|
||||||
|
method: 'POST',
|
||||||
|
body: msg
|
||||||
|
})
|
||||||
|
if (!resp.ok) {
|
||||||
|
var err_msg = null
|
||||||
|
if (resp.body != null) {
|
||||||
|
err_msg = await resp.text()
|
||||||
|
}
|
||||||
|
if (err_msg != null) {
|
||||||
|
status("manual mode set failed: " + resp.status + " " + err_msg)
|
||||||
|
} else {
|
||||||
|
status("manual mode set failed: " + resp.status)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status("manual mode set successful!")
|
||||||
|
manual_mode = on
|
||||||
|
if (manual_mode) {
|
||||||
|
manualModeLoop(auth)
|
||||||
|
}
|
||||||
|
//await queryParams()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function manualHumidifier(auth, on) {
|
||||||
|
const msg = JSON.stringify({
|
||||||
|
auth: auth,
|
||||||
|
data: {
|
||||||
|
manual_mode_on: on
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const resp = await fetch('/api/admin', {
|
||||||
|
method: 'POST',
|
||||||
|
body: msg
|
||||||
|
})
|
||||||
|
if (!resp.ok) {
|
||||||
|
var err_msg = null
|
||||||
|
if (resp.body != null) {
|
||||||
|
err_msg = await resp.text()
|
||||||
|
}
|
||||||
|
if (err_msg != null) {
|
||||||
|
status("manual hum set failed: " + resp.status + " " + err_msg)
|
||||||
|
} else {
|
||||||
|
status("manual hum set failed: " + resp.status)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status("manual hum set successful!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
document.getElementById('query-params').addEventListener('click', (e) => {
|
document.getElementById('query-params').addEventListener('click', (e) => {
|
||||||
queryParams()
|
queryParams()
|
||||||
|
@ -80,6 +150,17 @@ window.onload = () => {
|
||||||
}
|
}
|
||||||
setParam(auth, name, value)
|
setParam(auth, name, value)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
document.getElementById('manual-mode').addEventListener('click', (e) => {
|
||||||
|
const auth = document.getElementById('password').value
|
||||||
|
const on = document.getElementById('manual-mode').checked
|
||||||
|
manualMode(auth, on)
|
||||||
|
})
|
||||||
|
document.getElementById('manual-on').addEventListener('click', (e) => {
|
||||||
|
const auth = document.getElementById('password').value
|
||||||
|
const on = document.getElementById('manual-on').checked
|
||||||
|
manualHumidifier(auth, on)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -104,6 +185,11 @@ window.onload = () => {
|
||||||
<input id=value type=text></input><br />
|
<input id=value type=text></input><br />
|
||||||
<input id=set-param type=button value="Set parameter"></input><br />
|
<input id=set-param type=button value="Set parameter"></input><br />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Manual mode</legend>
|
||||||
|
<input id=manual-mode type=checkbox></input><label for=manual-mode>manual mode</label><br />
|
||||||
|
<input id=manual-on type=checkbox></input><label for=manual-on>humidifier on</label><br />
|
||||||
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -77,10 +77,24 @@ class Humidifier:
|
||||||
self.on_threshold = 2.6
|
self.on_threshold = 2.6
|
||||||
self.toggle_cooldown = 7
|
self.toggle_cooldown = 7
|
||||||
|
|
||||||
self.on = False
|
self._on = False
|
||||||
self.history = np.zeros(10)
|
self.history = np.zeros(10)
|
||||||
self.switch_timeout = 0
|
self.switch_timeout = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def on(self):
|
||||||
|
return self._on
|
||||||
|
|
||||||
|
@on.setter
|
||||||
|
def on(self, nv):
|
||||||
|
old_on = self._on
|
||||||
|
self._on = nv
|
||||||
|
if nv:
|
||||||
|
print("send hum on")
|
||||||
|
else:
|
||||||
|
print("send hum off")
|
||||||
|
send_update({"status": {"humidifier": nv}})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def off(self):
|
def off(self):
|
||||||
return not self.on
|
return not self.on
|
||||||
|
@ -93,14 +107,10 @@ class Humidifier:
|
||||||
if self.on:
|
if self.on:
|
||||||
if avg < self.off_threshold:
|
if avg < self.off_threshold:
|
||||||
self.on = False
|
self.on = False
|
||||||
print("send status off")
|
|
||||||
send_update({"status": {"humidifier": False}})
|
|
||||||
self.switch_timeout = time.time() + 1
|
self.switch_timeout = time.time() + 1
|
||||||
else:
|
else:
|
||||||
if avg > self.on_threshold:
|
if avg > self.on_threshold:
|
||||||
self.on = True
|
self.on = True
|
||||||
print("send status on")
|
|
||||||
send_update({"status": {"humidifier": True}})
|
|
||||||
self.switch_timeout = time.time() + 1
|
self.switch_timeout = time.time() + 1
|
||||||
|
|
||||||
def toggle(self, s):
|
def toggle(self, s):
|
||||||
|
@ -114,7 +124,7 @@ class Controller:
|
||||||
self.target_upper = 0.90
|
self.target_upper = 0.90
|
||||||
self.feedforward_coeff = 50
|
self.feedforward_coeff = 50
|
||||||
|
|
||||||
self.manual_mode = False
|
self._manual_mode = False
|
||||||
self.manual_on = False
|
self.manual_on = False
|
||||||
self.manual_timeout = 0
|
self.manual_timeout = 0
|
||||||
self.manual_duration = 120
|
self.manual_duration = 120
|
||||||
|
@ -122,6 +132,15 @@ class Controller:
|
||||||
self.humidifier_history = np.zeros(30)
|
self.humidifier_history = np.zeros(30)
|
||||||
self.first_sample = False
|
self.first_sample = False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def manual_mode(self):
|
||||||
|
return self._manual_mode
|
||||||
|
|
||||||
|
@manual_mode.setter
|
||||||
|
def manual_mode(self, on):
|
||||||
|
self._manual_mode = on
|
||||||
|
send_update({"status": {"manual_mode": on}})
|
||||||
|
|
||||||
def update(self, humidifier, humidity):
|
def update(self, humidifier, humidity):
|
||||||
if self.first_sample:
|
if self.first_sample:
|
||||||
self.humidifier_history[:] = humidity
|
self.humidifier_history[:] = humidity
|
||||||
|
@ -141,7 +160,7 @@ class Controller:
|
||||||
if self.manual_mode:
|
if self.manual_mode:
|
||||||
if humidifier.off and self.manual_on:
|
if humidifier.off and self.manual_on:
|
||||||
humidifier.toggle(s)
|
humidifier.toggle(s)
|
||||||
elif humdifier.on and not self.manual_on:
|
elif humidifier.on and not self.manual_on:
|
||||||
humidifier.toggle(s)
|
humidifier.toggle(s)
|
||||||
else:
|
else:
|
||||||
if comp_humidity < self.target_lower and humidifier.off:
|
if comp_humidity < self.target_lower and humidifier.off:
|
||||||
|
|
|
@ -40,6 +40,7 @@ type ShroomPacket struct {
|
||||||
type ShroomState struct {
|
type ShroomState struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
HumidifierOn bool
|
HumidifierOn bool
|
||||||
|
ManualMode bool
|
||||||
NumConnections int
|
NumConnections int
|
||||||
|
|
||||||
Params map[string]float32
|
Params map[string]float32
|
||||||
|
@ -162,10 +163,12 @@ func parseMsg(line []byte, db *sql.DB, state *ShroomState) {
|
||||||
} else if packet.Status != nil {
|
} else if packet.Status != nil {
|
||||||
//log.Println("received status ", data.Status)
|
//log.Println("received status ", data.Status)
|
||||||
state.Lock()
|
state.Lock()
|
||||||
// TODO change to have more detailed data
|
|
||||||
if packet.Status.HumOn != nil {
|
if packet.Status.HumOn != nil {
|
||||||
state.HumidifierOn = *packet.Status.HumOn
|
state.HumidifierOn = *packet.Status.HumOn
|
||||||
}
|
}
|
||||||
|
if packet.Status.ManualMode != nil {
|
||||||
|
state.ManualMode = *packet.Status.ManualMode
|
||||||
|
}
|
||||||
state.Unlock()
|
state.Unlock()
|
||||||
state.StatusUpdate()
|
state.StatusUpdate()
|
||||||
} else if packet.Params != nil {
|
} else if packet.Params != nil {
|
||||||
|
|
|
@ -30,6 +30,7 @@ var content embed.FS
|
||||||
type statusJson struct {
|
type statusJson struct {
|
||||||
Connected bool `json:"connected"`
|
Connected bool `json:"connected"`
|
||||||
Humidifier bool `json:"humidifier"`
|
Humidifier bool `json:"humidifier"`
|
||||||
|
ManualMode bool `json:"manual_mode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type adminMsg struct {
|
type adminMsg struct {
|
||||||
|
@ -103,10 +104,12 @@ func main() {
|
||||||
state.RLock()
|
state.RLock()
|
||||||
num_connections := state.NumConnections
|
num_connections := state.NumConnections
|
||||||
humidifier := state.HumidifierOn
|
humidifier := state.HumidifierOn
|
||||||
|
manual_mode := state.ManualMode
|
||||||
state.RUnlock()
|
state.RUnlock()
|
||||||
s := statusJson{
|
s := statusJson{
|
||||||
Connected: num_connections > 0,
|
Connected: num_connections > 0,
|
||||||
Humidifier: humidifier,
|
Humidifier: humidifier,
|
||||||
|
ManualMode: manual_mode,
|
||||||
}
|
}
|
||||||
msg, err := json.Marshal(s)
|
msg, err := json.Marshal(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -155,9 +155,7 @@ async function updateCharts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoupdate) {
|
if (autoupdate) {
|
||||||
chart_updater = chartupdater()
|
chartupdater()
|
||||||
} else {
|
|
||||||
chart_updater = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,36 +163,49 @@ const sleep = (ms) => new Promise(r => setTimeout(r, ms))
|
||||||
var chart_update_millis = 2000
|
var chart_update_millis = 2000
|
||||||
|
|
||||||
async function chartupdater() {
|
async function chartupdater() {
|
||||||
if (chart_updater != null) return
|
if (chart_updater) return
|
||||||
|
chart_updater = true
|
||||||
|
|
||||||
await sleep(chart_update_millis)
|
try {
|
||||||
// wait at least two seconds to avoid wasting a lot of bandwidth
|
while (autoupdate) {
|
||||||
const resp = await fetch("/api/update")
|
await sleep(chart_update_millis)
|
||||||
chart_updater = null
|
// wait at least two seconds to avoid wasting a lot of bandwidth
|
||||||
updateCharts()
|
const resp = await fetch("/api/update")
|
||||||
|
updateCharts()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
chart_updater = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var status_updater = null
|
var status_updater = false
|
||||||
async function updateStatus() {
|
async function updateStatus() {
|
||||||
const status_resp = await fetch("/api/status")
|
const status_resp = await fetch("/api/status")
|
||||||
const status = await status_resp.json()
|
const status = await status_resp.json()
|
||||||
//console.log(status)
|
//console.log(status)
|
||||||
const humidifier_state = (status.humidifier ? "on" : "off")
|
const humidifier_state = (status.humidifier ? "on" : "off")
|
||||||
|
const manual_mode_state = (status.manual_mode ? "on" : "off")
|
||||||
//console.log(humidifier_state)
|
//console.log(humidifier_state)
|
||||||
document.getElementById("device-status").textContent = "connected: " + status.connected + ", humidifier: " + humidifier_state
|
document.getElementById("device-status").textContent = "connected: " +
|
||||||
|
status.connected + ", manual mode: " + manual_mode_state + ", humidifier: "
|
||||||
|
+ humidifier_state
|
||||||
|
|
||||||
if (autoupdate) {
|
if (autoupdate) {
|
||||||
status_updater = waitThenUpdateStatus()
|
waitThenUpdateStatus()
|
||||||
} else {
|
|
||||||
status_updater = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitThenUpdateStatus() {
|
async function waitThenUpdateStatus() {
|
||||||
if (status_updater != null) return
|
if (status_updater) return
|
||||||
await fetch("/api/status_update")
|
status_updater = true
|
||||||
status_updater = null
|
try {
|
||||||
updateStatus()
|
while (autoupdate) {
|
||||||
|
await fetch("/api/status_update")
|
||||||
|
updateStatus()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
status_updater = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function testAdminMode() {
|
async function testAdminMode() {
|
||||||
|
|
Loading…
Reference in New Issue