From f73636701cfb878e41377b05873d116cfbcd8308 Mon Sep 17 00:00:00 2001 From: marktilles <82381104+marktilles@users.noreply.github.com> Date: Mon, 5 Jul 2021 22:20:46 +0200 Subject: [PATCH] Update --- .DS_Store | Bin 6148 -> 0 bytes lib/.DS_Store | Bin 6148 -> 0 bytes lib/oven.py | 157 ++++++++++++++++++++++++++++++++++------------- public/.DS_Store | Bin 6148 -> 0 bytes 4 files changed, 114 insertions(+), 43 deletions(-) delete mode 100644 .DS_Store delete mode 100644 lib/.DS_Store delete mode 100644 public/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index a9211d2295a9c7dd5bf246bdd3793fb5f1c56103..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}&EG40g5woe*LN1RQhWw!`=pJ0Mj94&0E6-~b33IzgqDmI@8jgyW^$$2V>g67CND$xpi z&#E&P&5qy506n`hBoKpA{rAr=iL<=XcoC&?Wnyy5tKx6QI}NUMKgh$pm$ky~G4=Mt z{7O0dKwso3^aoX;hjFtKP!W^48w@_3ho@e)#Zc85Q{Q8JTrBf+sZG=5B&+n&|Wr zJrq3&9q55F8^4IMi$vjHr?e@^AO{Uy2;maiqoL6X6vDy`FaylMpJ%`wYTopp-wAJk z8DIv!n*ll>Br2iru&`*34s1*bfJmQ_M$o2Of^wuo-(g`9M^J=KMYO5Hl^DXNqhGo> z-(g|Vrh{K-%h`z(ZB6?8xL%`6$4Kwhg G47>uVZ(Dr; diff --git a/lib/.DS_Store b/lib/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 (self.time_step * 2): + if self.bad_count + self.ok_count: + self.bad_percent = (self.bad_count / (self.bad_count + self.ok_count)) * 100 + else: + self.bad_percent = 0 + self.bad_count = 0 + self.ok_count = 0 + self.bad_stamp = time.time() + + temp = self.thermocouple.get() + self.noConnection = self.thermocouple.noConnection + self.shortToGround = self.thermocouple.shortToGround + self.shortToVCC = self.thermocouple.shortToVCC + self.unknownError = self.thermocouple.unknownError + + is_bad_value = self.noConnection | self.unknownError + if config.honour_theromocouple_short_errors: + is_bad_value |= self.shortToGround | self.shortToVCC + + if not is_bad_value: + temps.append(temp) + if len(temps) > config.temperature_average_samples: + del temps[0] + self.ok_count += 1 + + else: + log.error("Problem reading temp N/C:%s GND:%s VCC:%s ???:%s" % (self.noConnection,self.shortToGround,self.shortToVCC,self.unknownError)) + self.bad_count += 1 + + if len(temps): + self.temperature = sum(temps) / len(temps) + time.sleep(self.sleeptime) class Oven(threading.Thread): '''parent oven class. this has all the common code @@ -155,8 +184,22 @@ class Oven(threading.Thread): self.pid = PID(ki=config.pid_ki, kd=config.pid_kd, kp=config.pid_kp) def run_profile(self, profile, startat=0): - log.info("Running schedule %s" % profile.name) self.reset() + + if self.board.temp_sensor.noConnection: + log.info("Refusing to start profile - thermocouple not connected") + return + if self.board.temp_sensor.shortToGround: + log.info("Refusing to start profile - thermocouple short to ground") + return + if self.board.temp_sensor.shortToVCC: + log.info("Refusing to start profile - thermocouple short to VCC") + return + if self.board.temp_sensor.unknownError: + log.info("Refusing to start profile - thermocouple unknown error") + return + + log.info("Running schedule %s" % profile.name) self.profile = profile self.totaltime = profile.get_duration() self.state = "RUNNING" @@ -186,6 +229,9 @@ class Oven(threading.Thread): def update_runtime(self): runtime_delta = datetime.datetime.now() - self.start_time + if runtime_delta.total_seconds() < 0: + runtime_delta = datetime.timedelta(0) + if self.startat > 0: self.runtime = self.startat + runtime_delta.total_seconds() else: @@ -195,12 +241,24 @@ class Oven(threading.Thread): self.target = self.profile.get_target_temperature(self.runtime) def reset_if_emergency(self): - '''reset if the temperature is way TOO HOT''' + '''reset if the temperature is way TOO HOT, or other critical errors detected''' if (self.board.temp_sensor.temperature + config.thermocouple_offset >= config.emergency_shutoff_temp): log.info("emergency!!! temperature too high, shutting down") self.reset() + if self.board.temp_sensor.noConnection: + log.info("emergency!!! lost connection to thermocouple, shutting down") + self.reset() + + if self.board.temp_sensor.unknownError: + log.info("emergency!!! unknown thermocouple error, shutting down") + self.reset() + + if self.board.temp_sensor.bad_percent > 30: + log.info("emergency!!! too many errors in a short period, shutting down") + self.reset() + def reset_if_schedule_ended(self): if self.runtime > self.totaltime: log.info("schedule ended, shutting down") @@ -214,6 +272,8 @@ class Oven(threading.Thread): 'state': self.state, 'heat': self.heat, 'totaltime': self.totaltime, + 'kwh_rate': config.kwh_rate, + 'currency_type': config.currency_type, 'profile': self.profile.name if self.profile else None, } return state @@ -249,10 +309,10 @@ class SimulatedOven(Oven): # 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 - + # call parent init Oven.__init__(self) - + # start thread self.start() log.info("SimulatedOven started") @@ -310,9 +370,9 @@ class SimulatedOven(Oven): self.runtime, self.totaltime, time_left)) - + # we don't actually spend time heating & cooling during - # a simulation, so sleep. + # a simulation, so sleep. time.sleep(self.time_step) @@ -329,6 +389,10 @@ class RealOven(Oven): # start thread self.start() + def reset(self): + super().reset() + self.output.cool(0) + def heat_then_cool(self): pid = self.pid.compute(self.target, self.board.temp_sensor.temperature + @@ -341,8 +405,10 @@ class RealOven(Oven): if heat_on > 0: self.heat = 1.0 - self.output.heat(heat_on) - self.output.cool(heat_off) + if heat_on: + self.output.heat(heat_on) + if heat_off: + self.output.cool(heat_off) time_left = self.totaltime - self.runtime 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, @@ -400,7 +466,7 @@ class PID(): self.lastErr = 0 # FIX - this was using a really small window where the PID control - # takes effect from -1 to 1. I changed this to various numbers and + # takes effect from -1 to 1. I changed this to various numbers and # settled on -50 to 50 and then divide by 50 at the end. This results # in a larger PID control window and much more accurate control... # instead of what used to be binary on/off control. @@ -413,8 +479,12 @@ class PID(): error = float(setpoint - ispoint) if self.ki > 0: - self.iterm += (error * timeDelta * (1/self.ki)) - + if config.stop_integral_windup == True: + if abs(self.kp * error) < window_size: + self.iterm += (error * timeDelta * (1/self.ki)) + else: + self.iterm += (error * timeDelta * (1/self.ki)) + dErr = (error - self.lastErr) / timeDelta output = self.kp * error + self.iterm + self.kd * dErr out4logs = output @@ -426,15 +496,16 @@ class PID(): if output < 0: output = 0 - #if output > 1: - # output = 1 - output = float(output / window_size) - if out4logs > 0: - log.info("pid percents pid=%0.2f p=%0.2f i=%0.2f d=%0.2f" % (out4logs, - ((self.kp * error)/out4logs)*100, - (self.iterm/out4logs)*100, - ((self.kd * dErr)/out4logs)*100)) + if out4logs > 0: +# log.info("pid percents pid=%0.2f p=%0.2f i=%0.2f d=%0.2f" % (out4logs, +# ((self.kp * error)/out4logs)*100, +# (self.iterm/out4logs)*100, +# ((self.kd * dErr)/out4logs)*100)) + log.info("pid actuals pid=%0.2f p=%0.2f i=%0.2f d=%0.2f" % (out4logs, + self.kp * error, + self.iterm, + self.kd * dErr)) return output diff --git a/public/.DS_Store b/public/.DS_Store deleted file mode 100644 index eba7a31ae9f14d044b5485778d28c257b6f7c216..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z-NTO%bsNQIC7^)Wnc96tPr;<`cnj)CDOS4kE;i8om#iP zk!8(>*g4pnHbmAw+;528c6&OlS)1Ffqto8q!(;X|eSXora`*(5tQnlaD;R|>-n-*y zD5G2O&vIt5gv0-&E(iF(8UG4Q7t;FXTsabQcPwk~WAYpnq7fudksu5q3MhAPDn fi=}uAR0;S68i2OJTqAfu=tn@&Kn*eQqYQiiE_zZp