kiln-controller/lib/ovenWatcher.py
2022-02-05 11:23:27 -05:00

137 lines
4.1 KiB
Python

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
self.last_log = []
self.started = None
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
self.start()
# FIXME - need to save runs of schedules in near-real-time
# FIXME - this will enable re-start in case of power outage
# FIXME - re-start also requires safety start (pausing at the beginning
# until a temp is reached)
# FIXME - re-start requires a time setting in minutes. if power has been
# out more than N minutes, don't restart
# 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()
# record state for any new clients that join
if oven_state.get("state") == "RUNNING":
self.last_log.append(oven_state)
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):
'''send about maxpts from lastlog by skipping unwanted data'''
totalpts = len(self.last_log)
if (totalpts <= maxpts):
return self.last_log
every_nth = int(totalpts / (maxpts - 1))
return self.last_log[::every_nth]
def record(self, profile):
self.last_profile = profile
self.last_log = []
self.started = datetime.datetime.now()
self.recording = True
#we just turned on, add first state for nice graph
self.last_log.append(self.oven.get_state())
def add_observer(self,observer):
if self.last_profile:
p = {
"name": self.last_profile.name,
"data": self.last_profile.data,
"type" : "profile"
}
else:
p = None
backlog = {
'type': "backlog",
'profile': p,
'log': self.lastlog_subset(),
#'started': self.started
}
print(backlog)
backlog_json = json.dumps(backlog)
try:
print(backlog_json)
observer.send(backlog_json)
except:
log.error("Could not send backlog to new observer")
self.observers.append(observer)
def notify_all(self,message):
message_json = json.dumps(message)
log.debug("sending to %d clients: %s"%(len(self.observers),message_json))
for wsock in self.observers:
if wsock:
try:
wsock.send(message_json)
except:
log.error("could not write to socket %s"%wsock)
self.observers.remove(wsock)
else:
self.observers.remove(wsock)