diff --git a/cbpi/__init__.py b/cbpi/__init__.py index 7eed2ed..a48bba4 100644 --- a/cbpi/__init__.py +++ b/cbpi/__init__.py @@ -1 +1 @@ -__version__ = "4.0.2.0.a8" +__version__ = "4.0.2.0.a19" diff --git a/cbpi/api/dataclasses.py b/cbpi/api/dataclasses.py index 996d13b..921582c 100644 --- a/cbpi/api/dataclasses.py +++ b/cbpi/api/dataclasses.py @@ -131,7 +131,7 @@ class Fermenter: brewname: str = None description : str = None props: Props = Props() - target_temp: int = 0 + target_temp: float = 0 type: str = None steps: List[Step]= field(default_factory=list) instance: str = None @@ -162,7 +162,7 @@ class FermenterStep: props: Props = Props() type: str = None status: StepState = StepState.INITIAL - endtime: int = 0 # endtime if step is active and timer is running + endtime: int = 0 # endtime if step is active and timer is running instance: str = None step: dict = None @@ -170,7 +170,7 @@ class FermenterStep: return "name={} props={}, type={}, instance={}".format(self.name, self.props, self.type, self.instance) def to_dict(self): msg = self.instance.summary if self.instance is not None else "" - return dict(id=self.id, name=self.name, state_text=msg, type=self.type, status=self.status.value, endtime = self.endtime, props=self.props.to_dict()) + return dict(id=self.id, name=self.name, state_text=msg, type=self.type, status=self.status.value, endtime=self.endtime, props=self.props.to_dict()) diff --git a/cbpi/api/step.py b/cbpi/api/step.py index 7c20378..bf30778 100644 --- a/cbpi/api/step.py +++ b/cbpi/api/step.py @@ -117,15 +117,6 @@ class CBPiStep(CBPiBase): def __str__(self): return "name={} props={}, type={}".format(self.name, self.props, self.__class__.__name__) -#class CBPiFermentationStep(CBPiStep): - -# def __init__(self, cbpi, fermenter, step, props, on_done) -> None: -# self.fermenter = fermenter -# id = step.get("id") -# name=step.get("name") -# self.step=step -# super().__init__(cbpi, id, name, props, on_done) - class CBPiFermentationStep(CBPiBase): def __init__(self, cbpi, fermenter, step, props, on_done) -> None: @@ -190,9 +181,9 @@ class CBPiFermentationStep(CBPiBase): async def update_endtime(self): await self.cbpi.fermenter.update_endtime(self.fermenter.id, self.id, self.endtime) - + async def save_props(self): - self.cbpi.fermenter.save() + self.cbpi.fermenter.save() async def push_update(self): self.cbpi.fermenter.push_update(self.update_key) diff --git a/cbpi/controller/basic_controller2.py b/cbpi/controller/basic_controller2.py index 53c3445..990f54e 100644 --- a/cbpi/controller/basic_controller2.py +++ b/cbpi/controller/basic_controller2.py @@ -22,7 +22,7 @@ class BasicController: self.logger = logging.getLogger(__name__) self.data = [] self.autostart = True - self._loop = asyncio.get_event_loop() + #self._loop = asyncio.get_event_loop() self.path = os.path.join(".", 'config', file) self.cbpi.app.on_cleanup.append(self.shutdown) @@ -100,7 +100,8 @@ class BasicController: await item.instance.start() item.instance.running = True - item.instance.task = self._loop.create_task(item.instance._run()) + item.instance.task = asyncio.get_event_loop().create_task(item.instance._run()) + #item.instance.task = self._loop.create_task(item.instance._run()) logging.info("{} started {}".format(self.name, id)) diff --git a/cbpi/controller/fermentation_controller.py b/cbpi/controller/fermentation_controller.py index 8a749d4..e48bb50 100644 --- a/cbpi/controller/fermentation_controller.py +++ b/cbpi/controller/fermentation_controller.py @@ -15,79 +15,7 @@ from cbpi.controller.basic_controller2 import BasicController from tabulate import tabulate import sys, os from ..api.step import CBPiStep, StepMove, StepResult, StepState, CBPiFermentationStep - - - -class FermentStep: - - def __init__(self, cbpi, step, on_done) -> None: - self.cbpi = cbpi - self.logger = logging.getLogger(__name__) - self.step = step - self.props = step.props - self._done_callback = on_done - self.task = None - self.summary = "" - - def _done(self, task): - if self._done_callback is not None: - try: - result = task.result() - self._done_callback(self, result) - except Exception as e: - self.logger.error(e) - - @abstractmethod - async def run(self): - while self.running: - logging.info(self.step) - await asyncio.sleep(1) - pass - - async def _run(self): - try: - await self.step.instance.on_start() - await self.step.instance.run() - #await self.on_start() - #await self.run() - self.cancel_reason = StepResult.DONE - except asyncio.CancelledError as e: - pass - finally: - await self.on_stop() - - return self.cancel_reason - - async def start(self): - self.logger.info("Start {}".format(self.step.name)) - self.running = True - self.task = asyncio.create_task(self._run()) - self.task.add_done_callback(self._done) - - async def next(self): - self.running = False - self.cancel_reason = StepResult.NEXT - self.task.cancel() - await self.task - - async def stop(self): - try: - self.running = False - if self.task is not None and self.task.done() is False: - self.logger.info("Stopping Task") - self.cancel_reason = StepResult.STOP - self.task.cancel() - await self.task - except Exception as e: - self.logger.error(e) - - async def on_start(self): - #self.props.hello = "WOOHOo" - pass - - async def on_stop(self): - pass - + class FermentationController: def __init__(self, cbpi): @@ -95,7 +23,6 @@ class FermentationController: self.cbpi = cbpi self.logger = logging.getLogger(__name__) self.path = os.path.join(".", 'config', "fermenter_data.json") - self.data = [] self.types = {} self.steptypes = {} @@ -127,6 +54,10 @@ class FermentationController: for step in fermenter.steps: try: self.logger.info("Stop {}".format(step.name)) + try: + step.instance.shutdown = True + except: + pass await step.instance.stop() except Exception as e: self.logger.error(e) @@ -136,15 +67,16 @@ class FermentationController: for step in fermenter.steps: try: self.logger.info("Stop {}".format(step.name)) + try: + step.instance.shutdown = True + except: + pass await step.instance.stop() except Exception as e: self.logger.error(e) async def load(self): -# if os.path.exists(self.path) is False: -# with open(self.path, "w") as file: -# json.dump(dict(basic={}, steps=[]), file, indent=4, sort_keys=True) with open(self.path) as json_file: data = json.load(json_file) @@ -155,12 +87,14 @@ class FermentationController: id = item.get("id") name = item.get("name") props = Props(item.get("props")) + try: + endtime = int(item.get("endtime", 0)) + except: + endtime=0 + status = StepState(item.get("status", "I")) - endtime = int(item.get("endtime", 0)) if status == StepState.ACTIVE: status = StepState("S") - if status != StepState.STOP: - endtime = 0 type = item.get("type") try: @@ -221,7 +155,6 @@ class FermentationController: def get_state(self): if self.data == []: - #logging.info(self.data) pass return {"data": list(map(lambda x: x.to_dict(), self.data)), "types":self.get_types(), "steptypes":self.get_steptypes()} @@ -238,7 +171,6 @@ class FermentationController: def get_fermenter_steps(self): if self.data == []: - #logging.info(self.data) pass fermentersteps=[] steplist=list(map(lambda x: x.to_dict(), self.data)) @@ -307,16 +239,16 @@ class FermentationController: with open(self.path, "w") as file: json.dump(data, file, indent=4, sort_keys=True) - async def create_step(self, id, item): + def create_step(self, id, item): try: stepid = shortuuid.uuid() - props = item.get("props") + item['id'] = stepid status = StepState("I") type = item.get("type") name = item.get("name") + endtime = item.get("endtime", 0) props = Props(item.get("props")) fermenter = self._find_by_id(id) - try: type_cfg = self.steptypes.get(type) clazz = type_cfg.get("class") @@ -324,13 +256,8 @@ class FermentationController: except Exception as e: logging.warning("Failed to create step instance %s - %s" % (id, e)) instance = None - step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, instance=instance) + step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, endtime=endtime, instance=instance) - - - fermenter.steps.append(step) - self.save() - self.push_update("fermenterstepupdate") return step except Exception as e: self.logger.error(e) @@ -341,30 +268,29 @@ class FermentationController: props = item.get("props") status = StepState("I") type = item.get("type") - #logging.info(type) + endtime = 0 name = item.get("name") props = Props(item.get("props")) logging.info("update step") try: type_cfg = self.steptypes.get(type) - #logging.info(type_cfg) + logging.info(type_cfg) clazz = type_cfg.get("class") - #logging.info(clazz) + logging.info(clazz) instance = clazz(self.cbpi, fermenter, item, props, self._done) + logging.info(instance) except Exception as e: logging.warning("Failed to create step instance %s - %s " % (item.id, e)) instance = None - step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, instance=instance) - #logging.info(step) - #logging.info(fermenter.steps) + step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, endtime=endtime, instance=instance) + try: fermenter.steps = list(map(lambda old: step if old.id == step.id else old, fermenter.steps)) except Exception as e: logging.info(e) - #logging.info(fermenter.steps) + self.save() - #logging.info("SAVEUPDATE") self.push_update("fermenterstepupdate") @@ -382,6 +308,15 @@ class FermentationController: self.save() self.push_update("fermenterstepupdate") + async def update_endtime(self, id, stepid, endtime): + try: + item = self._find_by_id(id) + step = self._find_step_by_id(item.steps, stepid) + step.endtime = int(endtime) + self.save() + self.push_update("fermenterstepupdate") + except Exception as e: + self.logger.error(e) def _find_by_status(self, data, status): return next((item for item in data if item.status == status), None) @@ -419,6 +354,7 @@ class FermentationController: logging.info("Need to change timer") step.status = StepState.ACTIVE self.save() + self.push_update() self.push_update("fermenterstepupdate") return @@ -432,6 +368,7 @@ class FermentationController: logging.info("Starting step {}".format(step.name)) step.status = StepState.ACTIVE self.save() + self.push_update() self.push_update("fermenterstepupdate") except Exception as e: @@ -517,7 +454,7 @@ class FermentationController: await self.start(id) else: logging.info("No Step is running") - + self.push_update() self.push_update("fermenterstepupdate") except Exception as e: @@ -531,12 +468,14 @@ class FermentationController: for step in item.steps: self.logger.info("Stopping Step {} {}".format(step.name, step.id)) try: + await step.instance.stop() await step.instance.reset() - await step.instance.stop() step.status = StepState.INITIAL + step.endtime = 0 except Exception as e: self.logger.error(e) self.save() + self.push_update() self.push_update("fermenterstepupdate") except Exception as e: @@ -555,6 +494,7 @@ class FermentationController: fermenter.steps[index], fermenter.steps[index+direction] = fermenter.steps[index+direction], fermenter.steps[index] self.save() + self.push_update() self.push_update("fermenterstepupdate") except Exception as e: @@ -564,15 +504,19 @@ class FermentationController: if key == self.update_key: self.cbpi.ws.send(dict(topic=key, data=list(map(lambda item: item.to_dict(), self.data)))) - #self.cbpi.push_update("cbpi/{}".format(self.update_key), list(map(lambda item: item.to_dict(), self.data))) - + for item in self.data: self.cbpi.push_update("cbpi/{}/{}".format(self.update_key,item.id), item.to_dict()) pass else: - #logging.info("FERMENTERSTEPUPDATE {}".format(key)) fermentersteps=self.get_fermenter_steps() self.cbpi.ws.send(dict(topic=key, data=fermentersteps)) + + # send mqtt update for active femrentersteps + for fermenter in fermentersteps: + for step in fermenter['steps']: + if step['status'] == 'A': + self.cbpi.push_update("cbpi/{}/{}/{}".format(key,fermenter['id'],step['id']), step) async def call_action(self, id, action, parameter) -> None: logging.info("FermenterStep Controller - call Action {} {}".format(id, action)) @@ -582,8 +526,7 @@ class FermentationController: await item.instance.__getattribute__(action)(**parameter) except Exception as e: logging.error("FermenterStep Controller - Failed to call action on {} {} {}".format(id, action, e)) - - # todo: Sensors may need to be removed when saving the recipe -> need to be replaced when assinging later to Fermenter with 'fermenter.sensor' + async def savetobook(self, fermenterid): name = shortuuid.uuid() path = os.path.join(".", 'config', "fermenterrecipes", "{}.yaml".format(name)) @@ -591,7 +534,7 @@ class FermentationController: try: brewname = fermenter.brewname description = fermenter.description - # todo add escription at later point of time, once description has been added to fermenter dataclass + except: brewname = "" description = "" @@ -605,20 +548,38 @@ class FermentationController: with open(path, "w") as file: yaml.dump(data, file) - async def load_recipe(self, data, fermenterid): + async def load_recipe(self, data, fermenterid, name): try: await self.shutdown(None, fermenterid) except: pass fermenter = self._find_by_id(fermenterid) + def add_runtime_data(item): item["status"] = "I" + item["endtime"] = 0 item["id"] = shortuuid.uuid() item["props"]["Sensor"] = fermenter.sensor + list(map(lambda item: add_runtime_data(item), data.get("steps"))) fermenter.description = data['basic']['desc'] - fermenter.brewname = data['basic']['name'] - fermenter.steps=[] + if name is not None: + fermenter.brewname = name + else: + fermenter.brewname = data['basic']['name'] await self.update(fermenter) + fermenter.steps=[] for item in data.get("steps"): - await self.create_step(fermenterid, item) + fermenter.steps.append(self.create_step(fermenterid, item)) + + self.save() + self.push_update("fermenterstepupdate") + + async def add_step(self, fermenterid, newstep): + fermenter = self._find_by_id(fermenterid) + step = self.create_step(fermenterid, newstep) + fermenter.steps.append(step) + self.save() + self.push_update("fermenterstepupdate") + return step + \ No newline at end of file diff --git a/cbpi/controller/fermenter_recipe_controller.py b/cbpi/controller/fermenter_recipe_controller.py index e0065c3..d0de8b5 100644 --- a/cbpi/controller/fermenter_recipe_controller.py +++ b/cbpi/controller/fermenter_recipe_controller.py @@ -69,13 +69,13 @@ class FermenterRecipeController: os.remove(path) - async def brew(self, name, fermenterid): + async def brew(self, recipeid, fermenterid, name): - recipe_path = os.path.join(".", 'config', "fermenterrecipes", "%s.yaml" % name) + recipe_path = os.path.join(".", 'config', "fermenterrecipes", "%s.yaml" % recipeid) logging.info(recipe_path) with open(recipe_path) as file: data = yaml.load(file, Loader=yaml.FullLoader) - await self.cbpi.fermenter.load_recipe(data, fermenterid) + await self.cbpi.fermenter.load_recipe(data, fermenterid, name) async def clone(self, id, new_name): recipe_path = os.path.join(".", 'config', "fermenterrecipes", "%s.yaml" % id) diff --git a/cbpi/controller/step_controller.py b/cbpi/controller/step_controller.py index c4c2fe8..8f9294e 100644 --- a/cbpi/controller/step_controller.py +++ b/cbpi/controller/step_controller.py @@ -20,7 +20,7 @@ class StepController: self.cbpi = cbpi self.logger = logging.getLogger(__name__) self.path = os.path.join(".", 'config', "step_data.json") - self._loop = asyncio.get_event_loop() + #self._loop = asyncio.get_event_loop() self.basic_data = {} self.step = None self.types = {} @@ -68,8 +68,9 @@ class StepController: self.profile = list(map(lambda item: self.create(item), self.profile)) if startActive is True: active_step = self.find_by_status("A") - if active_step is not None: - self._loop.create_task(self.start_step(active_step)) + if active_step is not None: + asyncio.get_event_loop().create_task(self.start_step(active_step)) + #self._loop.create_task(self.start_step(active_step)) async def add(self, item: Step): logging.debug("Add step") diff --git a/cbpi/controller/system_controller.py b/cbpi/controller/system_controller.py index 33bf050..59a6eae 100644 --- a/cbpi/controller/system_controller.py +++ b/cbpi/controller/system_controller.py @@ -178,6 +178,8 @@ class SystemController: mempercent = 0 eth0IP = "N/A" wlan0IP = "N/A" + eth0speed = "N/A" + wlan0speed = "N/A" TEMP_UNIT=self.cbpi.config.get("TEMP_UNIT", "C") FAHRENHEIT = False if TEMP_UNIT == "C" else True @@ -225,12 +227,31 @@ class SystemController: if str(addr.family) == "AddressFamily.AF_INET": if addr.address: wlan0IP = addr.address + info = psutil.net_if_stats() + try: + for nic in info: + if nic == 'eth0': + if info[nic].isup == True: + if info[nic].speed: + eth0speed = info[nic].speed + else: + eth0speed = "down" + if nic == 'wlan0': + if info[nic].isup == True: + ratestring = os.popen('iwlist wlan0 rate | grep Rate').read() + start = ratestring.find("=") + 1 + end = ratestring.find(" Mb/s") + wlan0speed = ratestring[start:end] + else: + wlan0speed = "down" + except Exception as e: + logging.info(e) except: pass if system == "Windows": try: - ethernet = psutil.net_if_addrs() + ethernet = psutil.net_if_addrs() for nic, addrs in ethernet.items(): if nic == "Ethernet": for addr in addrs: @@ -242,6 +263,23 @@ class SystemController: if str(addr.family) == "AddressFamily.AF_INET": if addr.address: wlan0IP = addr.address + info = psutil.net_if_stats() + try: + for nic in info: + if nic == 'Ethernet': + if info[nic].isup == True: + if info[nic].speed: + eth0speed = info[nic].speed + else: + eth0speed = "down" + if nic == 'WLAN': + if info[nic].isup == True: + if info[nic].speed: + wlan0speed = info[nic].speed + else: + wlan0speed = "down" + except Exception as e: + logging.info(e) except: pass @@ -258,7 +296,9 @@ class SystemController: 'temp': temp, 'temp_unit': TEMP_UNIT, 'eth0': eth0IP, - 'wlan0': wlan0IP} + 'wlan0': wlan0IP, + 'eth0speed': eth0speed, + 'wlan0speed': wlan0speed} return systeminfo diff --git a/cbpi/craftbeerpi.py b/cbpi/craftbeerpi.py index 41ad6b3..aa79701 100644 --- a/cbpi/craftbeerpi.py +++ b/cbpi/craftbeerpi.py @@ -1,5 +1,10 @@ import asyncio +import sys +try: + from asyncio import set_event_loop_policy, WindowsSelectorEventLoopPolicy +except ImportError: + pass import json from voluptuous.schema_builder import message from cbpi.api.dataclasses import NotificationType @@ -82,6 +87,11 @@ async def error_middleware(request, handler): class CraftBeerPi: def __init__(self): + + operationsystem= sys.platform + if operationsystem.startswith('win'): + set_event_loop_policy(WindowsSelectorEventLoopPolicy()) + self.path = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-1]) # The path to the package dir self.version = __version__ diff --git a/cbpi/extension/FermentationStep/__init__.py b/cbpi/extension/FermentationStep/__init__.py index f7bf317..7ebfbc2 100644 --- a/cbpi/extension/FermentationStep/__init__.py +++ b/cbpi/extension/FermentationStep/__init__.py @@ -32,8 +32,9 @@ class FermenterNotificationStep(CBPiFermentationStep): if self.AutoNext == True: self.cbpi.notify(self.name, self.props.get("Notification",""), NotificationType.INFO) - await self.next(self.fermenter.id) - return StepResult.DONE + if self.shutdown != True: + await self.next(self.fermenter.id) + return StepResult.DONE else: self.cbpi.notify(self.name, self.props.get("Notification",""), NotificationType.INFO, action=[NotificationAction("Next Step", self.NextStep)]) await self.push_update() @@ -42,6 +43,7 @@ class FermenterNotificationStep(CBPiFermentationStep): await self.push_update() async def on_start(self): + self.shutdown = False self.summary="" self.AutoNext = False if self.props.get("AutoNext", "No") == "No" else True if self.timer is None: @@ -69,13 +71,12 @@ class FermenterNotificationStep(CBPiFermentationStep): class FermenterTargetTempStep(CBPiFermentationStep): async def NextStep(self, **kwargs): - await self.next(self.fermenter.id) - return StepResult.DONE + if self.shutdown != True: + await self.next(self.fermenter.id) + return StepResult.DONE - async def on_timer_done(self,timer): self.summary = "" - #self.fermenter.target_temp = 0 await self.push_update() if self.AutoMode == True: await self.setAutoMode(False) @@ -88,10 +89,10 @@ class FermenterTargetTempStep(CBPiFermentationStep): await self.push_update() async def on_start(self): + self.shutdown = False self.AutoMode = True if self.props.get("AutoMode","No") == "Yes" else False - self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value") if self.fermenter is not None: - self.fermenter.target_temp = int(self.props.get("Temp", 0)) + self.fermenter.target_temp = float(self.props.get("Temp", 0)) if self.AutoMode == True: await self.setAutoMode(True) self.summary = "Waiting for Target Temp" @@ -107,6 +108,9 @@ class FermenterTargetTempStep(CBPiFermentationStep): await self.push_update() async def run(self): + while self.get_sensor_value(self.props.get("Sensor", None)).get("value") > 900: + await asyncio.sleep(1) + self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value") if self.fermenter.target_temp >= self.starttemp: logging.info("warmup") while self.running == True: @@ -128,6 +132,7 @@ class FermenterTargetTempStep(CBPiFermentationStep): async def reset(self): self.timer = Timer(1 ,on_update=self.on_timer_update, on_done=self.on_timer_done) + self.timer.is_running == False async def setAutoMode(self, auto_state): try: @@ -162,13 +167,15 @@ class FermenterStep(CBPiFermentationStep): else: self.cbpi.notify(self.name, 'Timer is already running', NotificationType.WARNING) - #@action("Add 5 Minutes to Timer", []) - #async def add_timer(self): - # if self.timer.is_running == True: - # self.cbpi.notify(self.name, '5 Minutes added', NotificationType.INFO) - # await self.timer.add(300) - # else: - # self.cbpi.notify(self.name, 'Timer must be running to add time', NotificationType.WARNING) +# @action("Add 1 Day to Timer", []) +# async def add_timer(self): +# if self.timer.is_running == True: +# self.cbpi.notify(self.name, '1 Day added', NotificationType.INFO) +# await self.timer.add(86400) +# self.endtime = self.endtime +86400 +# await self.update_endtime() +# else: +# self.cbpi.notify(self.name, 'Timer must be running to add time', NotificationType.WARNING) async def on_timer_done(self,timer): @@ -176,8 +183,9 @@ class FermenterStep(CBPiFermentationStep): if self.AutoMode == True: await self.setAutoMode(False) self.cbpi.notify(self.name, 'Step finished', NotificationType.SUCCESS) - await self.next(self.fermenter.id) - return StepResult.DONE + if self.shutdown != True: + await self.next(self.fermenter.id) + return StepResult.DONE async def on_timer_update(self,timer, seconds): @@ -185,7 +193,8 @@ class FermenterStep(CBPiFermentationStep): await self.push_update() async def on_start(self): - if self.endtime == 0: + self.shutdown = False + if self.endtime == 0: timeD=int(self.props.get("TimerD", 0)) timeH=int(self.props.get("TimerH", 0)) timeM=int(self.props.get("TimerM", 0)) @@ -194,9 +203,8 @@ class FermenterStep(CBPiFermentationStep): self.fermentationtime = self.endtime - time.time() self.AutoMode = True if self.props.get("AutoMode", "No") == "Yes" else False - self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value") if self.fermenter is not None: - self.fermenter.target_temp = int(self.props.get("Temp", 0)) + self.fermenter.target_temp = float(self.props.get("Temp", 0)) if self.AutoMode == True: await self.setAutoMode(True) await self.push_update() @@ -217,6 +225,9 @@ class FermenterStep(CBPiFermentationStep): if self.endtime != 0 and self.timer is not None and self.timer.is_running == False: self.timer.start() self.timer.is_running = True + estimated_completion_time = datetime.fromtimestamp(time.time()+ self.fermentationtime) + self.cbpi.notify(self.name, 'Timer restarted. Estimated completion: {}'.format(estimated_completion_time.strftime("%d.%m, %H:%M")), NotificationType.INFO) + self.summary = "Waiting for Target Temp" await self.push_update() @@ -229,17 +240,19 @@ class FermenterStep(CBPiFermentationStep): await self.push_update() async def reset(self): - await self.timer.stop() timeD=int(self.props.get("TimerD", 0)) timeH=int(self.props.get("TimerH", 0)) timeM=int(self.props.get("TimerM", 0)) self.fermentationtime=(timeM+(60*timeH)+(1440*timeD)) *60 - self.timer = Timer(self.fermentationtime ,on_update=self.on_timer_update, on_done=self.on_timer_done) self.endtime = 0 - await self.update_endtime() + self.timer.is_running == False async def run(self): + while self.get_sensor_value(self.props.get("Sensor", None)).get("value") > 900: + await asyncio.sleep(1) + self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value") + if self.fermenter.target_temp >= self.starttemp: logging.info("warmup") while self.running == True: @@ -278,43 +291,6 @@ class FermenterStep(CBPiFermentationStep): except Exception as e: logging.error("Failed to switch on FermenterLogic {} {}".format(self.fermenter.id, e)) -@parameters([Property.Number(label="TimerD", description="Timer Days", configurable=True), - Property.Number(label="TimerH", description="Timer Hours", configurable=True), - Property.Number(label="TimerM", description="Timer Minutes", configurable=True) - ]) -class FermenterWaitStep(CBPiFermentationStep): - - async def on_timer_done(self, timer): - self.summary = "" - await self.next(self.fermenter.id) - return StepResult.DONE - - async def on_timer_update(self, timer, seconds): - self.summary = Timer.format_time(seconds) - await self.push_update() - - async def on_start(self): - timeD=int(self.props.get("TimerD", 0)) - timeH=int(self.props.get("TimerH", 0)) - timeM=int(self.props.get("TimerM", 0)) - self.fermentationtime=(timeM+(60*timeH)+(1440*timeD)) *60 - - if self.timer is None: - self.timer = Timer(self.fermentationtime, on_update=self.on_timer_update, on_done=self.on_timer_done) - self.timer.start() - - async def on_stop(self): - await self.timer.stop() - self.summary = "" - await self.push_update() - - async def reset(self): - self.timer = Timer(self.fermentationtime, on_update=self.on_timer_update, on_done=self.on_timer_done) - - async def run(self): - while self.running == True: - await asyncio.sleep(1) - return StepResult.DONE def setup(cbpi): ''' @@ -328,4 +304,3 @@ def setup(cbpi): cbpi.plugin.register("FermenterNotificationStep", FermenterNotificationStep) cbpi.plugin.register("FermenterTargetTempStep", FermenterTargetTempStep) cbpi.plugin.register("FermenterStep", FermenterStep) - #cbpi.plugin.register("FermenterWaitStep", FermenterWaitStep) \ No newline at end of file diff --git a/cbpi/extension/FermenterHysteresis/__init__.py b/cbpi/extension/FermenterHysteresis/__init__.py index b678edd..5be707c 100644 --- a/cbpi/extension/FermenterHysteresis/__init__.py +++ b/cbpi/extension/FermenterHysteresis/__init__.py @@ -33,7 +33,7 @@ class FermenterAutostart(CBPiExtension): try: if (self.fermenter.instance is None or self.fermenter.instance.state == False): await self.cbpi.fermenter.start(self.fermenter.id) - logging.info("Successfully switched on Fermenterlogic for Fermenter {}".format(self.fermenter.id)) + logging.info("Successfully switched on Ferenterlogic for Fermenter {}".format(self.fermenter.id)) except Exception as e: logging.error("Failed to switch on FermenterLogic {} {}".format(self.fermenter.id, e)) except: diff --git a/cbpi/extension/gpioactor/__init__.py b/cbpi/extension/gpioactor/__init__.py index ebed2ff..93141e9 100644 --- a/cbpi/extension/gpioactor/__init__.py +++ b/cbpi/extension/gpioactor/__init__.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) try: import RPi.GPIO as GPIO except Exception: - logger.warning("Failed to load RPi.GPIO. Using Mock") + logger.warning("Failed to load RPi.GPIO. Using Mock instead") MockRPi = MagicMock() modules = { "RPi": MockRPi, diff --git a/cbpi/extension/mqtt_actor/mqtt_actor.py b/cbpi/extension/mqtt_actor/mqtt_actor.py index 5788c12..28dd198 100644 --- a/cbpi/extension/mqtt_actor/mqtt_actor.py +++ b/cbpi/extension/mqtt_actor/mqtt_actor.py @@ -22,6 +22,8 @@ class MQTTActor(CBPiActor): async def on_start(self): self.topic = self.props.get("Topic", None) self.power = 100 + await self.off() + self.state = False async def on(self, power=None): if power is not None: diff --git a/cbpi/extension/mqtt_sensor/__init__.py b/cbpi/extension/mqtt_sensor/__init__.py index 4564416..e2d6e48 100644 --- a/cbpi/extension/mqtt_sensor/__init__.py +++ b/cbpi/extension/mqtt_sensor/__init__.py @@ -18,7 +18,7 @@ class MQTTSensor(CBPiSensor): if self.payload_text != None: self.payload_text = self.payload_text.split('.') self.mqtt_task = self.cbpi.satellite.subcribe(self.Topic, self.on_message) - self.value: int = 0 + self.value: float = 999 async def on_message(self, message): val = json.loads(message) diff --git a/cbpi/http_endpoints/http_fermentation.py b/cbpi/http_endpoints/http_fermentation.py index 1eec644..81c4d89 100644 --- a/cbpi/http_endpoints/http_fermentation.py +++ b/cbpi/http_endpoints/http_fermentation.py @@ -313,8 +313,8 @@ class FermentationHttpEndpoints(): data = await request.json() fermenterid= request.match_info['id'] - newstep = {"name": data.get("name"), "props": data.get("props", {}), "type": data.get("type")} - response_data = await self.controller.create_step(fermenterid,newstep) + newstep = {"name": data.get("name"), "props": data.get("props", {}), "endtime": 0, "type": data.get("type")} + response_data = await self.controller.add_step(fermenterid,newstep) return web.json_response(data=response_data.to_dict()) @request_mapping(path="/{fermenterid}/{stepid}", method="PUT", auth_required=False) @@ -352,7 +352,7 @@ class FermentationHttpEndpoints(): data = await request.json() stepid = request.match_info['stepid'] fermenterid = request.match_info['fermenterid'] - updatedstep = {"id": stepid, "name": data.get("name"), "props": data.get("props", {}), "type": data.get("type")} + updatedstep = {"id": stepid, "name": data.get("name"), "endtime": 0, "props": data.get("props", {}), "type": data.get("type")} #step = FermenterStep(stepid, data.get("name"), None, Props(data.get("props", {})), data.get("type")) await self.controller.update_step(fermenterid,updatedstep) return web.Response(status=200) diff --git a/cbpi/http_endpoints/http_fermenterrecipe.py b/cbpi/http_endpoints/http_fermenterrecipe.py index 76dddd9..e974e3e 100644 --- a/cbpi/http_endpoints/http_fermenterrecipe.py +++ b/cbpi/http_endpoints/http_fermenterrecipe.py @@ -117,7 +117,7 @@ class FermenterRecipeHttpEndpoints(): await self.controller.remove(name) return web.Response(status=204) - @request_mapping(path="/{name}/{fermenterid}/brew", method="POST", auth_required=False) + @request_mapping(path="/{recipeid}/{fermenterid}/{name}/brew", method="POST", auth_required=False) async def http_brew(self, request): """ @@ -137,9 +137,10 @@ class FermenterRecipeHttpEndpoints(): "200": description: successful operation """ + recipeid = request.match_info['recipeid'] name = request.match_info['name'] fermenterid = request.match_info['fermenterid'] - await self.controller.brew(name,fermenterid) + await self.controller.brew(recipeid,fermenterid,name) return web.Response(status=204) @request_mapping(path="/{id}/clone", method="POST", auth_required=False) diff --git a/requirements.txt b/requirements.txt index 428fcac..ca5da1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,24 +1,24 @@ -aiohttp==3.7.4 +aiohttp==3.8.1 aiohttp-auth==0.1.1 aiohttp-route-decorator==0.1.4 aiohttp-security==0.4.0 -aiohttp-session==2.9.0 -aiohttp-swagger==1.0.15 -aiojobs==0.3.0 -aiosqlite==0.16.0 -cryptography==3.3.2 -requests==2.25.1 -voluptuous==0.12.1 +aiohttp-session==2.11.0 +aiohttp-swagger==1.0.16 +aiojobs==1.0.0 +aiosqlite==0.17.0 +cryptography==36.0.1 +requests==2.27.1 +voluptuous==0.12.2 pyfiglet==0.8.post1 -pandas==1.4.0 -shortuuid==1.0.1 -tabulate==0.8.7 -numpy==1.22.0 +pandas==1.4.1 +shortuuid==1.0.8 +tabulate==0.8.9 +numpy==1.22.2 cbpi4ui -click==7.1.2 -importlib_metadata==4.8.2 +click==8.0.4 +importlib_metadata==4.11.1 asyncio-mqtt -psutil==5.8.0 +psutil==5.9.0 zipp>=0.5 PyInquirer==1.0.3 colorama==0.4.4 \ No newline at end of file diff --git a/setup.py b/setup.py index 30b3446..944575f 100644 --- a/setup.py +++ b/setup.py @@ -27,34 +27,33 @@ setup(name='cbpi', '': ['*.txt', '*.rst', '*.yaml'], 'cbpi': ['*','*.txt', '*.rst', '*.yaml']}, - python_requires='>=3', + python_requires='>=3.9', install_requires=[ - "aiohttp==3.7.4", + "aiohttp==3.8.1", "aiohttp-auth==0.1.1", "aiohttp-route-decorator==0.1.4", "aiohttp-security==0.4.0", - "aiohttp-session==2.9.0", - "aiohttp-swagger==1.0.15", - "aiojobs==0.3.0", - "aiosqlite==0.16.0", - "cryptography==3.3.2", - "requests==2.25.1", - "voluptuous==0.12.1", + "aiohttp-session==2.11.0", + "aiohttp-swagger==1.0.16", + "aiojobs==1.0.0 ", + "aiosqlite==0.17.0", + "cryptography==36.0.1", + "requests==2.27.1", + "voluptuous==0.12.2", "pyfiglet==0.8.post1", - 'click==7.1.2', - 'shortuuid==1.0.1', - 'tabulate==0.8.7', + 'click==8.0.4', + 'shortuuid==1.0.8', + 'tabulate==0.8.9', 'asyncio-mqtt', - 'psutil==5.8.0', - 'colorama==0.4.4', 'PyInquirer==1.0.3', + 'colorama==0.4.4', + 'psutil==5.9.0', 'cbpi4ui', - 'importlib_metadata'] + ( - ['RPi.GPIO==0.7.1'] if raspberrypi else [] ) + - (['numpy==1.22.0'] if (int(platform.python_version_tuple()[1]) >= 9) and (int(platform.python_version_tuple()[0]) == 3) else ['numpy==1.20.3'] ) + - (['pandas==1.4.0'] if (int(platform.python_version_tuple()[1]) >= 9) and (int(platform.python_version_tuple()[0]) == 3) else ['pandas==1.1.5'] ), - + 'importlib_metadata', + 'numpy==1.22.2', + 'pandas==1.4.1'] + ( + ['RPi.GPIO==0.7.1'] if raspberrypi else [] ), dependency_links=[ 'https://testpypi.python.org/pypi',