From 884f4fe3be2f8a76d36fd68c0b3f82ddd8e5a512 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 8 Jan 2022 16:33:53 -0500 Subject: [PATCH 01/57] added pinouts for kiln hat PCB --- config.py | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/config.py b/config.py index 1931eeeb..c6d4421f 100644 --- a/config.py +++ b/config.py @@ -29,22 +29,41 @@ # can use whichever GPIO you prefer/have available. ### Outputs -gpio_heat = 23 # Switches zero-cross solid-state-relay + +## Mosfet outputs +gpio_heat = 17 # pin 11 Switches zero-cross solid-state-relay +gpio_erelay = 27 # pin 13 +gpio_fan = 22 # pin 15 + +## Display outputs +gpio_disp1_clk = 20 # pin 38 +gpio_disp1_dat = 21 # pin 40 + +gpio_disp2_clk = 16 # pin 36 +gpio_disp2_dat = 26 # pin 37 + +gpio_dotstar_clk = 19 # pin 35 +gpio_dotstar_dat = 13 # pin 33 + +## I2C pins +gpio_i2c_sda1 = 2 # pin 3 +gpio_i2c_scl1 = 3 # pin 5 + ### Thermocouple Adapter selection: # max31855 - bitbang SPI interface # max31856 - bitbang SPI interface. must specify thermocouple_type. -max31855 = 1 -max31856 = 0 +max31855 = 0 +max31856 = 1 # see lib/max31856.py for other thermocouple_type, only applies to max31856 # uncomment this if using MAX-31856 -#thermocouple_type = MAX31856.MAX31856_S_TYPE +thermocouple_type = MAX31856.MAX31856_K_TYPE ### Thermocouple Connection (using bitbang interfaces) -gpio_sensor_cs = 27 -gpio_sensor_clock = 22 -gpio_sensor_data = 17 -gpio_sensor_di = 10 # only used with max31856 +gpio_sensor_cs = 8 # pin 24 +gpio_sensor_clock = 11 # pin 23 +gpio_sensor_data = 9 # pin 21 +gpio_sensor_di = 10 # pin 19 ######################################################################## # From 4d201abdc91c5eebeae0047ed2f1c1c12c2ef3ed Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 8 Jan 2022 19:02:23 -0500 Subject: [PATCH 02/57] added e relay code --- config.py | 1 + lib/oven.py | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/config.py b/config.py index 1931eeeb..9d7da2d5 100644 --- a/config.py +++ b/config.py @@ -30,6 +30,7 @@ ### Outputs gpio_heat = 23 # Switches zero-cross solid-state-relay +gpio_e_relay = 27 # pin 13; emergency cutoff relay ### Thermocouple Adapter selection: # max31855 - bitbang SPI interface diff --git a/lib/oven.py b/lib/oven.py index af2b42f6..e20d36a1 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -20,6 +20,7 @@ def load_libs(self): GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(config.gpio_heat, GPIO.OUT) + GPIO.setup(config.gpio_e_relay, GPIO.OUT) self.active = True self.GPIO = GPIO except: @@ -27,6 +28,14 @@ def load_libs(self): log.warning(msg) self.active = False + def safety_off(self): + '''Energizes the safety relay''' + self.GPIO.output(config.gpio_e_relay, self.GPIO.HIGH) + + def safety_on(self): + '''Deenergizes the safety relay''' + self.GPIO.output(config.gpio_e_relay, self.GPIO.LOW) + def heat(self,sleepfor): self.GPIO.output(config.gpio_heat, self.GPIO.HIGH) time.sleep(sleepfor) @@ -384,12 +393,14 @@ def __init__(self): # call parent init Oven.__init__(self) + self.output.safety_off() # start thread self.start() def reset(self): super().reset() + self.output.safety_on() self.output.cool(0) def heat_then_cool(self): From f7f63a00f9ca7bc40abbe497cf62bb903cacaf4c Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 8 Jan 2022 19:05:02 -0500 Subject: [PATCH 03/57] added comment --- config.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config.py b/config.py index 9d7da2d5..4240f2fd 100644 --- a/config.py +++ b/config.py @@ -32,6 +32,13 @@ gpio_heat = 23 # Switches zero-cross solid-state-relay gpio_e_relay = 27 # pin 13; emergency cutoff relay +# Note: `gpio_e_relay` is used to and a redundant mechanical relay in series with +# the SSR. Because SSRs normally fail closed (i.e. energized), this provides a +# way for the controller to shut off the kiln in the event that the SSR fails. +# It is designed to be used with the SSR input connected to the safety relay's +# Normally Open (NC) output; thus, the kiln can only heat when the RPi has +# energized the safety relay. + ### Thermocouple Adapter selection: # max31855 - bitbang SPI interface # max31856 - bitbang SPI interface. must specify thermocouple_type. From ef5f011e400f11a54c08de637ddfe1c88db50a1a Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 8 Jan 2022 21:55:02 -0500 Subject: [PATCH 04/57] testing TM1637 display addition --- config.py | 11 +++++++---- lib/display.py | 27 +++++++++++++++++++++++++++ lib/oven.py | 1 + lib/ovenWatcher.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 lib/display.py diff --git a/config.py b/config.py index 60dd6fbc..3126e328 100644 --- a/config.py +++ b/config.py @@ -43,11 +43,14 @@ # energized the safety relay. ## Display outputs -gpio_disp1_clk = 20 # pin 38 -gpio_disp1_dat = 21 # pin 40 -gpio_disp2_clk = 16 # pin 36 -gpio_disp2_dat = 26 # pin 37 +time_disp = {'type': 'TMC1637', + 'pins': {'clock': 16, # pin 36 + 'data': 26}} # pin 37 + +time_disp = {'type': 'TMC1637', + 'pins': {'clock': 20, # pin 38 + 'data': 21}} # pin 40 gpio_dotstar_clk = 19 # pin 35 gpio_dotstar_dat = 13 # pin 33 diff --git a/lib/display.py b/lib/display.py new file mode 100644 index 00000000..e4e00ae8 --- /dev/null +++ b/lib/display.py @@ -0,0 +1,27 @@ +class TM1637(object): + def __init__(self, + clk_pin, + dat_pin): + + self.clk_pin = clock_pin + self.dat_pin = dat_pin + + try: + import tm1637 + self.tm = tm1637.TM1637(clk=clk_pin, + dio=dat_pin) + def temp(self, + t): + self.tm.number(t) + + def time(self, + h, + m): + self.tm.numbers(h, m, True) + + def text(self, + text): + self.tm.show(text[0:4]) + + def off(self): + self.tm.write([0, 0, 0, 0]) diff --git a/lib/oven.py b/lib/oven.py index e20d36a1..380010b7 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -45,6 +45,7 @@ def cool(self,sleepfor): self.GPIO.output(config.gpio_heat, self.GPIO.LOW) time.sleep(sleepfor) + # FIX - Board class needs to be completely removed class Board(object): def __init__(self): diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index 3e47e4fd..991ce166 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -1,7 +1,33 @@ import threading,logging,json,time,datetime from oven import Oven +from display import TM1637 +import config + log = logging.getLogger(__name__) + +class Display(object): + def __init__(self, + type, + pins): + + if type == "TMC1637": + self.disp = TM1637(pins['clock'] + pins['data']) + + def temp(self, t): + self.disp.temp(t) + + def time(self, h, m): + self.disp.time(h, m) + + def off(self): + self.disp.off() + + def text(self, text): + self.disp.text(text) + + class OvenWatcher(threading.Thread): def __init__(self,oven): self.last_profile = None @@ -13,6 +39,21 @@ def __init__(self,oven): self.daemon = True self.oven = oven self.start() + self.time_disp = None + self.temp_disp = None + + try: + self.time_disp = Display(config.time_disp['type'], + config.time_disp['pins']) + except NameError: + self.time_disp = None + + try: + self.temp_disp = Display(config.temp_disp['type'], + config.temp_disp['pins']) + except NameErro: + self.temp_disp = None + # FIXME - need to save runs of schedules in near-real-time # FIXME - this will enable re-start in case of power outage @@ -32,6 +73,10 @@ def run(self): else: self.recording = False self.notify_all(oven_state) + if self.time_disp: + self.time_disp.time(oven_state['runtime']) + if self.temp_disp: + self.temp_disp.temp(oven_state['temperature']) time.sleep(self.oven.time_step) def lastlog_subset(self,maxpts=50): diff --git a/requirements.txt b/requirements.txt index cbe34f2b..4bdeeb2d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ RPi.GPIO Adafruit-MAX31855 Adafruit-GPIO websocket-client +raspberrypi-tm1637 From f496712c04267353ad100f7263df89d9827d0ba3 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 8 Jan 2022 22:15:01 -0500 Subject: [PATCH 05/57] fixed errors --- config.py | 12 ++++++------ lib/display.py | 43 +++++++++++++++++++++++-------------------- lib/ovenWatcher.py | 19 +++++++++---------- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/config.py b/config.py index 3126e328..0dda0210 100644 --- a/config.py +++ b/config.py @@ -44,13 +44,13 @@ ## Display outputs -time_disp = {'type': 'TMC1637', - 'pins': {'clock': 16, # pin 36 - 'data': 26}} # pin 37 +temp_disp = {'type': 'TMC1637', + 'pins': {'clock': 16, + 'data': 26}} # pin 36, pin 37 time_disp = {'type': 'TMC1637', - 'pins': {'clock': 20, # pin 38 - 'data': 21}} # pin 40 + 'pins': {'clock': 20, + 'data': 21}} # pin 38, pin 40 gpio_dotstar_clk = 19 # pin 35 gpio_dotstar_dat = 13 # pin 33 @@ -67,7 +67,7 @@ max31856 = 1 # see lib/max31856.py for other thermocouple_type, only applies to max31856 # uncomment this if using MAX-31856 -thermocouple_type = MAX31856.MAX31856_K_TYPE +# thermocouple_type = MAX31856.MAX31856_K_TYPE ### Thermocouple Connection (using bitbang interfaces) gpio_sensor_cs = 8 # pin 24 diff --git a/lib/display.py b/lib/display.py index e4e00ae8..5f6d498e 100644 --- a/lib/display.py +++ b/lib/display.py @@ -1,27 +1,30 @@ class TM1637(object): - def __init__(self, - clk_pin, - dat_pin): + def __init__(self, + clk_pin, + dat_pin): - self.clk_pin = clock_pin - self.dat_pin = dat_pin + self.clk_pin = clock_pin + self.dat_pin = dat_pin - try: - import tm1637 - self.tm = tm1637.TM1637(clk=clk_pin, - dio=dat_pin) - def temp(self, - t): - self.tm.number(t) + try: + import tm1637 + self.tm = tm1637.TM1637(clk=clk_pin, + dio=dat_pin) + except ImportError: + print('import failure') - def time(self, - h, - m): - self.tm.numbers(h, m, True) + def temp(self, + t): + self.tm.number(t) - def text(self, - text): - self.tm.show(text[0:4]) + def time(self, + h, + m): + self.tm.numbers(h, m, True) + + def text(self, + text): + self.tm.show(text[0:4]) def off(self): - self.tm.write([0, 0, 0, 0]) + self.tm.write([0, 0, 0, 0]) diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index 991ce166..4506cbb8 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -12,7 +12,7 @@ def __init__(self, pins): if type == "TMC1637": - self.disp = TM1637(pins['clock'] + self.disp = TM1637(pins['clock'], pins['data']) def temp(self, t): @@ -35,24 +35,23 @@ def __init__(self,oven): self.started = None self.recording = False self.observers = [] - threading.Thread.__init__(self) - self.daemon = True - self.oven = oven - self.start() - self.time_disp = None - self.temp_disp = None try: self.time_disp = Display(config.time_disp['type'], config.time_disp['pins']) except NameError: - self.time_disp = None + self.time_disp = False try: self.temp_disp = Display(config.temp_disp['type'], config.temp_disp['pins']) - except NameErro: - self.temp_disp = None + except NameError: + self.temp_disp = False + + threading.Thread.__init__(self) + self.daemon = True + self.oven = oven + self.start() # FIXME - need to save runs of schedules in near-real-time From 6679867fdd314df374db9072097ced7fca27fd4b Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 11:23:27 -0500 Subject: [PATCH 06/57] added init display --- lib/ovenWatcher.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index 4506cbb8..9eb1a161 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -39,12 +39,14 @@ def __init__(self,oven): try: self.time_disp = Display(config.time_disp['type'], config.time_disp['pins']) + self.time_disp.show('TIME') except NameError: self.time_disp = False try: self.temp_disp = Display(config.temp_disp['type'], config.temp_disp['pins']) + self.time_disp.show('TEMP') except NameError: self.temp_disp = False From 5ae5916400ff8c492a062a67563139e64235ad8c Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 11:31:30 -0500 Subject: [PATCH 07/57] moved display code to oven --- lib/oven.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ lib/ovenWatcher.py | 40 ---------------------------------------- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 380010b7..4b56716a 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -46,6 +46,30 @@ def cool(self,sleepfor): time.sleep(sleepfor) + +class Display(object): + def __init__(self, + type, + pins): + + if type == "TMC1637": + self.disp = TM1637(pins['clock'], + pins['data']) + + def temp(self, t): + self.disp.temp(t) + + def time(self, h, m): + self.disp.time(h, m) + + def off(self): + self.disp.off() + + def text(self, text): + self.disp.text(text) + + + # FIX - Board class needs to be completely removed class Board(object): def __init__(self): @@ -399,6 +423,26 @@ def __init__(self): # start thread self.start() + + try: + self.time_disp = Display(config.time_disp['type'], + config.time_disp['pins']) + self.time_disp.show('TIME') + except NameError: + self.time_disp = False + + try: + self.temp_disp = Display(config.temp_disp['type'], + config.temp_disp['pins']) + self.time_disp.show('TEMP') + except NameError: + self.temp_disp = False + + # if self.time_disp: + # self.time_disp.time(oven_state['runtime']) + # if self.temp_disp: + # self.temp_disp.temp(oven_state['temperature']) + def reset(self): super().reset() self.output.safety_on() diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index 9eb1a161..aa9e1faa 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -6,28 +6,6 @@ log = logging.getLogger(__name__) -class Display(object): - def __init__(self, - type, - pins): - - if type == "TMC1637": - self.disp = TM1637(pins['clock'], - pins['data']) - - def temp(self, t): - self.disp.temp(t) - - def time(self, h, m): - self.disp.time(h, m) - - def off(self): - self.disp.off() - - def text(self, text): - self.disp.text(text) - - class OvenWatcher(threading.Thread): def __init__(self,oven): self.last_profile = None @@ -36,20 +14,6 @@ def __init__(self,oven): self.recording = False self.observers = [] - try: - self.time_disp = Display(config.time_disp['type'], - config.time_disp['pins']) - self.time_disp.show('TIME') - except NameError: - self.time_disp = False - - try: - self.temp_disp = Display(config.temp_disp['type'], - config.temp_disp['pins']) - self.time_disp.show('TEMP') - except NameError: - self.temp_disp = False - threading.Thread.__init__(self) self.daemon = True self.oven = oven @@ -74,10 +38,6 @@ def run(self): else: self.recording = False self.notify_all(oven_state) - if self.time_disp: - self.time_disp.time(oven_state['runtime']) - if self.temp_disp: - self.temp_disp.temp(oven_state['temperature']) time.sleep(self.oven.time_step) def lastlog_subset(self,maxpts=50): From 4bc68aac5059094eb1291d632f275997c6d56256 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:14:57 -0500 Subject: [PATCH 08/57] updating config --- config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.py b/config.py index 0dda0210..304218e8 100644 --- a/config.py +++ b/config.py @@ -1,7 +1,7 @@ import logging # uncomment this if using MAX-31856 -#from lib.max31856 import MAX31856 +from lib.max31856 import MAX31856 ######################################################################## # @@ -10,6 +10,7 @@ ### Logging log_level = logging.INFO log_format = '%(asctime)s %(levelname)s %(name)s: %(message)s' +log_file = '/var/log/kiln-controller.log' ### Server listening_ip = "0.0.0.0" From fb673ff568f7e76b7af1f0a1ca402dbc2357e6b9 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:21:51 -0500 Subject: [PATCH 09/57] testing --- config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.py b/config.py index 304218e8..9c6f204a 100644 --- a/config.py +++ b/config.py @@ -68,7 +68,7 @@ max31856 = 1 # see lib/max31856.py for other thermocouple_type, only applies to max31856 # uncomment this if using MAX-31856 -# thermocouple_type = MAX31856.MAX31856_K_TYPE +thermocouple_type = MAX31856.MAX31856_K_TYPE ### Thermocouple Connection (using bitbang interfaces) gpio_sensor_cs = 8 # pin 24 From cc3ddbbff5e1ba5ec88e717a923bc6e8e1e71662 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:28:46 -0500 Subject: [PATCH 10/57] moving display code --- lib/oven.py | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 4b56716a..8710527e 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -14,6 +14,26 @@ def __init__(self): self.active = False self.load_libs() + if self.active: + try: + self.time_disp = Display(config.time_disp['type'], + config.time_disp['pins']) + self.time_disp.show('TIME') + except NameError: + self.time_disp = False + + try: + self.temp_disp = Display(config.temp_disp['type'], + config.temp_disp['pins']) + self.time_disp.show('TEMP') + except NameError: + self.temp_disp = False + + # if self.time_disp: + # self.time_disp.time(oven_state['runtime']) + # if self.temp_disp: + # self.temp_disp.temp(oven_state['temperature']) + def load_libs(self): try: import RPi.GPIO as GPIO @@ -45,8 +65,6 @@ def cool(self,sleepfor): self.GPIO.output(config.gpio_heat, self.GPIO.LOW) time.sleep(sleepfor) - - class Display(object): def __init__(self, type, @@ -423,26 +441,6 @@ def __init__(self): # start thread self.start() - - try: - self.time_disp = Display(config.time_disp['type'], - config.time_disp['pins']) - self.time_disp.show('TIME') - except NameError: - self.time_disp = False - - try: - self.temp_disp = Display(config.temp_disp['type'], - config.temp_disp['pins']) - self.time_disp.show('TEMP') - except NameError: - self.temp_disp = False - - # if self.time_disp: - # self.time_disp.time(oven_state['runtime']) - # if self.temp_disp: - # self.temp_disp.temp(oven_state['temperature']) - def reset(self): super().reset() self.output.safety_on() From cd1e07957d5efd433ee7747f2644ae4da7876c61 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:31:12 -0500 Subject: [PATCH 11/57] testing --- lib/oven.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/oven.py b/lib/oven.py index 8710527e..3d713a3d 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -15,11 +15,13 @@ def __init__(self): self.load_libs() if self.active: + log.info("Trying to initialize displays") try: self.time_disp = Display(config.time_disp['type'], config.time_disp['pins']) self.time_disp.show('TIME') except NameError: + log.info("Couldn't initialize time display") self.time_disp = False try: From 8ca88394f166f6a682f47dc3a9de2c832bbf0983 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:37:23 -0500 Subject: [PATCH 12/57] testing --- lib/oven.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 3d713a3d..1a1a6f00 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -13,7 +13,7 @@ class Output(object): def __init__(self): self.active = False self.load_libs() - + log.warning('Active: %s' % self.active) if self.active: log.info("Trying to initialize displays") try: @@ -21,7 +21,7 @@ def __init__(self): config.time_disp['pins']) self.time_disp.show('TIME') except NameError: - log.info("Couldn't initialize time display") + log.warning("Couldn't initialize time display") self.time_disp = False try: From 1f32c1899432c7f76305d46758992ebfd4c9b02e Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:40:02 -0500 Subject: [PATCH 13/57] testing --- lib/oven.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/oven.py b/lib/oven.py index 1a1a6f00..7192ce08 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -20,8 +20,9 @@ def __init__(self): self.time_disp = Display(config.time_disp['type'], config.time_disp['pins']) self.time_disp.show('TIME') - except NameError: + except NameError as e: log.warning("Couldn't initialize time display") + log.warning("Error: %s" % e) self.time_disp = False try: From 03f319c5f50766b793adc39f85ae9e875ce753a1 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:41:50 -0500 Subject: [PATCH 14/57] testing --- lib/oven.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/oven.py b/lib/oven.py index 7192ce08..2959a126 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -5,6 +5,7 @@ import logging import json import config +from display import TM1637 log = logging.getLogger(__name__) From 504f0ff5e127b8c5973566ce4a6ea596fd593bb7 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:44:41 -0500 Subject: [PATCH 15/57] testing --- lib/display.py | 2 +- lib/ovenWatcher.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/display.py b/lib/display.py index 5f6d498e..eac5e7fb 100644 --- a/lib/display.py +++ b/lib/display.py @@ -3,7 +3,7 @@ def __init__(self, clk_pin, dat_pin): - self.clk_pin = clock_pin + self.clk_pin = clk_pin self.dat_pin = dat_pin try: diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index aa9e1faa..47d4d740 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -1,6 +1,5 @@ import threading,logging,json,time,datetime from oven import Oven -from display import TM1637 import config log = logging.getLogger(__name__) From 17d8db82fdd7ebfa2492dbf9bc482f3806527f85 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:48:56 -0500 Subject: [PATCH 16/57] testing --- lib/oven.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 2959a126..ff4e410d 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -20,7 +20,7 @@ def __init__(self): try: self.time_disp = Display(config.time_disp['type'], config.time_disp['pins']) - self.time_disp.show('TIME') + self.time_disp.time(11,11) except NameError as e: log.warning("Couldn't initialize time display") log.warning("Error: %s" % e) @@ -29,7 +29,7 @@ def __init__(self): try: self.temp_disp = Display(config.temp_disp['type'], config.temp_disp['pins']) - self.time_disp.show('TEMP') + self.time_disp.temp(1337) except NameError: self.temp_disp = False @@ -78,18 +78,6 @@ def __init__(self, self.disp = TM1637(pins['clock'], pins['data']) - def temp(self, t): - self.disp.temp(t) - - def time(self, h, m): - self.disp.time(h, m) - - def off(self): - self.disp.off() - - def text(self, text): - self.disp.text(text) - # FIX - Board class needs to be completely removed From 5d728bcfe66d4850ed61bd996b4bf0551335e941 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:50:51 -0500 Subject: [PATCH 17/57] testing --- lib/oven.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/oven.py b/lib/oven.py index ff4e410d..5c2d5fed 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -78,6 +78,18 @@ def __init__(self, self.disp = TM1637(pins['clock'], pins['data']) + def temp(self, t): + self.disp.temp(t) + + def time(self, h, m): + self.disp.time(h, m) + + def off(self): + self.disp.off() + + def text(self, text): + self.disp.text(text) + # FIX - Board class needs to be completely removed From 38674ba7f578f7b47c517b5c4c3f6cbf63f80ed9 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:53:08 -0500 Subject: [PATCH 18/57] testing --- lib/display.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/display.py b/lib/display.py index eac5e7fb..a4ff8a65 100644 --- a/lib/display.py +++ b/lib/display.py @@ -1,3 +1,9 @@ +import tm1637 +import logging + +log = logging.getLogger(__name__) + + class TM1637(object): def __init__(self, clk_pin, @@ -10,8 +16,8 @@ def __init__(self, import tm1637 self.tm = tm1637.TM1637(clk=clk_pin, dio=dat_pin) - except ImportError: - print('import failure') + except ImportError as e: + log.warning('import failure: \n%s' % e) def temp(self, t): From 3762602c86c0440710bb20aa7c0b75b070395829 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 12:59:34 -0500 Subject: [PATCH 19/57] testing --- lib/display.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/display.py b/lib/display.py index a4ff8a65..c109331b 100644 --- a/lib/display.py +++ b/lib/display.py @@ -13,7 +13,6 @@ def __init__(self, self.dat_pin = dat_pin try: - import tm1637 self.tm = tm1637.TM1637(clk=clk_pin, dio=dat_pin) except ImportError as e: From c3e2d6f63ccd4771e1e8a0d3cd012e4a2048715b Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 13:02:43 -0500 Subject: [PATCH 20/57] testing --- lib/tm16347.py | 270 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 lib/tm16347.py diff --git a/lib/tm16347.py b/lib/tm16347.py new file mode 100644 index 00000000..2d536a35 --- /dev/null +++ b/lib/tm16347.py @@ -0,0 +1,270 @@ +""" +Original source for MicroPython +MicroPython TM1637 quad 7-segment LED display driver +https://github.com/mcauser/micropython-tm1637 + +Python3 Port +https://github.com/depklyon/raspberrypi-tm1637 + +MIT License +Copyright (c) 2016-2018 Mike Causer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +from time import sleep + +from wiringpi import wiringPiSetupGpio, pinMode, digitalRead, digitalWrite, GPIO + +wiringPiSetupGpio() + +TM1637_CMD1 = 0x40 # 0x40 data command +TM1637_CMD2 = 0xc0 # 0xC0 address command +TM1637_CMD3 = 0x80 # 0x80 display control command +TM1637_DSP_ON = 0x08 # 0x08 display on +TM1637_DELAY = 0.00000001 # 10us delay between clk/dio pulses +TM1637_MSB = 0x80 # msb is the decimal point or the colon depending on your display + +# 0-9, a-z, blank, dash, star +_SEGMENTS = bytearray( + b'\x3F\x06\x5B\x4F\x66\x6D\x7D\x07\x7F\x6F\x77\x7C\x39\x5E\x79\x71\x3D\x76\x06\x1E\x76\x38\x55\x54\x3F\x73\x67' + b'\x50\x6D\x78\x3E\x1C\x2A\x76\x6E\x5B\x00\x40\x63') + + +class TM1637(object): + """Library for quad 7-segment LED modules based on the TM1637 LED driver.""" + + def __init__(self, clk, dio, brightness=7): + self.clk = clk + self.dio = dio + + if not 0 <= brightness <= 7: + raise ValueError("Brightness out of range") + self._brightness = brightness + + pinMode(self.clk, GPIO.OUTPUT) + pinMode(self.dio, GPIO.OUTPUT) + digitalWrite(self.clk, 0) + digitalWrite(self.dio, 0) + + def _start(self): + digitalWrite(self.clk, GPIO.HIGH) + digitalWrite(self.dio, GPIO.HIGH) + digitalWrite(self.dio, GPIO.LOW) + digitalWrite(self.clk, GPIO.LOW) + + def _stop(self): + digitalWrite(self.clk, GPIO.LOW) + digitalWrite(self.dio, GPIO.LOW) + digitalWrite(self.clk, GPIO.HIGH) + digitalWrite(self.dio, GPIO.HIGH) + + def _write_data_cmd(self): + # automatic address increment, normal mode + self._start() + self._write_byte(TM1637_CMD1) + self._stop() + + def _write_dsp_ctrl(self): + # display on, set brightness + self._start() + self._write_byte(TM1637_CMD3 | TM1637_DSP_ON | self._brightness) + self._stop() + + def _write_byte(self, b): + for i in range(8): + digitalWrite(self.clk, GPIO.LOW) + digitalWrite(self.dio, GPIO.HIGH if b & 1 else GPIO.LOW) + b >>= 1 + digitalWrite(self.clk, GPIO.HIGH) + + # wait for ACK + digitalWrite(self.clk, GPIO.LOW) + digitalWrite(self.dio, GPIO.HIGH) + digitalWrite(self.clk, GPIO.HIGH) + pinMode(self.dio, GPIO.INPUT) + + while digitalRead(self.dio): + sleep(TM1637_DELAY) + if digitalRead(self.dio): + pinMode(self.dio, GPIO.OUTPUT) + digitalWrite(self.dio, GPIO.LOW) + pinMode(self.dio, GPIO.INPUT) + pinMode(self.dio, GPIO.OUTPUT) + + def brightness(self, val=None): + """Set the display brightness 0-7.""" + # brightness 0 = 1/16th pulse width + # brightness 7 = 14/16th pulse width + if val is None: + return self._brightness + if not 0 <= val <= 7: + raise ValueError("Brightness out of range") + + self._brightness = val + self._write_data_cmd() + self._write_dsp_ctrl() + + def write(self, segments, pos=0): + """Display up to 6 segments moving right from a given position. + The MSB in the 2nd segment controls the colon between the 2nd + and 3rd segments.""" + if not 0 <= pos <= 5: + raise ValueError("Position out of range") + self._write_data_cmd() + self._start() + self._write_byte(TM1637_CMD2 | pos) + for seg in segments: + self._write_byte(seg) + self._stop() + self._write_dsp_ctrl() + + @staticmethod + def encode_digit(digit): + """Convert a character 0-9, a-f to a segment.""" + return _SEGMENTS[digit & 0x0f] + + @staticmethod + def encode_char(char): + """Convert a character 0-9, a-z, space, dash or star to a segment.""" + o = ord(char) + if o == 32: + return _SEGMENTS[36] # space + if o == 42: + return _SEGMENTS[38] # star/degrees + if o == 45: + return _SEGMENTS[37] # dash + if 65 <= o <= 90: + return _SEGMENTS[o - 55] # uppercase A-Z + if 97 <= o <= 122: + return _SEGMENTS[o - 87] # lowercase a-z + if 48 <= o <= 57: + return _SEGMENTS[o - 48] # 0-9 + raise ValueError("Character out of range: {:d} '{:s}'".format(o, chr(o))) + + def encode_string(self, string): + """Convert an up to 4 character length string containing 0-9, a-z, + space, dash, star to an array of segments, matching the length of the + source string.""" + segments = bytearray(len(string)) + for i in range(len(string)): + segments[i] = self.encode_char(string[i]) + return segments + + def hex(self, val): + """Display a hex value 0x0000 through 0xffff, right aligned.""" + string = '{:04x}'.format(val & 0xffff) + self.write(self.encode_string(string)) + + def number(self, num): + """Display a numeric value -999 through 9999, right aligned.""" + # limit to range -999 to 9999 + num = max(-999, min(num, 9999)) + string = '{0: >4d}'.format(num) + self.write(self.encode_string(string)) + + def numbers(self, num1, num2, colon=True): + """Display two numeric values -9 through 99, with leading zeros + and separated by a colon.""" + num1 = max(-9, min(num1, 99)) + num2 = max(-9, min(num2, 99)) + segments = self.encode_string('{0:0>2d}{1:0>2d}'.format(num1, num2)) + if colon: + segments[1] |= 0x80 # colon on + self.write(segments) + + def temperature(self, num): + if num < -9: + self.show('lo') # low + elif num > 99: + self.show('hi') # high + else: + string = '{0: >2d}'.format(num) + self.write(self.encode_string(string)) + self.write([_SEGMENTS[38], _SEGMENTS[12]], 2) # degrees C + + def dec_temperature(self, num): + if num < -9.9: # limit to single digit negatives + self.write([0, 0, 0, 0]) + self.show('lo') # low + elif num > 99.9: + self.write([0, 0, 0, 0]) + self.show('hi') # high + else: + intval = abs(int(num/1)) + if num == 0: # exact zero + seg1 = 0b00000000 + seg2 = self.encode_digit(0) + seg3 = self.encode_digit(0) + else: + if intval < 10 and num > 0: # single digit positive + seg1 = 0b00000000 + seg2 = self.encode_digit(intval) + elif num < 0: # negative + seg1 = 0b01000000 # '-' + seg2 = self.encode_digit(intval) + else: # two digit (can only be positive) + seg1 = self.encode_digit(int(intval/10)) + seg2 = self.encode_digit(int(num-(int(intval/10)*10))) + + try: + seg3 = self.encode_digit(int(str(num).split('.')[1][0])) # will fail if there is no decimal point + except: + seg3 = self.encode_digit(0) + segments = [seg1, seg2, seg3, _SEGMENTS[38]] # segments and degree character + segments[1] |= 0x80 # colon as decimal + self.write(segments) + + def show(self, string, colon=False): + segments = self.encode_string(string) + if len(segments) > 1 and colon: + segments[1] |= 128 + self.write(segments[:4]) + + def scroll(self, string, delay=250): + segments = string if isinstance(string, list) else self.encode_string(string) + data = [0] * 8 + data[4:0] = list(segments) + for i in range(len(segments) + 5): + self.write(data[0 + i:4 + i]) + sleep(delay / 1000) + + +class TM1637Decimal(TM1637): + """Library for quad 7-segment LED modules based on the TM1637 LED driver. + + This class is meant to be used with decimal display modules (modules + that have a decimal point after each 7-segment LED). + """ + + def encode_string(self, string): + """Convert a string to LED segments. + + Convert an up to 4 character length string containing 0-9, a-z, + space, dash, star and '.' to an array of segments, matching the length of + the source string.""" + segments = bytearray(len(string.replace('.', ''))) + j = 0 + for i in range(len(string)): + if string[i] == '.' and j > 0: + segments[j - 1] |= TM1637_MSB + continue + segments[j] = self.encode_char(string[i]) + j += 1 + return segments \ No newline at end of file From 4c8215f75f57c6059b44ca972da04471de51acf7 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 13:07:18 -0500 Subject: [PATCH 21/57] testing --- lib/tm16347.py | 270 ------------------------------------------------- 1 file changed, 270 deletions(-) delete mode 100644 lib/tm16347.py diff --git a/lib/tm16347.py b/lib/tm16347.py deleted file mode 100644 index 2d536a35..00000000 --- a/lib/tm16347.py +++ /dev/null @@ -1,270 +0,0 @@ -""" -Original source for MicroPython -MicroPython TM1637 quad 7-segment LED display driver -https://github.com/mcauser/micropython-tm1637 - -Python3 Port -https://github.com/depklyon/raspberrypi-tm1637 - -MIT License -Copyright (c) 2016-2018 Mike Causer - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -""" - -from time import sleep - -from wiringpi import wiringPiSetupGpio, pinMode, digitalRead, digitalWrite, GPIO - -wiringPiSetupGpio() - -TM1637_CMD1 = 0x40 # 0x40 data command -TM1637_CMD2 = 0xc0 # 0xC0 address command -TM1637_CMD3 = 0x80 # 0x80 display control command -TM1637_DSP_ON = 0x08 # 0x08 display on -TM1637_DELAY = 0.00000001 # 10us delay between clk/dio pulses -TM1637_MSB = 0x80 # msb is the decimal point or the colon depending on your display - -# 0-9, a-z, blank, dash, star -_SEGMENTS = bytearray( - b'\x3F\x06\x5B\x4F\x66\x6D\x7D\x07\x7F\x6F\x77\x7C\x39\x5E\x79\x71\x3D\x76\x06\x1E\x76\x38\x55\x54\x3F\x73\x67' - b'\x50\x6D\x78\x3E\x1C\x2A\x76\x6E\x5B\x00\x40\x63') - - -class TM1637(object): - """Library for quad 7-segment LED modules based on the TM1637 LED driver.""" - - def __init__(self, clk, dio, brightness=7): - self.clk = clk - self.dio = dio - - if not 0 <= brightness <= 7: - raise ValueError("Brightness out of range") - self._brightness = brightness - - pinMode(self.clk, GPIO.OUTPUT) - pinMode(self.dio, GPIO.OUTPUT) - digitalWrite(self.clk, 0) - digitalWrite(self.dio, 0) - - def _start(self): - digitalWrite(self.clk, GPIO.HIGH) - digitalWrite(self.dio, GPIO.HIGH) - digitalWrite(self.dio, GPIO.LOW) - digitalWrite(self.clk, GPIO.LOW) - - def _stop(self): - digitalWrite(self.clk, GPIO.LOW) - digitalWrite(self.dio, GPIO.LOW) - digitalWrite(self.clk, GPIO.HIGH) - digitalWrite(self.dio, GPIO.HIGH) - - def _write_data_cmd(self): - # automatic address increment, normal mode - self._start() - self._write_byte(TM1637_CMD1) - self._stop() - - def _write_dsp_ctrl(self): - # display on, set brightness - self._start() - self._write_byte(TM1637_CMD3 | TM1637_DSP_ON | self._brightness) - self._stop() - - def _write_byte(self, b): - for i in range(8): - digitalWrite(self.clk, GPIO.LOW) - digitalWrite(self.dio, GPIO.HIGH if b & 1 else GPIO.LOW) - b >>= 1 - digitalWrite(self.clk, GPIO.HIGH) - - # wait for ACK - digitalWrite(self.clk, GPIO.LOW) - digitalWrite(self.dio, GPIO.HIGH) - digitalWrite(self.clk, GPIO.HIGH) - pinMode(self.dio, GPIO.INPUT) - - while digitalRead(self.dio): - sleep(TM1637_DELAY) - if digitalRead(self.dio): - pinMode(self.dio, GPIO.OUTPUT) - digitalWrite(self.dio, GPIO.LOW) - pinMode(self.dio, GPIO.INPUT) - pinMode(self.dio, GPIO.OUTPUT) - - def brightness(self, val=None): - """Set the display brightness 0-7.""" - # brightness 0 = 1/16th pulse width - # brightness 7 = 14/16th pulse width - if val is None: - return self._brightness - if not 0 <= val <= 7: - raise ValueError("Brightness out of range") - - self._brightness = val - self._write_data_cmd() - self._write_dsp_ctrl() - - def write(self, segments, pos=0): - """Display up to 6 segments moving right from a given position. - The MSB in the 2nd segment controls the colon between the 2nd - and 3rd segments.""" - if not 0 <= pos <= 5: - raise ValueError("Position out of range") - self._write_data_cmd() - self._start() - self._write_byte(TM1637_CMD2 | pos) - for seg in segments: - self._write_byte(seg) - self._stop() - self._write_dsp_ctrl() - - @staticmethod - def encode_digit(digit): - """Convert a character 0-9, a-f to a segment.""" - return _SEGMENTS[digit & 0x0f] - - @staticmethod - def encode_char(char): - """Convert a character 0-9, a-z, space, dash or star to a segment.""" - o = ord(char) - if o == 32: - return _SEGMENTS[36] # space - if o == 42: - return _SEGMENTS[38] # star/degrees - if o == 45: - return _SEGMENTS[37] # dash - if 65 <= o <= 90: - return _SEGMENTS[o - 55] # uppercase A-Z - if 97 <= o <= 122: - return _SEGMENTS[o - 87] # lowercase a-z - if 48 <= o <= 57: - return _SEGMENTS[o - 48] # 0-9 - raise ValueError("Character out of range: {:d} '{:s}'".format(o, chr(o))) - - def encode_string(self, string): - """Convert an up to 4 character length string containing 0-9, a-z, - space, dash, star to an array of segments, matching the length of the - source string.""" - segments = bytearray(len(string)) - for i in range(len(string)): - segments[i] = self.encode_char(string[i]) - return segments - - def hex(self, val): - """Display a hex value 0x0000 through 0xffff, right aligned.""" - string = '{:04x}'.format(val & 0xffff) - self.write(self.encode_string(string)) - - def number(self, num): - """Display a numeric value -999 through 9999, right aligned.""" - # limit to range -999 to 9999 - num = max(-999, min(num, 9999)) - string = '{0: >4d}'.format(num) - self.write(self.encode_string(string)) - - def numbers(self, num1, num2, colon=True): - """Display two numeric values -9 through 99, with leading zeros - and separated by a colon.""" - num1 = max(-9, min(num1, 99)) - num2 = max(-9, min(num2, 99)) - segments = self.encode_string('{0:0>2d}{1:0>2d}'.format(num1, num2)) - if colon: - segments[1] |= 0x80 # colon on - self.write(segments) - - def temperature(self, num): - if num < -9: - self.show('lo') # low - elif num > 99: - self.show('hi') # high - else: - string = '{0: >2d}'.format(num) - self.write(self.encode_string(string)) - self.write([_SEGMENTS[38], _SEGMENTS[12]], 2) # degrees C - - def dec_temperature(self, num): - if num < -9.9: # limit to single digit negatives - self.write([0, 0, 0, 0]) - self.show('lo') # low - elif num > 99.9: - self.write([0, 0, 0, 0]) - self.show('hi') # high - else: - intval = abs(int(num/1)) - if num == 0: # exact zero - seg1 = 0b00000000 - seg2 = self.encode_digit(0) - seg3 = self.encode_digit(0) - else: - if intval < 10 and num > 0: # single digit positive - seg1 = 0b00000000 - seg2 = self.encode_digit(intval) - elif num < 0: # negative - seg1 = 0b01000000 # '-' - seg2 = self.encode_digit(intval) - else: # two digit (can only be positive) - seg1 = self.encode_digit(int(intval/10)) - seg2 = self.encode_digit(int(num-(int(intval/10)*10))) - - try: - seg3 = self.encode_digit(int(str(num).split('.')[1][0])) # will fail if there is no decimal point - except: - seg3 = self.encode_digit(0) - segments = [seg1, seg2, seg3, _SEGMENTS[38]] # segments and degree character - segments[1] |= 0x80 # colon as decimal - self.write(segments) - - def show(self, string, colon=False): - segments = self.encode_string(string) - if len(segments) > 1 and colon: - segments[1] |= 128 - self.write(segments[:4]) - - def scroll(self, string, delay=250): - segments = string if isinstance(string, list) else self.encode_string(string) - data = [0] * 8 - data[4:0] = list(segments) - for i in range(len(segments) + 5): - self.write(data[0 + i:4 + i]) - sleep(delay / 1000) - - -class TM1637Decimal(TM1637): - """Library for quad 7-segment LED modules based on the TM1637 LED driver. - - This class is meant to be used with decimal display modules (modules - that have a decimal point after each 7-segment LED). - """ - - def encode_string(self, string): - """Convert a string to LED segments. - - Convert an up to 4 character length string containing 0-9, a-z, - space, dash, star and '.' to an array of segments, matching the length of - the source string.""" - segments = bytearray(len(string.replace('.', ''))) - j = 0 - for i in range(len(string)): - if string[i] == '.' and j > 0: - segments[j - 1] |= TM1637_MSB - continue - segments[j] = self.encode_char(string[i]) - j += 1 - return segments \ No newline at end of file From f3d2213f36d659458e725f934ff0d922dbd5dbd7 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 13:09:47 -0500 Subject: [PATCH 22/57] displays!! --- lib/oven.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 5c2d5fed..b9d532cb 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -29,8 +29,10 @@ def __init__(self): try: self.temp_disp = Display(config.temp_disp['type'], config.temp_disp['pins']) - self.time_disp.temp(1337) - except NameError: + self.temp_disp.temp(1337) + except NameError as e: + log.warning("Couldn't initialize temp display") + log.warning("Error: %s" % e) self.temp_disp = False # if self.time_disp: From 98dfcf51b9facdbe282ec6b843fda1b2c0da9638 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 16:30:09 -0500 Subject: [PATCH 23/57] added display update routine --- lib/oven.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index b9d532cb..576582a5 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -1,5 +1,6 @@ import threading import time +from math import floor import random import datetime import logging @@ -35,11 +36,6 @@ def __init__(self): log.warning("Error: %s" % e) self.temp_disp = False - # if self.time_disp: - # self.time_disp.time(oven_state['runtime']) - # if self.temp_disp: - # self.temp_disp.temp(oven_state['temperature']) - def load_libs(self): try: import RPi.GPIO as GPIO @@ -440,6 +436,11 @@ def __init__(self): self.output = Output() self.reset() + if self.output.time_disp: + self.output.time_disp.text(self.state) + if self.output.temp_disp: + self.temp_disp.temp(self.temperature) + # call parent init Oven.__init__(self) self.output.safety_off() @@ -469,6 +470,16 @@ def heat_then_cool(self): if heat_off: self.output.cool(heat_off) time_left = self.totaltime - self.runtime + + time_left_h = floor(time_left / 3600) + time_left_m = ceil((time_left % 3600) / 60) + + if self.output.time_disp: + self.output.time_disp.time(time_left_h, + time_left_m) + if self.output.temp_disp: + self.temp_disp.temp(self.temperature) + log.info("temp=%.2f, target=%.2f, pid=%.3f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % (self.board.temp_sensor.temperature + config.thermocouple_offset, self.target, From 35e6b10f3fb12ecd7558a6f58379b1cdd1432342 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 16:33:26 -0500 Subject: [PATCH 24/57] updated display defaults --- lib/oven.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 576582a5..173c9412 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -30,7 +30,7 @@ def __init__(self): try: self.temp_disp = Display(config.temp_disp['type'], config.temp_disp['pins']) - self.temp_disp.temp(1337) + self.temp_disp.text('----') except NameError as e: log.warning("Couldn't initialize temp display") log.warning("Error: %s" % e) @@ -439,7 +439,7 @@ def __init__(self): if self.output.time_disp: self.output.time_disp.text(self.state) if self.output.temp_disp: - self.temp_disp.temp(self.temperature) + self.output.temp_disp.temp(self.temperature) # call parent init Oven.__init__(self) @@ -473,7 +473,7 @@ def heat_then_cool(self): time_left_h = floor(time_left / 3600) time_left_m = ceil((time_left % 3600) / 60) - + if self.output.time_disp: self.output.time_disp.time(time_left_h, time_left_m) From eadf9f8f08c9993477861d409fb99824a4d0407f Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 16:35:58 -0500 Subject: [PATCH 25/57] fixed object order --- lib/oven.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 173c9412..39092fb6 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -436,13 +436,15 @@ def __init__(self): self.output = Output() self.reset() + + # call parent init + Oven.__init__(self) + if self.output.time_disp: self.output.time_disp.text(self.state) if self.output.temp_disp: self.output.temp_disp.temp(self.temperature) - - # call parent init - Oven.__init__(self) + self.output.safety_off() # start thread From 3f9b82a348dc7d28720deb26b8892e3ac3bea47e Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 16:56:39 -0500 Subject: [PATCH 26/57] typo --- lib/oven.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 39092fb6..cfddd582 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -1,6 +1,6 @@ import threading import time -from math import floor +from math import floor, ceil import random import datetime import logging @@ -444,7 +444,7 @@ def __init__(self): self.output.time_disp.text(self.state) if self.output.temp_disp: self.output.temp_disp.temp(self.temperature) - + self.output.safety_off() # start thread From 4ca77a0fed9d39bd4e577e93d5e2470dca0befe6 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 17:18:29 -0500 Subject: [PATCH 27/57] fixing error --- lib/oven.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oven.py b/lib/oven.py index cfddd582..6338fea9 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -480,7 +480,7 @@ def heat_then_cool(self): self.output.time_disp.time(time_left_h, time_left_m) if self.output.temp_disp: - self.temp_disp.temp(self.temperature) + self.output.temp_disp.temp(self.board.temp_sensor.temperature) log.info("temp=%.2f, target=%.2f, pid=%.3f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % (self.board.temp_sensor.temperature + config.thermocouple_offset, From da2acf2e0d7c35b09f09342cc7e9184bfd51231f Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 17:22:54 -0500 Subject: [PATCH 28/57] fixed float to int --- lib/oven.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 6338fea9..8421b0a8 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -473,8 +473,8 @@ def heat_then_cool(self): self.output.cool(heat_off) time_left = self.totaltime - self.runtime - time_left_h = floor(time_left / 3600) - time_left_m = ceil((time_left % 3600) / 60) + time_left_h = int(floor(time_left / 3600)) + time_left_m = int(ceil((time_left % 3600) / 60)) if self.output.time_disp: self.output.time_disp.time(time_left_h, From 8af52153f4b3dd19efcb67a51155047e735e961c Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 17:24:35 -0500 Subject: [PATCH 29/57] fixed float to int --- lib/oven.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/oven.py b/lib/oven.py index 8421b0a8..3518d2a5 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -480,7 +480,7 @@ def heat_then_cool(self): self.output.time_disp.time(time_left_h, time_left_m) if self.output.temp_disp: - self.output.temp_disp.temp(self.board.temp_sensor.temperature) + self.output.temp_disp.temp(int(self.board.temp_sensor.temperature)) log.info("temp=%.2f, target=%.2f, pid=%.3f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % (self.board.temp_sensor.temperature + config.thermocouple_offset, From d96235ff4388def22ce35ae4b465ab2f4c236d2c Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 19:56:04 -0500 Subject: [PATCH 30/57] added log file location --- kiln-controller.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kiln-controller.py b/kiln-controller.py index 4482ba86..a02db8d0 100755 --- a/kiln-controller.py +++ b/kiln-controller.py @@ -23,7 +23,9 @@ print ("Copy config.py.EXAMPLE to config.py and adapt it for your setup.") exit(1) -logging.basicConfig(level=config.log_level, format=config.log_format) +logging.basicConfig(level=config.log_level, + format=config.log_format, + filename=config.log_file) log = logging.getLogger("kiln-controller") log.info("Starting kiln controller") From 1e8076f4e548e86ad4e1703b82f7fc8ad850f3dc Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 20:03:56 -0500 Subject: [PATCH 31/57] added logging to safety relay --- lib/oven.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/oven.py b/lib/oven.py index 3518d2a5..f3059216 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -52,10 +52,12 @@ def load_libs(self): def safety_off(self): '''Energizes the safety relay''' + log.info("energizing safety relay") self.GPIO.output(config.gpio_e_relay, self.GPIO.HIGH) def safety_on(self): '''Deenergizes the safety relay''' + log.info("deenergizing safety relay") self.GPIO.output(config.gpio_e_relay, self.GPIO.LOW) def heat(self,sleepfor): From 6cdd626a7bd2033518add99c8231f4afc77e5db8 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 20:30:31 -0500 Subject: [PATCH 32/57] rearranging Output class functions --- lib/oven.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index f3059216..f7793c4d 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -52,13 +52,19 @@ def load_libs(self): def safety_off(self): '''Energizes the safety relay''' - log.info("energizing safety relay") - self.GPIO.output(config.gpio_e_relay, self.GPIO.HIGH) + if self.active: + log.info("energizing safety relay") + self.GPIO.output(config.gpio_e_relay, self.GPIO.HIGH) + else: + log.info("simulating energizing safety relay") def safety_on(self): '''Deenergizes the safety relay''' - log.info("deenergizing safety relay") - self.GPIO.output(config.gpio_e_relay, self.GPIO.LOW) + if self.active: + log.info("deenergizing safety relay") + self.GPIO.output(config.gpio_e_relay, self.GPIO.LOW) + else: + log.info("simulating deenergizing safety relay") def heat(self,sleepfor): self.GPIO.output(config.gpio_heat, self.GPIO.HIGH) @@ -225,6 +231,11 @@ def __init__(self): self.daemon = True self.temperature = 0 self.time_step = config.sensor_time_wait + self.output = Output() + + self.safety_off = self.output.safety_off + self.safety_on = self.output.safety_on + self.reset() def reset(self): @@ -239,6 +250,7 @@ def reset(self): def run_profile(self, profile, startat=0): self.reset() + self.safety_off() if self.board.temp_sensor.noConnection: log.info("Refusing to start profile - thermocouple not connected") @@ -361,6 +373,10 @@ def __init__(self): self.R_ho_noair = config.sim_R_ho_noair self.R_ho = self.R_ho_noair + # simulated safeties + self.safety_off = log.info("energizing safety relay") + self.safety_on = log.info("deenergizing safety relay") + # set temps to the temp of the surrounding environment self.t = self.t_env # deg C temp of oven self.t_h = self.t_env #deg C temp of heating element @@ -438,7 +454,6 @@ def __init__(self): self.output = Output() self.reset() - # call parent init Oven.__init__(self) @@ -447,14 +462,14 @@ def __init__(self): if self.output.temp_disp: self.output.temp_disp.temp(self.temperature) - self.output.safety_off() + self.safety_off() # start thread self.start() def reset(self): super().reset() - self.output.safety_on() + self.safety_on() self.output.cool(0) def heat_then_cool(self): From 160e32bb1bf588ef2c6c452db400a231cf112783 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 20:32:44 -0500 Subject: [PATCH 33/57] fixed bug --- lib/oven.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index f7793c4d..eecac1d4 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -239,6 +239,7 @@ def __init__(self): self.reset() def reset(self): + self.safety_on() self.state = "IDLE" self.profile = None self.start_time = 0 @@ -462,14 +463,11 @@ def __init__(self): if self.output.temp_disp: self.output.temp_disp.temp(self.temperature) - self.safety_off() - # start thread self.start() def reset(self): super().reset() - self.safety_on() self.output.cool(0) def heat_then_cool(self): From ae856689d8e968e041a001375de13a31743edec9 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 20:35:09 -0500 Subject: [PATCH 34/57] fixed bug --- lib/oven.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index eecac1d4..5497bb5c 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -233,13 +233,11 @@ def __init__(self): self.time_step = config.sensor_time_wait self.output = Output() - self.safety_off = self.output.safety_off - self.safety_on = self.output.safety_on self.reset() def reset(self): - self.safety_on() + self.output.safety_on() self.state = "IDLE" self.profile = None self.start_time = 0 @@ -251,7 +249,7 @@ def reset(self): def run_profile(self, profile, startat=0): self.reset() - self.safety_off() + self.output.safety_off() if self.board.temp_sensor.noConnection: log.info("Refusing to start profile - thermocouple not connected") @@ -374,10 +372,6 @@ def __init__(self): self.R_ho_noair = config.sim_R_ho_noair self.R_ho = self.R_ho_noair - # simulated safeties - self.safety_off = log.info("energizing safety relay") - self.safety_on = log.info("deenergizing safety relay") - # set temps to the temp of the surrounding environment self.t = self.t_env # deg C temp of oven self.t_h = self.t_env #deg C temp of heating element From 425acd262052a1eb08154c530346c4e7f6aaea76 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 20:41:51 -0500 Subject: [PATCH 35/57] splitting temp and time updates --- lib/oven.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 5497bb5c..414cc6f0 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -330,6 +330,10 @@ def reset_if_schedule_ended(self): self.reset() def get_state(self): + + if self.output.temp_disp: + self.output.temp_disp.temp(int(self.board.temp_sensor.temperature)) + state = { 'runtime': self.runtime, 'temperature': self.board.temp_sensor.temperature + config.thermocouple_offset, @@ -488,8 +492,6 @@ def heat_then_cool(self): if self.output.time_disp: self.output.time_disp.time(time_left_h, time_left_m) - if self.output.temp_disp: - self.output.temp_disp.temp(int(self.board.temp_sensor.temperature)) log.info("temp=%.2f, target=%.2f, pid=%.3f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % (self.board.temp_sensor.temperature + config.thermocouple_offset, From 41030fc91b6412c7de607d078bbfeeec56f1a574 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 5 Feb 2022 20:48:17 -0500 Subject: [PATCH 36/57] added reset to IDLE on time disp --- lib/oven.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/oven.py b/lib/oven.py index 414cc6f0..23ce8e51 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -233,12 +233,18 @@ def __init__(self): self.time_step = config.sensor_time_wait self.output = Output() + if self.output.time_disp: + self.output.time_disp.text(self.state) + if self.output.temp_disp: + self.output.temp_disp.temp(self.temperature) self.reset() def reset(self): self.output.safety_on() self.state = "IDLE" + if self.output.time_disp: + self.output.time_disp.text(self.state) self.profile = None self.start_time = 0 self.runtime = 0 @@ -456,11 +462,6 @@ def __init__(self): # call parent init Oven.__init__(self) - if self.output.time_disp: - self.output.time_disp.text(self.state) - if self.output.temp_disp: - self.output.temp_disp.temp(self.temperature) - # start thread self.start() From 5edbc8109eb1bc59298319bebd17ad7805ce6205 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 16 Jul 2022 12:21:54 -0400 Subject: [PATCH 37/57] added gpio off function on service stop --- gpio_off.py | 5 +++++ lib/init/kiln-controller.service | 1 + 2 files changed, 6 insertions(+) create mode 100644 gpio_off.py diff --git a/gpio_off.py b/gpio_off.py new file mode 100644 index 00000000..6a2dbcf7 --- /dev/null +++ b/gpio_off.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +if __name__ == "__main__": + pins = list(range(0,40)) + GPIO.setup(pins, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) diff --git a/lib/init/kiln-controller.service b/lib/init/kiln-controller.service index 318e4c05..1fc241cc 100644 --- a/lib/init/kiln-controller.service +++ b/lib/init/kiln-controller.service @@ -3,6 +3,7 @@ Description=kiln-controller [Service] ExecStart=/home/pi/kiln-controller/venv/bin/python /home/pi/kiln-controller/kiln-controller.py +ExecStopPost=/home/pi/kiln-controller/venv/bin/python /home/pi/kiln-controller/gpio_off.py [Install] WantedBy=multi-user.target From 0f2c85d3d0089260093ea727a0b84f53b230de78 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 23 Jul 2022 10:37:38 -0400 Subject: [PATCH 38/57] added *56 library* --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index cbe34f2b..dcaee763 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,6 @@ gevent gevent-websocket RPi.GPIO Adafruit-MAX31855 +Adafruit-MAX31856 Adafruit-GPIO websocket-client From 3ca0a557f6783756e07d53b5cfe94fad3dcbbe02 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 23 Jul 2022 10:42:39 -0400 Subject: [PATCH 39/57] added *56 library* --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dcaee763..cbe34f2b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,5 @@ gevent gevent-websocket RPi.GPIO Adafruit-MAX31855 -Adafruit-MAX31856 Adafruit-GPIO websocket-client From d6282008ced1d20a2807c4f29fbcdde667a31622 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 23 Jul 2022 10:53:18 -0400 Subject: [PATCH 40/57] changed log path --- config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.py b/config.py index 9c6f204a..bf0efd58 100644 --- a/config.py +++ b/config.py @@ -10,7 +10,7 @@ ### Logging log_level = logging.INFO log_format = '%(asctime)s %(levelname)s %(name)s: %(message)s' -log_file = '/var/log/kiln-controller.log' +log_file = '$HOME/kiln-controller.log' ### Server listening_ip = "0.0.0.0" @@ -113,7 +113,7 @@ ######################################################################## # # Simulation parameters -simulate = True +simulate = False sim_t_env = 60.0 # deg C sim_c_heat = 100.0 # J/K heat capacity of heat element sim_c_oven = 5000.0 # J/K heat capacity of oven From 281f78a7eac5dc70fbae4041bc110698e5d62179 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 23 Jul 2022 10:54:21 -0400 Subject: [PATCH 41/57] changed log path --- config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.py b/config.py index bf0efd58..baa5ce37 100644 --- a/config.py +++ b/config.py @@ -10,7 +10,7 @@ ### Logging log_level = logging.INFO log_format = '%(asctime)s %(levelname)s %(name)s: %(message)s' -log_file = '$HOME/kiln-controller.log' +log_file = '/home/pi/kiln-controller.log' ### Server listening_ip = "0.0.0.0" From a85926a04cf1414f28b5a81551f541db1d51321e Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 23 Jul 2022 11:12:27 -0400 Subject: [PATCH 42/57] adding status file --- config.py | 1 + lib/ovenWatcher.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/config.py b/config.py index baa5ce37..f170a115 100644 --- a/config.py +++ b/config.py @@ -11,6 +11,7 @@ log_level = logging.INFO log_format = '%(asctime)s %(levelname)s %(name)s: %(message)s' log_file = '/home/pi/kiln-controller.log' +status_file = '/home/pi/kiln-controller.status' ### Server listening_ip = "0.0.0.0" diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index 47d4d740..d699efe8 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -28,8 +28,12 @@ def __init__(self,oven): # FIXME - this should not be done in the Watcher, but in the Oven class def run(self): + + while True: oven_state = self.oven.get_state() + with open(config.status_file, 'w') as f + f.write(oven_state) # record state for any new clients that join if oven_state.get("state") == "RUNNING": From 5862e4caf1e0fcf3d0affe49a0262536eea4acc9 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 23 Jul 2022 11:13:07 -0400 Subject: [PATCH 43/57] adding status file --- lib/ovenWatcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index d699efe8..be899d32 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -32,7 +32,7 @@ def run(self): while True: oven_state = self.oven.get_state() - with open(config.status_file, 'w') as f + with open(config.status_file, 'w') as f: f.write(oven_state) # record state for any new clients that join From cf69e36ef3343855e4065ceff02da16d1a926b6e Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 23 Jul 2022 11:15:03 -0400 Subject: [PATCH 44/57] adding status file --- lib/ovenWatcher.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ovenWatcher.py b/lib/ovenWatcher.py index be899d32..172d2501 100644 --- a/lib/ovenWatcher.py +++ b/lib/ovenWatcher.py @@ -32,8 +32,9 @@ def run(self): while True: oven_state = self.oven.get_state() + with open(config.status_file, 'w') as f: - f.write(oven_state) + f.write(str(oven_state)) # record state for any new clients that join if oven_state.get("state") == "RUNNING": From a88c92f660a8f3b70f7ef39027cd59a20c7f3f5a Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 11:44:09 -0400 Subject: [PATCH 45/57] 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 00000000..e059f0f7 --- /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 00000000..93c228ce --- /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 00000000..7b93613f --- /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 23ce8e51..ff416584 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -253,6 +253,19 @@ def reset(self): 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 @@ def reset_if_emergency(self): 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: From 88d757790a3cb71a8f0c333908971321c2a83f6c Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 11:47:21 -0400 Subject: [PATCH 46/57] moved dotstar files --- lib/dotstar_fail.py => dotstar_fail.py | 0 lib/dotstar_watcher.py => dotstar_watcher.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename lib/dotstar_fail.py => dotstar_fail.py (100%) rename lib/dotstar_watcher.py => dotstar_watcher.py (100%) diff --git a/lib/dotstar_fail.py b/dotstar_fail.py similarity index 100% rename from lib/dotstar_fail.py rename to dotstar_fail.py diff --git a/lib/dotstar_watcher.py b/dotstar_watcher.py similarity index 100% rename from lib/dotstar_watcher.py rename to dotstar_watcher.py From a65e6800493a675fdd46c65da3d5512fa97c0dac Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:02:13 -0400 Subject: [PATCH 47/57] pin naming --- dotstar_watcher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index 93c228ce..fcbe1bee 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# import board +import board import asyncio import adafruit_dotstar import config @@ -100,8 +100,8 @@ async def main(): 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, + pixels = adafruit_dotstar.DotStar(getattr(board, 'D%s' % dotstar_clk), + getattr(board, 'D%s' % dotstar_dat), dotstar_num) substrip_len = ceil(dotstar_num/3.0) From 62a9b1252a7db1e08cfd016f98fc95eb1f5d15c2 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:03:51 -0400 Subject: [PATCH 48/57] pin naming --- dotstar_fail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotstar_fail.py b/dotstar_fail.py index e059f0f7..11d0024f 100644 --- a/dotstar_fail.py +++ b/dotstar_fail.py @@ -20,8 +20,8 @@ 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, +pixels = adafruit_dotstar.DotStar(getattr(board, 'D%s' % dotstar_clk), + getattr(board, 'D%s' % dotstar_dat), dotstar_num) blink = Blink(pixels, speed=0.5, color=PURPLE) From 871dc20dadf36099031e312beaa2702049f9e7c5 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:04:19 -0400 Subject: [PATCH 49/57] pin naming --- dotstar_fail.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dotstar_fail.py b/dotstar_fail.py index 11d0024f..0aa8f94a 100644 --- a/dotstar_fail.py +++ b/dotstar_fail.py @@ -11,6 +11,7 @@ Haxpress), but not on SAMD21 non-Express boards (such as QT Py or Trinket). """ import config +import board import adafruit_dotstar from adafruit_led_animation.animation.blink import Blink From 6cff7ddf435fc4f973e94a27b3880028a6da6752 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:06:33 -0400 Subject: [PATCH 50/57] testing --- dotstar_watcher.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index fcbe1bee..ad38654e 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -106,9 +106,9 @@ async def main(): substrip_len = ceil(dotstar_num/3.0) - # strip_left = PixelSubset(pixels, - # 0, - # substrip_len) + strip_left = PixelSubset(pixels, + 0, + substrip_len) # strip_right = PixelSubset(pixels, # dotstar_num - substrip_len, @@ -122,8 +122,10 @@ async def main(): kiln_status)) check_task = asyncio.create_task(update_status(kiln_status)) + l_blink = Blink(strip_left, speed=0.5, color=PURPLE) + l_blink.animate() + await asyncio.gather(check_task, top_task) -if __name__ == "__main__": - asyncio.run(main()) +asyncio.run(main()) From 154525358c48ea4c998d3628447f8a5b05399491 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:07:19 -0400 Subject: [PATCH 51/57] testing --- dotstar_watcher.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index ad38654e..86df0dd4 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -11,6 +11,8 @@ from adafruit_led_animation.animation.pulse import Pulse from adafruit_led_animation.animation.comet import Comet from adafruit_led_animation.animation.blink import Blink +from adafruit_led_animation.color import PURPLE + time_int = 0.5 From 622c7ed23637ebb767e3c30574701739d4db3dd3 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:14:34 -0400 Subject: [PATCH 52/57] testing --- dotstar_watcher.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index 86df0dd4..aa8a15c1 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -89,6 +89,11 @@ async def task_strip_top(pixels, kiln_status): top.animate() await asyncio.sleep(time_int) +async def task_strip_right(pixels, kiln_status): + while True: + r_blink = Blink(pixels, speed=0.5, color=PURPLE) + r_blink.animate() + await asyncio.sleep(0) async def main(): @@ -112,9 +117,9 @@ async def main(): 0, substrip_len) - # strip_right = PixelSubset(pixels, - # dotstar_num - substrip_len, - # dotstar_num) + strip_right = PixelSubset(pixels, + dotstar_num - substrip_len, + dotstar_num) strip_top = PixelSubset(pixels, substrip_len, @@ -123,11 +128,13 @@ async def main(): top_task = asyncio.create_task(task_strip_top(strip_top, kiln_status)) check_task = asyncio.create_task(update_status(kiln_status)) + right_task = asyncio.create_task(task_strip_right(strip_right, + kiln_status)) l_blink = Blink(strip_left, speed=0.5, color=PURPLE) l_blink.animate() - await asyncio.gather(check_task, top_task) + await asyncio.gather(check_task, top_task, right_task) asyncio.run(main()) From b50ac3e9ac2fbee2a51bbba7bdf8feffbe630436 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:22:08 -0400 Subject: [PATCH 53/57] testing --- dotstar_watcher.py | 48 ++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index aa8a15c1..a3631a18 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -1,10 +1,10 @@ #!/usr/bin/env python import board -import asyncio import adafruit_dotstar import config import ast +from time import sleep from math import ceil from adafruit_led_animation.helper import PixelSubset from adafruit_led_animation.animation.rainbowchase import RainbowChase @@ -51,16 +51,15 @@ def check_status(self): # 'pidstats': {}} -async def update_status(kiln_status): +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) + + kiln_status.check_status() -async def task_strip_top(pixels, kiln_status): +def task_strip_top(pixels, kiln_status): while True: if kiln_status.state == 'STARTUP': top = RainbowChase(pixels, @@ -86,16 +85,13 @@ async def task_strip_top(pixels, kiln_status): top = Blink(pixels, 0.7, (255, 0, 0)) - top.animate() - await asyncio.sleep(time_int) + return(top) -async def task_strip_right(pixels, kiln_status): - while True: - r_blink = Blink(pixels, speed=0.5, color=PURPLE) - r_blink.animate() - await asyncio.sleep(0) +def task_strip_right(pixels, kiln_status): + r_blink = Blink(pixels, speed=0.5, color=PURPLE) + return(r_blink) -async def main(): +def main(): # setup @@ -125,16 +121,18 @@ async def main(): 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)) - right_task = asyncio.create_task(task_strip_right(strip_right, - kiln_status)) - l_blink = Blink(strip_left, speed=0.5, color=PURPLE) - l_blink.animate() - await asyncio.gather(check_task, top_task, right_task) - - -asyncio.run(main()) + while True: + kiln_status.check_status() + animations = AnimationSequence( + AnimationGroup( + l_blink, + task_strip_right(strip_right, kiln_status), + task_strip_top(strip_top, kiln_status) + ) + animations.animate() + sleep(time_int) + +if __name__ == "__main__": + main() From 22f6ffbaf174404d641512522f8a9c2fed55343e Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:22:48 -0400 Subject: [PATCH 54/57] testing --- dotstar_watcher.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index a3631a18..17ff9758 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -12,6 +12,8 @@ from adafruit_led_animation.animation.comet import Comet from adafruit_led_animation.animation.blink import Blink from adafruit_led_animation.color import PURPLE +from adafruit_led_animation.group import AnimationGroup +from adafruit_led_animation.sequence import AnimationSequence time_int = 0.5 @@ -126,11 +128,11 @@ def main(): while True: kiln_status.check_status() animations = AnimationSequence( - AnimationGroup( - l_blink, - task_strip_right(strip_right, kiln_status), - task_strip_top(strip_top, kiln_status) - ) + AnimationGroup( + l_blink, + task_strip_right(strip_right, kiln_status), + task_strip_top(strip_top, kiln_status) + )) animations.animate() sleep(time_int) From 24449ea7be4466e55f6fb66598ace4f964fa987f Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:24:32 -0400 Subject: [PATCH 55/57] testing --- dotstar_watcher.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index 17ff9758..0c92edb6 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -126,14 +126,15 @@ def main(): l_blink = Blink(strip_left, speed=0.5, color=PURPLE) while True: - kiln_status.check_status() - animations = AnimationSequence( - AnimationGroup( - l_blink, - task_strip_right(strip_right, kiln_status), - task_strip_top(strip_top, kiln_status) - )) - animations.animate() + # kiln_status.check_status() + # animations = AnimationSequence( + # AnimationGroup( + # l_blink, + # task_strip_right(strip_right, kiln_status), + # task_strip_top(strip_top, kiln_status) + # )) + # animations.animate() + l_blink.animate() sleep(time_int) if __name__ == "__main__": From 17c26a404a9947fdbd2be3176974d0ba83d42e8a Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:30:16 -0400 Subject: [PATCH 56/57] testing --- dotstar_watcher.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index 0c92edb6..0d7f06c0 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -124,17 +124,17 @@ def main(): dotstar_num - substrip_len) l_blink = Blink(strip_left, speed=0.5, color=PURPLE) + + animations = AnimationSequence( + AnimationGroup( + l_blink + # task_strip_right(strip_right, kiln_status), + # task_strip_top(strip_top, kiln_status) + )) while True: - # kiln_status.check_status() - # animations = AnimationSequence( - # AnimationGroup( - # l_blink, - # task_strip_right(strip_right, kiln_status), - # task_strip_top(strip_top, kiln_status) - # )) - # animations.animate() - l_blink.animate() + kiln_status.check_status() + animations.animate() sleep(time_int) if __name__ == "__main__": From f5087f008f069041c4aa05cc481b4af58d2b20c4 Mon Sep 17 00:00:00 2001 From: Tanaes Date: Sat, 6 Aug 2022 12:32:30 -0400 Subject: [PATCH 57/57] testing --- dotstar_watcher.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dotstar_watcher.py b/dotstar_watcher.py index 0d7f06c0..5961f774 100644 --- a/dotstar_watcher.py +++ b/dotstar_watcher.py @@ -124,16 +124,18 @@ def main(): dotstar_num - substrip_len) l_blink = Blink(strip_left, speed=0.5, color=PURPLE) - - animations = AnimationSequence( - AnimationGroup( - l_blink - # task_strip_right(strip_right, kiln_status), - # task_strip_top(strip_top, kiln_status) - )) + while True: kiln_status.check_status() + right = task_strip_right(strip_right, kiln_status) + top = task_strip_top(strip_top, kiln_status) + animations = AnimationSequence( + AnimationGroup( + l_blink, + right, + top + )) animations.animate() sleep(time_int)