Parameterize everything

This commit is contained in:
Kelvin Ly 2023-05-16 14:49:25 -04:00
parent 80916bc3fa
commit 251d23446a
1 changed files with 87 additions and 35 deletions

View File

@ -73,6 +73,10 @@ def reset_serial():
class Humidifier: class Humidifier:
def __init__(self): def __init__(self):
self.off_threshold = 0.2
self.on_threshold = 2.6
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
@ -87,13 +91,13 @@ class Humidifier:
#print(self.history) #print(self.history)
avg = np.sum(self.history)/self.history.shape[0] avg = np.sum(self.history)/self.history.shape[0]
if self.on: if self.on:
if avg < 0.2: if avg < self.off_threshold:
self.on = False self.on = False
print("send status off") print("send status off")
send_update({"status": {"humidifier": False}}) send_update({"status": {"humidifier": False}})
self.switch_timeout = time.time() + 1 self.switch_timeout = time.time() + 1
else: else:
if avg > 2.6: if avg > self.on_threshold:
self.on = True self.on = True
print("send status on") print("send status on")
send_update({"status": {"humidifier": True}}) send_update({"status": {"humidifier": True}})
@ -102,17 +106,56 @@ class Humidifier:
def toggle(self, s): def toggle(self, s):
if time.time() > self.switch_timeout: if time.time() > self.switch_timeout:
s.write(b"h") s.write(b"h")
self.switch_timeout = time.time() + 7 self.switch_timeout = time.time() + self.toggle_cooldown
class Controller:
def __init__(self):
self.target_lower = 0.85
self.target_upper = 0.90
self.feedforward_coeff = 50
self.manual_mode = False
self.manual_on = False
self.manual_timeout = 0
self.manual_duration = 120
self.humidifier_history = np.zeros(30)
self.first_sample = False
def update(self, humidifier, humidity):
if self.first_sample:
self.humidifier_history[:] = humidity
self.first_sample = False
else:
self.humidifier_history[:-1] = self.humidifier_history[1:]
self.humidifier_history[-1] = humidity
# compensate for the slow response time by adding a little feed forward
# using the slope of the humidifier data
slope = (self.humidifier_history[-1] - self.humidifier_history[0])/self.humidifier_history.shape[0]
comp_humidity = humidity + self.feedforward_coeff*slope
if self.manual_mode and time.time() > self.manual_timeout:
self.manual_mode = False
if self.manual_mode:
if humidifier.off and self.manual_on:
humidifier.toggle(s)
elif humdifier.on and not self.manual_on:
humidifier.toggle(s)
else:
if comp_humidity < self.target_lower and humidifier.off:
humidifier.toggle(s)
elif comp_humidity > self.target_upper and humidifier.on:
humidifier.toggle(s)
humidifier = Humidifier() humidifier = Humidifier()
target_lower = 0.85 controller = Controller()
target_upper = 0.90
feedforward_coeff = 50
exiting = False exiting = False
# run thread to process data from process's stdout # run thread to process data from process's stdout
def stdout_loop(): def stdout_loop():
global process, target_lower, target_upper, feedforward_coeff global process, controller, humidifier
while not exiting: while not exiting:
msg = process.stdout.readline() msg = process.stdout.readline()
if len(msg) == 0: if len(msg) == 0:
@ -123,33 +166,56 @@ def stdout_loop():
if "query_params" in msg_js: if "query_params" in msg_js:
if msg_js["query_params"]: if msg_js["query_params"]:
send_update({"params": { send_update({"params": {
"target_lower": target_lower, "target_lower": controller.target_lower,
"target_upper": target_upper, "target_upper": controller.target_upper,
"feedforward_coeff": feedforward_coeff "feedforward_coeff": controller.feedforward_coeff,
"manual_timeout": controller.manual_timeout,
"manual_duration_s": controller.manual_duration,
"manual_mode": 1.0 if controller.manual_mode else 0.0,
"manual_hum_on": 1.0 if controller.manual_on else 0.0,
"off_threshold_volts": humidifier.off_threshold,
"on_threshold_volts": humidifier.on_threshold,
"toggle_cooldown": humidifier.toggle_cooldown
} }
}) })
elif "set_params" in msg_js: elif "set_params" in msg_js:
if type(msg_js["set_params"]) is dict: if type(msg_js["set_params"]) is dict:
set_params = msg_js["set_params"] set_params = msg_js["set_params"]
if "name" in set_params and "value" in set_params: if "name" in set_params and "value" in set_params:
if type(set_params["value"]) is float: name, value = set_params["name"], set_params["value"]
if set_params["name"] == "target_lower": if type(value) is float:
target_lower = set_params["value"] if name == "target_lower":
elif set_params["name"] == "target_upper": controller.target_lower = value
target_upper = set_params["value"] elif name == "target_upper":
elif set_params["name"] == "feedforward_coeff": controller.target_upper = value
feedforward_coeff = set_params["value"] elif name == "feedforward_coeff":
controller.feedforward_coeff = value
elif name == "manual_timeout":
controller.manual_timeout = value
elif name == "manual_duration_s":
controller.manual_duration = value
elif name == "off_threshold_volts":
humidifier.off_threshold = value
elif name == "on_threshold_volts":
humidifier.on_threshold = value
elif name == "toggle_cooldown":
humidifier.toggle_cooldown = value
elif "manual_mode" in msg_js:
controller.manual_mode = msg_js["manual_mode"]
if controller.manual_mode:
controller.manual_timeout = time.time() + controller.manual_duration
elif "manual_mode_on" in msg_js:
controller.manual_on = msg_js["manual_mode_on"]
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
print("received bad json ", msg) print("received bad json ", msg)
stdout_thread = threading.Thread(target=stdout_loop) stdout_thread = threading.Thread(target=stdout_loop)
stdout_thread.start() stdout_thread.start()
humidifier_history = np.zeros(30)
first_sample = False
frame_num = 0 frame_num = 0
last_sample = 0
try: try:
last_sample = 0
while True: while True:
now = time.time() now = time.time()
if now - last_sample < SAMPLE_PERIOD: if now - last_sample < SAMPLE_PERIOD:
@ -167,24 +233,10 @@ try:
humidity = float(parts[0]) humidity = float(parts[0])
temp = float(parts[1]) temp = float(parts[1])
volts = float(parts[2]) volts = float(parts[2])
if first_sample:
humidifier_history[:] = humidity
first_sample = False
else:
humidifier_history[:-1] = humidifier_history[1:]
humidifier_history[-1] = humidity
# compensate for the slow response time by adding a little feed forward
# using the slope of the humidifier data
slope = (humidifier_history[-1] - humidifier_history[0])/humidifier_history.shape[0]
comp_humidity = humidity + feedforward_coeff*slope
try: try:
humidifier.update(volts) humidifier.update(volts)
if comp_humidity < target_lower and humidifier.off: controller.update(humidifier, humidity)
humidifier.toggle(s)
elif comp_humidity > target_upper and humidifier.on:
humidifier.toggle(s)
if frame_num == 0: if frame_num == 0:
print(humidity, temp, volts) print(humidity, temp, volts)