|
- import time
- import datetime
- from flask import json, request
- from flask_classy import route
-
- from modules import DBModel, cbpi, get_db
- from modules.core.baseview import BaseView
-
-
- class Step(DBModel):
- __fields__ = ["name","type", "stepstate", "state", "start", "end", "order", "config"]
- __table_name__ = "step"
- __json_fields__ = ["config", "stepstate"]
- __order_by__ = "order"
- __as_array__ = True
-
- @classmethod
- def get_max_order(cls):
- cur = get_db().cursor()
- cur.execute("SELECT max(step.'order') as 'order' FROM %s" % cls.__table_name__)
- r = cur.fetchone()
- return r.get("order")
-
- @classmethod
- def get_by_state(cls, state, order=True):
- cur = get_db().cursor()
- cur.execute("SELECT * FROM %s WHERE state = ? ORDER BY %s.'order'" % (cls.__table_name__,cls.__table_name__,), state)
- r = cur.fetchone()
- if r is not None:
- return cls(r)
- else:
- return None
-
- @classmethod
- def delete_all(cls):
- cur = get_db().cursor()
- cur.execute("DELETE FROM %s" % cls.__table_name__)
- get_db().commit()
-
- @classmethod
- def reset_all_steps(cls):
- cur = get_db().cursor()
- cur.execute("UPDATE %s SET state = 'I', stepstate = NULL , start = NULL, end = NULL " % cls.__table_name__)
- get_db().commit()
-
- @classmethod
- def update_state(cls, id, state):
- cur = get_db().cursor()
- cur.execute("UPDATE %s SET state = ? WHERE id =?" % cls.__table_name__, (state, id))
- get_db().commit()
-
- @classmethod
- def update_step_state(cls, id, state):
- cur = get_db().cursor()
- cur.execute("UPDATE %s SET stepstate = ? WHERE id =?" % cls.__table_name__, (json.dumps(state),id))
- get_db().commit()
-
- @classmethod
- def sort(cls, new_order):
- cur = get_db().cursor()
-
- for e in new_order:
-
- cur.execute("UPDATE %s SET '%s' = ? WHERE id = ?" % (cls.__table_name__, "order"), (e[1], e[0]))
- get_db().commit()
-
-
- class StepView(BaseView):
- model = Step
- def _pre_post_callback(self, data):
- order = self.model.get_max_order()
- data["order"] = 1 if order is None else order + 1
- data["state"] = "I"
-
- @route('/sort', methods=["POST"])
- def sort_steps(self):
- Step.sort(request.json)
- cbpi.emit("UPDATE_ALL_STEPS", self.model.get_all())
- return ('', 204)
-
- @route('/', methods=["DELETE"])
- def deleteAll(self):
- self.model.delete_all()
- cbpi.emit("UPDATE_ALL_STEPS", self.model.get_all())
- return ('', 204)
-
- @route('/action/<method>', methods=["POST"])
- def action(self, method):
- cbpi.cache["active_step"].__getattribute__(method)()
- return ('', 204)
-
- @route('/reset', methods=["POST"])
- def reset(self):
- self.model.reset_all_steps()
- self.stop_step()
- cbpi.emit("UPDATE_ALL_STEPS", self.model.get_all())
- cbpi.cache["active_brew"] = "none"
- return ('', 204)
-
- def stop_step(self):
- '''
- stop active step
- :return:
- '''
- step = cbpi.cache.get("active_step")
- cbpi.cache["active_step"] = None
-
- if step is not None:
- step.finish()
-
- @route('/reset/current', methods=['POST'])
- def resetCurrentStep(self):
- '''
- Reset current step
- :return:
- '''
- step = cbpi.cache.get("active_step")
-
- if step is not None:
- step.reset()
- if step.is_dirty():
-
- state = {}
- for field in step.managed_fields:
- state[field] = step.__getattribute__(field)
- Step.update_step_state(step.id, state)
- step.reset_dirty()
- cbpi.emit("UPDATE_ALL_STEPS", self.model.get_all())
- return ('', 204)
-
- def init_step(self, step):
- cbpi.log_action("Start Step %s" % step.name)
- type_cfg = cbpi.cache.get("step_types").get(step.type)
- if type_cfg is None:
- # if type not found
- return
-
- # copy config to stepstate
- # init step
- cfg = step.config.copy()
- cfg.update(dict(name=step.name, api=cbpi, id=step.id, timer_end=None, managed_fields=get_manged_fields_as_array(type_cfg)))
- instance = type_cfg.get("class")(**cfg)
- instance.init()
- # set step instance to ache
- cbpi.cache["active_step"] = instance
-
- @route('/start', methods=['POST'])
- def start(self):
- if "none" == cbpi.cache["active_brew"]:
- cbpi.cache["active_brew"] = cbpi.cache["config"]["brew_name"].__dict__["value"] + \
- "_" + datetime.datetime.now().strftime('%y-%m-%dT%H:%M')
- return self.next()
-
- @route('/next', methods=['POST'])
- def next(self):
- active = Step.get_by_state("A")
- inactive = Step.get_by_state('I')
-
- if (active is not None):
- active.state = 'D'
- active.end = int(time.time())
- self.stop_step()
- Step.update(**active.__dict__)
-
- if (inactive is not None):
- self.init_step(inactive)
- inactive.state = 'A'
- inactive.stepstate = inactive.config
- inactive.start = int(time.time())
- Step.update(**inactive.__dict__)
- else:
- cbpi.log_action("Brewing Finished")
- cbpi.notify("Brewing Finished", "You are done!", timeout=None)
- cbpi.cache["active_brew"] = "none"
-
- cbpi.emit("UPDATE_ALL_STEPS", Step.get_all())
- return ('', 204)
-
- def get_manged_fields_as_array(type_cfg):
-
- result = []
- for f in type_cfg.get("properties"):
-
- result.append(f.get("name"))
-
- return result
-
- @cbpi.try_catch(None)
- def init_after_startup():
- '''
- Restart after startup. Check is a step is in state A and reinitialize
- :return: None
- '''
-
- step = Step.get_by_state('A')
- # We have an active step
- if step is not None:
-
- # get the type
-
-
- type_cfg = cbpi.cache.get("step_types").get(step.type)
-
- if type_cfg is None:
- # step type not found. cant restart step
- return
-
- cfg = step.stepstate.copy()
- cfg.update(dict(api=cbpi, id=step.id, managed_fields=get_manged_fields_as_array(type_cfg)))
- instance = type_cfg.get("class")(**cfg)
- instance.init()
- cbpi.cache["active_step"] = instance
-
- @cbpi.initalizer(order=2000)
- def init(cbpi):
-
- StepView.register(cbpi.app, route_base='/api/step')
-
- def get_all():
- with cbpi.app.app_context():
- return Step.get_all()
-
- with cbpi.app.app_context():
- init_after_startup()
- cbpi.add_cache_callback("steps", get_all)
-
- @cbpi.backgroundtask(key="step_task", interval=0.1)
- def execute_step(api):
- '''
- Background job which executes the step
- :return:
- '''
- with cbpi.app.app_context():
- step = cbpi.cache.get("active_step")
- if step is not None:
- step.execute()
- if step.is_dirty():
- state = {}
- for field in step.managed_fields:
- state[field] = step.__getattribute__(field)
- Step.update_step_state(step.id, state)
- step.reset_dirty()
- cbpi.emit("UPDATE_ALL_STEPS", Step.get_all())
-
- if step.n is True:
-
- StepView().start()
- cbpi.emit("UPDATE_ALL_STEPS", Step.get_all())
|