import numpy as np import json import os import serial import subprocess import threading import time from humidifier import Humidifier, HumidifierV2 from humidifier_v3 import HumidifierV3 from controller import Controller import utils from utils import start_process, send_update SERIAL_PATH = "/dev/ttyACM0" SERIAL_BAUD = 115200 SAMPLE_PERIOD = 0.5 DECIMATION_RATE = 1 try: is_mock = os.environ['MOCK'] except KeyError: is_mock = False print("controller start") start_process() if is_mock: import mock_serial s = mock_serial.MockSerial() else: s = serial.Serial(SERIAL_PATH, SERIAL_BAUD, timeout = 0.3) print("pausing for bootloader...") time.sleep(10) print("pause done") def reset_serial(): global s if not is_mock: s.close() s = serial.Serial(SERIAL_PATH, SERIAL_BAUD, timeout = 0.3) time.sleep(10) humidifier = HumidifierV3() controller = Controller([humidifier]) exiting = False # run thread to process data from process's stdout def stdout_loop(): global process, controller, humidifier, humidifier2 while not exiting: msg = utils.process.stdout.readline() if len(msg) <= 1: continue print("got message ", msg) try: msg_js = json.loads(msg) if "query_params" in msg_js: if msg_js["query_params"]: send_update({"params": { "target_lower": controller.target_lower, "target_upper": controller.target_upper, "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: if type(msg_js["set_params"]) is dict: set_params = msg_js["set_params"] if "name" in set_params and "value" in set_params: name, value = set_params["name"], set_params["value"] if type(value) is float: if name == "target_lower": controller.target_lower = value elif name == "target_upper": controller.target_upper = 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 name == "off_threshold_volts2": humidifier2.off_threshold = value elif name == "on_threshold_volts2": humidifier2.on_threshold = value elif name == "toggle_cooldown2": humidifier2.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: print("received bad json ", msg) stdout_thread = threading.Thread(target=stdout_loop) stdout_thread.start() def restart_pipe(): global exiting, stdout_thread exiting = True utils.process.kill() time.sleep(0.1) stdout_thread.join() exiting = False start_process() stdout_thread = threading.Thread(target=stdout_loop) stdout_thread.start() frame_num = 0 last_sample = 0 last_pipe_reboot = 0 last_running = False pipe_timeout = 10 fan_on = False try: while True: now = time.time() # check to see if the SSH pipe is working if utils.running(): if not last_running and utils.running(): print("pipe is now running, resetting timeout", pipe_timeout) pipe_timeout = 10 last_running = utils.running() if not utils.running() and (now - last_pipe_reboot) > pipe_timeout: try: restart_pipe() except Exception as e: print("error restarting pipe: {}".format(repr(e))) last_pipe_reboot = now pipe_timeout *= 1.5 pipe_timeout = min(pipe_timeout, 5*60) print("new pipe timeout ", pipe_timeout) now = time.time() if now - last_sample < SAMPLE_PERIOD: time.sleep(SAMPLE_PERIOD - (now - last_sample) + 0.001) continue last_sample = now # turn on the fan 1 minutes every 5 minutes cur_min = int(now / 60) fan_should_be_on = (cur_min % 5 == 0) if fan_on != fan_should_be_on: if fan_should_be_on: s.write(b"Y") else: s.write(b"y") #print("write s") s.write(b"s") s.flush() resp = s.read(120) #print("read", resp) if len(resp) == 0: reset_serial() time.sleep(5) continue parts = resp.split(b",") humidity = float(parts[0]) temp = float(parts[1]) volts = float(parts[2]) volts2 = float(parts[3]) fan_on = int(volts2) #print(parts) try: humidifier.update(volts) controller.update(s, humidity) if frame_num == 0: #print(humidity, temp, volts) update = { "data": { "time": int(now*1000), "temp": temp, "hum": humidity, "hv": volts, "hv2": volts2, } } send_update(update) #print("sending update {}".format(update)) frame_num = (frame_num + 1) % DECIMATION_RATE except Exception as e: print("pipe errored out, restarting: ", repr(e)) # restart the process I guess restart_pipe() finally: # kill ssh connection exiting = True utils.process.kill() stdout_thread.join()