From a88c92f660a8f3b70f7ef39027cd59a20c7f3f5a Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 11:44:09 -0400 Subject: [PATCH] added dostar monitor code --- lib/dotstar_fail.py | 30 ++++++++ lib/dotstar_watcher.py | 129 ++++++++++++++++++++++++++++++++++ lib/init/kiln-display.service | 9 +++ lib/oven.py | 21 ++++-- 4 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 lib/dotstar_fail.py create mode 100644 lib/dotstar_watcher.py create mode 100644 lib/init/kiln-display.service diff --git a/lib/dotstar_fail.py b/lib/dotstar_fail.py new file mode 100644 index 0000000..e059f0f --- /dev/null +++ b/lib/dotstar_fail.py @@ -0,0 +1,30 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" + 5This example blinks the LEDs purple at a 0.5 second interval. + 6 + 7For QT Py Haxpress and a NeoPixel strip. Update pixel_pin and pixel_num to match your wiring if + 8using a different board or form of NeoPixels. + 9 +This example will run on SAMD21 (M0) Express boards (such as Circuit Playground Express or QT Py +Haxpress), but not on SAMD21 non-Express boards (such as QT Py or Trinket). +""" +import config +import adafruit_dotstar + +from adafruit_led_animation.animation.blink import Blink +from adafruit_led_animation.color import PURPLE + +dotstar_num = config.dotstar_num = 27 +dotstar_clk = config.gpio_dotstar_clk = 19 # pin 35 +dotstar_dat = config.gpio_dotstar_dat = 13 # pin 33 + +pixels = adafruit_dotstar.DotStar('D%s' % dotstar_clk, + 'D%s' % dotstar_dat, + dotstar_num) + +blink = Blink(pixels, speed=0.5, color=PURPLE) + +while True: + blink.animate() \ No newline at end of file diff --git a/lib/dotstar_watcher.py b/lib/dotstar_watcher.py new file mode 100644 index 0000000..93c228c --- /dev/null +++ b/lib/dotstar_watcher.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +# import board +import asyncio +import adafruit_dotstar +import config +import ast +from math import ceil +from adafruit_led_animation.helper import PixelSubset +from adafruit_led_animation.animation.rainbowchase import RainbowChase +from adafruit_led_animation.animation.pulse import Pulse +from adafruit_led_animation.animation.comet import Comet +from adafruit_led_animation.animation.blink import Blink + +time_int = 0.5 + + +class KilnStatus: + def __init__(self, status_fp): + self.state = 'STARTUP' + self.heat = False + self.temp = 0.0 + self.target = 0.0 + self.runtime = 0.0 + self.totaltime = 0.0 + self.delay = 0.5 + self.status_fp = status_fp + self.speed = 0.1 + + def check_status(self): + with open(self.status_fp, 'r') as f: + status = ast.literal_eval(f.readline().strip()) + self.state = status['state'] + self.heat = status['heat'] + self.temp = status['temperature'] + self.target = status['target'] + self.totaltime = status['totaltime'] + self.runtime = status['runtime'] + +# {'runtime': 0, +# 'temperature': 78.41890624999999, +# 'target': 0, +# 'state': 'IDLE', +# 'heat': 0, +# 'totaltime': 0, +# 'kwh_rate': 0.1319, +# 'currency_type': '$', +# 'profile': None, +# 'pidstats': {}} + + +async def update_status(kiln_status): + """Monitor button that reverses rainbow direction and changes blink speed. + Assume button is active low. + """ + while True: + kiln_status.check_status() + await asyncio.sleep(time_int) + + +async def task_strip_top(pixels, kiln_status): + while True: + if kiln_status.state == 'STARTUP': + top = RainbowChase(pixels, + kiln_status.speed, + size=2, + spacing=3, + reverse=False, + step=8) + elif kiln_status.state == 'IDLE': + top = Pulse(pixels, + kiln_status.speed, + (135, 135, 135), + period=5) + elif kiln_status.state == 'RUNNING': + top = Comet(pixels, + kiln_status.speed, + (120, 200, 180), + tail_length=10, + reverse=False, + bounce=False, + ring=True) + elif kiln_status.state == 'EMERGENCY RESET': + top = Blink(pixels, + 0.7, + (255, 0, 0)) + top.animate() + await asyncio.sleep(time_int) + + +async def main(): + + # setup + + status_fp = config.status_file + + kiln_status = KilnStatus(status_fp) + + dotstar_num = config.dotstar_num = 27 + dotstar_clk = config.gpio_dotstar_clk = 19 # pin 35 + dotstar_dat = config.gpio_dotstar_dat = 13 # pin 33 + + pixels = adafruit_dotstar.DotStar('D%s' % dotstar_clk, + 'D%s' % dotstar_dat, + dotstar_num) + + substrip_len = ceil(dotstar_num/3.0) + + # strip_left = PixelSubset(pixels, + # 0, + # substrip_len) + + # strip_right = PixelSubset(pixels, + # dotstar_num - substrip_len, + # dotstar_num) + + strip_top = PixelSubset(pixels, + substrip_len, + dotstar_num - substrip_len) + + top_task = asyncio.create_task(task_strip_top(strip_top, + kiln_status)) + check_task = asyncio.create_task(update_status(kiln_status)) + + await asyncio.gather(check_task, top_task) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/lib/init/kiln-display.service b/lib/init/kiln-display.service new file mode 100644 index 0000000..7b93613 --- /dev/null +++ b/lib/init/kiln-display.service @@ -0,0 +1,9 @@ +[Unit] +Description=kiln-display + +[Service] +ExecStart=/home/pi/kiln-controller/venv/bin/python /home/pi/kiln-controller/dotstar_watcher.py +ExecStopPost=/home/pi/kiln-controller/venv/bin/python /home/pi/kiln-controller/dotstar_fail.py + +[Install] +WantedBy=multi-user.target diff --git a/lib/oven.py b/lib/oven.py index 23ce8e5..ff41658 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -253,6 +253,19 @@ class Oven(threading.Thread): self.heat = 0 self.pid = PID(ki=config.pid_ki, kd=config.pid_kd, kp=config.pid_kp) + def e_reset(self): + self.output.safety_on() + self.state = "EMERGENCY RESET" + if self.output.time_disp: + self.output.time_disp.text(self.state) + self.profile = None + self.start_time = 0 + self.runtime = 0 + self.totaltime = 0 + self.target = 0 + self.heat = 0 + self.pid = PID(ki=config.pid_ki, kd=config.pid_kd, kp=config.pid_kp) + def run_profile(self, profile, startat=0): self.reset() self.output.safety_off() @@ -316,19 +329,19 @@ class Oven(threading.Thread): if (self.board.temp_sensor.temperature + config.thermocouple_offset >= config.emergency_shutoff_temp): log.info("emergency!!! temperature too high, shutting down") - self.reset() + self.e_reset() if self.board.temp_sensor.noConnection: log.info("emergency!!! lost connection to thermocouple, shutting down") - self.reset() + self.e_reset() if self.board.temp_sensor.unknownError: log.info("emergency!!! unknown thermocouple error, shutting down") - self.reset() + self.e_reset() if self.board.temp_sensor.bad_percent > 30: log.info("emergency!!! too many errors in a short period, shutting down") - self.reset() + self.e_reset() def reset_if_schedule_ended(self): if self.runtime > self.totaltime: