From 8a45ca9033d36f3b4e615d9e8d915d18df18cfe3 Mon Sep 17 00:00:00 2001 From: cocothenut Date: Fri, 21 Jul 2017 20:22:37 +0200 Subject: [PATCH 1/9] Add files via upload --- modules/buzzer/__init__.py | 225 ++++++++++++++++++++++++++++--------- 1 file changed, 175 insertions(+), 50 deletions(-) diff --git a/modules/buzzer/__init__.py b/modules/buzzer/__init__.py index 51205875..0db76d5f 100644 --- a/modules/buzzer/__init__.py +++ b/modules/buzzer/__init__.py @@ -1,50 +1,175 @@ -import time -from thread import start_new_thread -from modules import cbpi - -try: - import RPi.GPIO as GPIO -except Exception as e: - pass - -class Buzzer(object): - - sound = ["H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L"] - def __init__(self, gpio): - try: - cbpi.app.logger.info("INIT BUZZER NOW GPIO%s" % gpio) - self.gpio = int(gpio) - GPIO.setmode(GPIO.BCM) - GPIO.setup(self.gpio, GPIO.OUT) - self.state = True - cbpi.app.logger.info("BUZZER SETUP OK") - except Exception as e: - cbpi.app.logger.info("BUZZER EXCEPTION %s" % str(e)) - self.state = False - - def beep(self): - if self.state is False: - cbpi.app.logger.error("BUZZER not working") - return - - def play(sound): - try: - for i in sound: - if (isinstance(i, str)): - if i == "H": - GPIO.output(int(self.gpio), GPIO.HIGH) - else: - GPIO.output(int(self.gpio), GPIO.LOW) - else: - time.sleep(i) - except Exception as e: - pass - - start_new_thread(play, (self.sound,)) - -@cbpi.initalizer(order=1) -def init(cbpi): - gpio = cbpi.get_config_parameter("buzzer", 16) - cbpi.buzzer = Buzzer(gpio) - cbpi.beep() - cbpi.app.logger.info("INIT OK") +import time +from thread import start_new_thread +from modules import cbpi + +try: + import RPi.GPIO as GPIO +except Exception as e: + pass + +class Buzzer(object): + +# custom beep sounds + + sound = ["H", 0.1, "L"] + melodie1 = ["H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L"] + melodie2 = ["H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L"] + melodie3 = ["H", 0.4, "L", 0.1, "H", 0.4, "L", 0.1, "H", 0.4, "L"] + melodie4 = ["H", 0.4, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.4, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.4, "L"] + melodie5 = ["H", 0.6, "L", 0.3, "H", 0.6, "L", 0.3, "H", 0.6, "L"] + melodie6 = ["H", 0.2, "L", 0.4, "H", 0.2, "L", 0.3, "H", 0.2, "L", 0.2, "H", 0.2, "L", 0.1, "H", 0.2, "L", 0.1, "H", 0.2, "L"] + def __init__(self, gpio): + try: + cbpi.app.logger.info("INIT BUZZER NOW GPIO%s" % gpio) + self.gpio = int(gpio) + GPIO.setmode(GPIO.BCM) + GPIO.setup(self.gpio, GPIO.OUT) + self.state = True + cbpi.app.logger.info("BUZZER SETUP OK") + except Exception as e: + cbpi.app.logger.info("BUZZER EXCEPTION %s" % str(e)) + self.state = False + + + + + + + def beep(self): # beeps once when you boot up your Pi with CBPi -- beeps at Brewing finished + if self.state is False: + cbpi.app.logger.error("BUZZER not working") + return + + def play(sound): + try: + for i in sound: + if (isinstance(i, str)): + if i == "H": + GPIO.output(int(self.gpio), GPIO.HIGH) + else: + GPIO.output(int(self.gpio), GPIO.LOW) + else: + time.sleep(i) + except Exception as e: + pass + + start_new_thread(play, (self.melodie2,)) + + + def MashStepEndBeep(self): # beeps at end of step + if self.state is False: + cbpi.app.logger.error("BUZZER not working") + return + + def play(sound): + try: + for i in sound: + if (isinstance(i, str)): + if i == "H": + GPIO.output(int(self.gpio), GPIO.HIGH) + else: + GPIO.output(int(self.gpio), GPIO.LOW) + else: + time.sleep(i) + except Exception as e: + pass + + start_new_thread(play, (self.melodie1,)) + + + + def MashInStepEndBeep(self): # beeps at end of step + if self.state is False: + cbpi.app.logger.error("BUZZER not working") + return + + def play(sound): + try: + for i in sound: + if (isinstance(i, str)): + if i == "H": + GPIO.output(int(self.gpio), GPIO.HIGH) + else: + GPIO.output(int(self.gpio), GPIO.LOW) + else: + time.sleep(i) + except Exception as e: + pass + + start_new_thread(play, (self.melodie3,)) + + + def ChilStepEndBeep(self): # beeps at end of step + if self.state is False: + cbpi.app.logger.error("BUZZER not working") + return + + def play(sound): + try: + for i in sound: + if (isinstance(i, str)): + if i == "H": + GPIO.output(int(self.gpio), GPIO.HIGH) + else: + GPIO.output(int(self.gpio), GPIO.LOW) + else: + time.sleep(i) + except Exception as e: + pass + + start_new_thread(play, (self.melodie4,)) + + + def PumpStepEndBeep(self): # beeps at end of step + if self.state is False: + cbpi.app.logger.error("BUZZER not working") + return + + def play(sound): + try: + for i in sound: + if (isinstance(i, str)): + if i == "H": + GPIO.output(int(self.gpio), GPIO.HIGH) + else: + GPIO.output(int(self.gpio), GPIO.LOW) + else: + time.sleep(i) + except Exception as e: + pass + + start_new_thread(play, (self.melodie5,)) + + + def BoilStepEndBeep(self): # beeps at end of step + if self.state is False: + cbpi.app.logger.error("BUZZER not working") + return + + def play(sound): + try: + for i in sound: + if (isinstance(i, str)): + if i == "H": + GPIO.output(int(self.gpio), GPIO.HIGH) + else: + GPIO.output(int(self.gpio), GPIO.LOW) + else: + time.sleep(i) + except Exception as e: + pass + + start_new_thread(play, (self.melodie6,)) + + +@cbpi.initalizer(order=1) +def init(cbpi): + gpio = cbpi.get_config_parameter("buzzer", 16) + cbpi.buzzer = Buzzer(gpio) + cbpi.beep() + cbpi.MashStepEndBeep() + cbpi.MashInStepEndBeep() + cbpi.ChilStepEndBeep() + cbpi.PumpStepEndBeep() + cbpi.BoilStepEndBeep() + cbpi.app.logger.info("INIT OK") From 6b7a28df820dfba82f0ea35807d552c569a3c38a Mon Sep 17 00:00:00 2001 From: cocothenut Date: Fri, 21 Jul 2017 20:23:10 +0200 Subject: [PATCH 2/9] Add files via upload --- modules/base_plugins/brew_steps/__init__.py | 450 ++++++++++---------- 1 file changed, 229 insertions(+), 221 deletions(-) diff --git a/modules/base_plugins/brew_steps/__init__.py b/modules/base_plugins/brew_steps/__init__.py index 177ff46f..c3dbd9f3 100644 --- a/modules/base_plugins/brew_steps/__init__.py +++ b/modules/base_plugins/brew_steps/__init__.py @@ -1,221 +1,229 @@ -# -*- coding: utf-8 -*- -import time - - -from modules.core.props import Property, StepProperty -from modules.core.step import StepBase -from modules import cbpi - - - -@cbpi.step -class MashStep(StepBase): - ''' - Just put the decorator @cbpi.step on top of a method - ''' - # Properties - temp = Property.Number("Temperature", configurable=True, description="Target Temperature of Mash Step") - kettle = StepProperty.Kettle("Kettle", description="Kettle in which the mashing takes place") - timer = Property.Number("Timer in Minutes", configurable=True, description="Timer is started when the target temperature is reached") - - def init(self): - ''' - Initialize Step. This method is called once at the beginning of the step - :return: - ''' - # set target tep - self.set_target_temp(self.temp, self.kettle) - - @cbpi.action("Start Timer Now") - def start(self): - ''' - Custom Action which can be execute form the brewing dashboard. - All method with decorator @cbpi.action("YOUR CUSTOM NAME") will be available in the user interface - :return: - ''' - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - - def reset(self): - self.stop_timer() - self.set_target_temp(self.temp, self.kettle) - - def finish(self): - self.set_target_temp(0, self.kettle) - - def execute(self): - ''' - This method is execute in an interval - :return: - ''' - - # Check if Target Temp is reached - if self.get_kettle_temp(self.kettle) >= float(self.temp): - # Check if Timer is Running - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - - # Check if timer finished and go to next step - if self.is_timer_finished() == True: - self.next() - - -@cbpi.step -class MashInStep(StepBase): - ''' - Just put the decorator @cbpi.step on top of a method - ''' - # Properties - temp = Property.Number("Temperature", configurable=True, description="Target Temperature of Mash Step") - kettle = StepProperty.Kettle("Kettle", description="Kettle in which the mashing takes place") - s = False - - @cbpi.action("Change Power") - def change_power(self): - self.actor_power(1, 50) - - def init(self): - ''' - Initialize Step. This method is called once at the beginning of the step - :return: - ''' - # set target tep - self.s = False - self.set_target_temp(self.temp, self.kettle) - - - - def execute(self): - ''' - This method is execute in an interval - :return: - ''' - - # Check if Target Temp is reached - if self.get_kettle_temp(self.kettle) >= float(self.temp) and self.s is False: - self.s = True - self.notify("Step Temp Reached!", "Please press the next button to continue", timeout=None) - - - -@cbpi.step -class ChilStep(StepBase): - - timer = Property.Number("Timer in Minutes", configurable=True, default_value=0, description="Timer is started immediately") - - @cbpi.action("Stat Timer") - def start(self): - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - - def reset(self): - self.stop_timer() - - - def finish(self): - pass - - def execute(self): - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - - if self.is_timer_finished() == True: - self.next() - -@cbpi.step -class PumpStep(StepBase): - - pump = StepProperty.Actor("Pump", description="Pump actor gets toogled") - timer = Property.Number("Timer in Minutes", configurable=True, default_value=0, description="Timer is started immediately") - - @cbpi.action("Stat Timer") - def start(self): - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - - def reset(self): - self.stop_timer() - - - def finish(self): - self.actor_off(int(self.pump)) - - def init(self): - self.actor_on(int(self.pump)) - - def execute(self): - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - - if self.is_timer_finished() == True: - self.next() - -@cbpi.step -class BoilStep(StepBase): - ''' - Just put the decorator @cbpi.step on top of a method - ''' - # Properties - temp = Property.Number("Temperature", configurable=True, default_value=100, description="Target temperature for boiling") - kettle = StepProperty.Kettle("Kettle", description="Kettle in which the boiling step takes place") - timer = Property.Number("Timer in Minutes", configurable=True, default_value=90, description="Timer is started when target temperature is reached") - hop_1 = Property.Number("Hop 1 Addition", configurable=True, description="Fist Hop alert") - hop_1_added = Property.Number("",default_value=None) - hop_2 = Property.Number("Hop 2 Addition", configurable=True, description="Second Hop alert") - hop_2_added = Property.Number("", default_value=None) - hop_3 = Property.Number("Hop 3 Addition", configurable=True) - hop_3_added = Property.Number("", default_value=None, description="Second Hop alert") - - def init(self): - ''' - Initialize Step. This method is called once at the beginning of the step - :return: - ''' - # set target tep - self.set_target_temp(self.temp, self.kettle) - - - - - @cbpi.action("Start Timer Now") - def start(self): - ''' - Custom Action which can be execute form the brewing dashboard. - All method with decorator @cbpi.action("YOUR CUSTOM NAME") will be available in the user interface - :return: - ''' - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - - def reset(self): - self.stop_timer() - self.set_target_temp(self.temp, self.kettle) - - def finish(self): - self.set_target_temp(0, self.kettle) - - - def check_hop_timer(self, number, value): - - if self.__getattribute__("hop_%s_added" % number) is not True and time.time() > ( - self.timer_end - (int(self.timer) * 60 - int(value) * 60)): - self.__setattr__("hop_%s_added" % number, True) - self.notify("Hop Alert", "Please add Hop %s" % number, timeout=None) - - def execute(self): - ''' - This method is execute in an interval - :return: - ''' - # Check if Target Temp is reached - if self.get_kettle_temp(self.kettle) >= float(self.temp): - # Check if Timer is Running - if self.is_timer_finished() is None: - self.start_timer(int(self.timer) * 60) - else: - self.check_hop_timer(1, self.hop_1) - self.check_hop_timer(2, self.hop_2) - self.check_hop_timer(3, self.hop_3) - # Check if timer finished and go to next step - if self.is_timer_finished() == True: - self.next() +# -*- coding: utf-8 -*- +import time + + +from modules.core.props import Property, StepProperty +from modules.core.step import StepBase +from modules import cbpi + + +@cbpi.step +class MashStep(StepBase): + ''' + Just put the decorator @cbpi.step on top of a method + ''' + # Properties + temp = Property.Number("Temperature", configurable=True, description="Target Temperature of Mash Step") + kettle = StepProperty.Kettle("Kettle", description="Kettle in which the mashing takes place") + timer = Property.Number("Timer in Minutes", configurable=True, description="Timer is started when the target temperature is reached") + + def init(self): + ''' + Initialize Step. This method is called once at the beginning of the step + :return: + ''' + # set target tep + self.set_target_temp(self.temp, self.kettle) + + @cbpi.action("Start Timer Now") + def start(self): + ''' + Custom Action which can be execute form the brewing dashboard. + All method with decorator @cbpi.action("YOUR CUSTOM NAME") will be available in the user interface + :return: + ''' + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + + def reset(self): + self.stop_timer() + self.set_target_temp(self.temp, self.kettle) + + def finish(self): + self.set_target_temp(0, self.kettle) + + def execute(self): + ''' + This method is execute in an interval + :return: + ''' + + # Check if Target Temp is reached + if self.get_kettle_temp(self.kettle) >= float(self.temp): + # Check if Timer is Running + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + + # Check if timer finished and go to next step + if self.is_timer_finished() == True: + # if you dont want a beep sound comment out like : # cbpi.MashStepEndBeep() + cbpi.MashStepEndBeep() + self.next() + + +@cbpi.step +class MashInStep(StepBase): + ''' + Just put the decorator @cbpi.step on top of a method + ''' + # Properties + temp = Property.Number("Temperature", configurable=True, description="Target Temperature of Mash Step") + kettle = StepProperty.Kettle("Kettle", description="Kettle in which the mashing takes place") + s = False + + @cbpi.action("Change Power") + def change_power(self): + self.actor_power(1, 50) + + def init(self): + ''' + Initialize Step. This method is called once at the beginning of the step + :return: + ''' + # set target tep + self.s = False + self.set_target_temp(self.temp, self.kettle) + + + + def execute(self): + ''' + This method is execute in an interval + :return: + ''' + + # Check if Target Temp is reached + if self.get_kettle_temp(self.kettle) >= float(self.temp) and self.s is False: + self.s = True + self.notify("Step Temp Reached!", "Please press the next button to continue", timeout=None) + # if you dont want a beep sound comment out like : # cbpi.MashInStepEndBeep() + cbpi.MashInStepEndBeep() + + +@cbpi.step +class ChilStep(StepBase): + + timer = Property.Number("Timer in Minutes", configurable=True, default_value=0, description="Timer is started immediately") + + @cbpi.action("Stat Timer") + def start(self): + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + + def reset(self): + self.stop_timer() + + + def finish(self): + pass + + def execute(self): + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + + if self.is_timer_finished() == True: + # if you dont want a beep sound comment out like : # cbpi.ChilStepEndBeep() + cbpi.ChilStepEndBeep() + self.next() + +@cbpi.step +class PumpStep(StepBase): + + pump = StepProperty.Actor("Pump", description="Pump actor gets toogled") + timer = Property.Number("Timer in Minutes", configurable=True, default_value=0, description="Timer is started immediately") + + @cbpi.action("Stat Timer") + def start(self): + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + + def reset(self): + self.stop_timer() + + + def finish(self): + self.actor_off(int(self.pump)) + + def init(self): + self.actor_on(int(self.pump)) + + def execute(self): + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + + if self.is_timer_finished() == True: + # if you dont want a beep sound comment out like : # cbpi.PumpStepEndBeep() + cbpi.PumpStepEndBeep() + self.next() + +@cbpi.step +class BoilStep(StepBase): + ''' + Just put the decorator @cbpi.step on top of a method + ''' + # Properties + temp = Property.Number("Temperature", configurable=True, default_value=100, description="Target temperature for boiling") + kettle = StepProperty.Kettle("Kettle", description="Kettle in which the boiling step takes place") + timer = Property.Number("Timer in Minutes", configurable=True, default_value=90, description="Timer is started when target temperature is reached") + hop_1 = Property.Number("Hop 1 Addition", configurable=True, description="Fist Hop alert") + hop_1_added = Property.Number("",default_value=None) + hop_2 = Property.Number("Hop 2 Addition", configurable=True, description="Second Hop alert") + hop_2_added = Property.Number("", default_value=None) + hop_3 = Property.Number("Hop 3 Addition", configurable=True) + hop_3_added = Property.Number("", default_value=None, description="Second Hop alert") + + def init(self): + ''' + Initialize Step. This method is called once at the beginning of the step + :return: + ''' + # set target tep + self.set_target_temp(self.temp, self.kettle) + + + + + @cbpi.action("Start Timer Now") + def start(self): + ''' + Custom Action which can be execute form the brewing dashboard. + All method with decorator @cbpi.action("YOUR CUSTOM NAME") will be available in the user interface + :return: + ''' + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + + def reset(self): + self.stop_timer() + self.set_target_temp(self.temp, self.kettle) + + def finish(self): + self.set_target_temp(0, self.kettle) + + + def check_hop_timer(self, number, value): + + if self.__getattribute__("hop_%s_added" % number) is not True and time.time() > ( + self.timer_end - (int(self.timer) * 60 - int(value) * 60)): + self.__setattr__("hop_%s_added" % number, True) + self.notify("Hop Alert", "Please add Hop %s" % number, timeout=None) + + def execute(self): + ''' + This method is execute in an interval + :return: + ''' + # Check if Target Temp is reached + if self.get_kettle_temp(self.kettle) >= float(self.temp): + # Check if Timer is Running + if self.is_timer_finished() is None: + self.start_timer(int(self.timer) * 60) + else: + self.check_hop_timer(1, self.hop_1) + self.check_hop_timer(2, self.hop_2) + self.check_hop_timer(3, self.hop_3) + # Check if timer finished and go to next step + if self.is_timer_finished() == True: + # if you dont want a beep sound comment out like : # cbpi.BoilStepEndBeep() + cbpi.BoilStepEndBeep() + self.next() From 0f979108d08c3cd45b06851fae0639ba3614bd23 Mon Sep 17 00:00:00 2001 From: cocothenut Date: Fri, 21 Jul 2017 20:23:39 +0200 Subject: [PATCH 3/9] Add files via upload --- modules/core/core.py | 1015 ++++++++++++++++++++++-------------------- 1 file changed, 521 insertions(+), 494 deletions(-) diff --git a/modules/core/core.py b/modules/core/core.py index f0634a29..ea316081 100644 --- a/modules/core/core.py +++ b/modules/core/core.py @@ -1,494 +1,521 @@ -import inspect -import pprint - -import sqlite3 -from flask import make_response, g -import datetime -from datetime import datetime -from flask.views import MethodView -from flask_classy import FlaskView, route - -from time import localtime, strftime -from functools import wraps, update_wrapper - - -from props import * - -from hardware import * - -import time -import uuid - - -class NotificationAPI(object): - pass - -class ActorAPI(object): - - def init_actors(self): - self.app.logger.info("Init Actors") - t = self.cache.get("actor_types") - for key, value in t.iteritems(): - value.get("class").api = self - value.get("class").init_global() - - for key in self.cache.get("actors"): - self.init_actor(key) - - def init_actor(self, id): - try: - value = self.cache.get("actors").get(int(id)) - cfg = value.config.copy() - cfg.update(dict(api=self, id=id, name=value.name)) - cfg.update(dict(api=self, id=id, name=value.name)) - clazz = self.cache.get("actor_types").get(value.type).get("class") - value.instance = clazz(**cfg) - value.instance.init() - value.state = 0 - value.power = 100 - except Exception as e: - self.notify("Actor Error", "Failed to setup actor %s. Please check the configuraiton" % value.name, - type="danger", timeout=None) - self.app.logger.error("Initializing of Actor %s failed" % id) - - def switch_actor_on(self, id, power=None): - actor = self.cache.get("actors").get(id) - - if actor.state == 1: - return - - actor.instance.on(power=power) - actor.state = 1 - if power is not None: - - actor.power = power - self.emit("SWITCH_ACTOR", actor) - - def actor_power(self, id, power=100): - actor = self.cache.get("actors").get(id) - actor.instance.set_power(power=power) - actor.power = power - self.emit("SWITCH_ACTOR", actor) - - def switch_actor_off(self, id): - actor = self.cache.get("actors").get(id) - - if actor.state == 0: - return - actor.instance.off() - actor.state = 0 - self.emit("SWITCH_ACTOR", actor) - -class SensorAPI(object): - - def init_sensors(self): - ''' - Initialize all sensors - :return: - ''' - - self.app.logger.info("Init Sensors") - - t = self.cache.get("sensor_types") - for key, value in t.iteritems(): - value.get("class").init_global() - - for key in self.cache.get("sensors"): - self.init_sensor(key) - - def stop_sensor(self, id): - - try: - self.cache.get("sensors").get(id).instance.stop() - except Exception as e: - - self.app.logger.info("Stop Sensor Error") - pass - - - def init_sensor(self, id): - ''' - initialize sensor by id - :param id: - :return: - ''' - - def start_active_sensor(instance): - ''' - start active sensors as background job - :param instance: - :return: - ''' - instance.execute() - - try: - if id in self.cache.get("sensor_instances"): - self.cache.get("sensor_instances").get(id).stop() - value = self.cache.get("sensors").get(id) - - cfg = value.config.copy() - cfg.update(dict(api=self, id=id, name=value.name)) - clazz = self.cache.get("sensor_types").get(value.type).get("class") - value.instance = clazz(**cfg) - value.instance.init() - if isinstance(value.instance, SensorPassive): - # Passive Sensors - value.mode = "P" - else: - # Active Sensors - value.mode = "A" - t = self.socketio.start_background_task(target=start_active_sensor, instance=value.instance) - - except Exception as e: - - self.notify("Sensor Error", "Failed to setup Sensor %s. Please check the configuraiton" % value.name, type="danger", timeout=None) - self.app.logger.error("Initializing of Sensor %s failed" % id) - - def receive_sensor_value(self, id, value): - self.emit("SENSOR_UPDATE", self.cache.get("sensors")[id]) - self.save_to_file(id, value) - - def save_to_file(self, id, value, prefix="sensor"): - filename = "./logs/%s_%s.log" % (prefix, str(id)) - formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime()) - msg = str(formatted_time) + "," +str(value) + "\n" - - with open(filename, "a") as file: - file.write(msg) - - def log_action(self, text): - filename = "./logs/action.log" - formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime()) - with open(filename, "a") as file: - text = text.encode("utf-8") - file.write("%s,%s\n" % (formatted_time, text)) - - def shutdown_sensor(self, id): - self.cache.get("sensors")[id].stop() - - - def get_sensor_value(self, id): - try: - id = int(id) - return float(self.cache.get("sensors")[id].instance.last_value) - except Exception as e: - - return None - -class CacheAPI(object): - - def get_sensor(self, id): - try: - return self.cache["sensors"][id] - except: - return None - - def get_actor(self, id): - try: - return self.cache["actors"][id] - except: - return None - -class CraftBeerPi(ActorAPI, SensorAPI): - - cache = { - "init": {}, - "config": {}, - "actor_types": {}, - "sensor_types": {}, - "sensors": {}, - "sensor_instances": {}, - "init": [], - "background":[], - "step_types": {}, - "controller_types": {}, - "messages": [], - "plugins": {}, - "fermentation_controller_types": {}, - "fermenter_task": {} - } - buzzer = None - eventbus = {} - - - # constructor - def __init__(self, app, socketio): - self.app = app - self.socketio = socketio - - - def emit(self, key, data): - self.socketio.emit(key, data, namespace='/brew') - - def notify(self, headline, message, type="success", timeout=5000): - self.beep() - msg = {"id": str(uuid.uuid1()), "type": type, "headline": headline, "message": message, "timeout": timeout} - self.emit_message(msg) - - def beep(self): - if self.buzzer is not None: - self.buzzer.beep() - - - def add_cache_callback(self, key, method): - method.callback = True - self.cache[key] = method - - def get_config_parameter(self, key, default): - cfg = self.cache.get("config").get(key) - - if cfg is None: - return default - else: - return cfg.value - - def set_config_parameter(self, name, value): - from modules.config import Config - with self.app.app_context(): - update_data = {"name": name, "value": value} - self.cache.get("config")[name].__dict__.update(**update_data) - c = Config.update(**update_data) - self.emit("UPDATE_CONFIG", c) - - - def add_config_parameter(self, name, value, type, description, options=None): - from modules.config import Config - with self.app.app_context(): - c = Config.insert(**{"name":name, "value": value, "type": type, "description": description, "options": options}) - if self.cache.get("config") is not None: - self.cache.get("config")[c.name] = c - - def clear_cache(self, key, is_array=False): - if is_array: - self.cache[key] = [] - else: - self.cache[key] = {} - - # helper method for parsing props - def __parseProps(self, key, cls): - name = cls.__name__ - self.cache[key][name] = {"name": name, "class": cls, "properties": [], "actions": []} - tmpObj = cls() - members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")] - for m in members: - if isinstance(tmpObj.__getattribute__(m), Property.Number): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append( - {"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), Property.Text): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append( - {"name": m, "label": t.label, "type": "text", "configurable": t.configurable, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), Property.Select): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append( - {"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), Property.Actor): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), Property.Sensor): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), Property.Kettle): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description}) - - for name, method in cls.__dict__.iteritems(): - if hasattr(method, "action"): - label = method.__getattribute__("label") - self.cache[key][cls.__name__]["actions"].append({"method": name, "label": label}) - - - return cls - - - def actor(self, cls): - return self.__parseProps("actor_types", cls) - - - - def actor2(self, description="", power=True, **options): - - def decorator(f): - print f() - print f - print options - print description - return f - return decorator - - def sensor(self, cls): - return self.__parseProps("sensor_types", cls) - - def controller(self, cls): - return self.__parseProps("controller_types", cls) - - def fermentation_controller(self, cls): - return self.__parseProps("fermentation_controller_types", cls) - - def get_controller(self, name): - return self.cache["controller_types"].get(name) - - def get_fermentation_controller(self, name): - return self.cache["fermentation_controller_types"].get(name) - - - # Step action - def action(self,label): - def real_decorator(func): - func.action = True - func.label = label - return func - return real_decorator - - # step decorator - def step(self, cls): - - key = "step_types" - name = cls.__name__ - self.cache[key][name] = {"name": name, "class": cls, "properties": [], "actions": []} - - tmpObj = cls() - members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")] - for m in members: - if isinstance(tmpObj.__getattribute__(m), StepProperty.Number): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "default_value": t.default_value, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), StepProperty.Text): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "text", "configurable": t.configurable, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), StepProperty.Select): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), StepProperty.Actor): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), StepProperty.Sensor): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description}) - elif isinstance(tmpObj.__getattribute__(m), StepProperty.Kettle): - t = tmpObj.__getattribute__(m) - self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description}) - - for name, method in cls.__dict__.iteritems(): - if hasattr(method, "action"): - label = method.__getattribute__("label") - self.cache[key][cls.__name__]["actions"].append({"method": name, "label": label}) - - return cls - - - # Event Bus - def event(self, name, async=False): - - def real_decorator(function): - if self.eventbus.get(name) is None: - self.eventbus[name] = [] - self.eventbus[name].append({"function": function, "async": async}) - def wrapper(*args, **kwargs): - return function(*args, **kwargs) - return wrapper - return real_decorator - - def emit_message(self, message): - self.emit_event(name="MESSAGE", message=message) - - def emit_event(self, name, **kwargs): - for i in self.eventbus.get(name, []): - if i["async"] is False: - i["function"](**kwargs) - else: - t = self.socketio.start_background_task(target=i["function"], **kwargs) - - # initializer decorator - def initalizer(self, order=0): - def real_decorator(function): - self.cache["init"].append({"function": function, "order": order}) - def wrapper(*args, **kwargs): - return function(*args, **kwargs) - return wrapper - return real_decorator - - - - def try_catch(self, errorResult="ERROR"): - def real_decorator(function): - def wrapper(*args, **kwargs): - try: - return function(*args, **kwargs) - except: - self.app.logger.error("Exception in function %s. Return default %s" % (function.__name__, errorResult)) - return errorResult - return wrapper - - return real_decorator - - def nocache(self, view): - @wraps(view) - def no_cache(*args, **kwargs): - response = make_response(view(*args, **kwargs)) - response.headers['Last-Modified'] = datetime.now() - response.headers[ - 'Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0' - response.headers['Pragma'] = 'no-cache' - response.headers['Expires'] = '-1' - return response - - return update_wrapper(no_cache, view) - - def init_kettle(self, id): - try: - value = self.cache.get("kettle").get(id) - value["state"] = False - except: - self.notify("Kettle Setup Faild", "Please check %s configuration" % value.name, type="danger", timeout=None) - self.app.logger.error("Initializing of Kettle %s failed" % id) - - - def run_init(self): - ''' - call all initialziers after startup - :return: - ''' - self.app.logger.info("Invoke Init") - self.cache["init"] = sorted(self.cache["init"], key=lambda k: k['order']) - for i in self.cache.get("init"): - self.app.logger.info("INITIALIZER - METHOD %s PAHT %s: " % (i.get("function").__name__, str(inspect.getmodule(i.get("function")).__file__) )) - i.get("function")(self) - - - - def backgroundtask(self, key, interval, config_parameter=None): - - ''' - Background Task Decorator - :param key: - :param interval: - :param config_parameter: - :return: - ''' - def real_decorator(function): - self.cache["background"].append({"function": function, "key": key, "interval": interval, "config_parameter": config_parameter}) - def wrapper(*args, **kwargs): - return function(*args, **kwargs) - return wrapper - return real_decorator - - def run_background_processes(self): - ''' - call all background task after startup - :return: - ''' - self.app.logger.info("Start Background") - - def job(interval, method): - while True: - try: - method(self) - except Exception as e: - self.app.logger.error("Exception" + method.__name__ + ": " + str(e)) - self.socketio.sleep(interval) - - - for value in self.cache.get("background"): - t = self.socketio.start_background_task(target=job, interval=value.get("interval"), method=value.get("function")) +import inspect +import pprint + +import sqlite3 +from flask import make_response, g +import datetime +from datetime import datetime +from flask.views import MethodView +from flask_classy import FlaskView, route + +from time import localtime, strftime +from functools import wraps, update_wrapper + + +from props import * + +from hardware import * + +import time +import uuid + + +class NotificationAPI(object): + pass + +class ActorAPI(object): + + def init_actors(self): + self.app.logger.info("Init Actors") + t = self.cache.get("actor_types") + for key, value in t.iteritems(): + value.get("class").api = self + value.get("class").init_global() + + for key in self.cache.get("actors"): + self.init_actor(key) + + def init_actor(self, id): + try: + value = self.cache.get("actors").get(int(id)) + cfg = value.config.copy() + cfg.update(dict(api=self, id=id, name=value.name)) + cfg.update(dict(api=self, id=id, name=value.name)) + clazz = self.cache.get("actor_types").get(value.type).get("class") + value.instance = clazz(**cfg) + value.instance.init() + value.state = 0 + value.power = 100 + except Exception as e: + self.notify("Actor Error", "Failed to setup actor %s. Please check the configuraiton" % value.name, + type="danger", timeout=None) + self.app.logger.error("Initializing of Actor %s failed" % id) + + def switch_actor_on(self, id, power=None): + actor = self.cache.get("actors").get(id) + + if actor.state == 1: + return + + actor.instance.on(power=power) + actor.state = 1 + if power is not None: + + actor.power = power + self.emit("SWITCH_ACTOR", actor) + + def actor_power(self, id, power=100): + actor = self.cache.get("actors").get(id) + actor.instance.set_power(power=power) + actor.power = power + self.emit("SWITCH_ACTOR", actor) + + def switch_actor_off(self, id): + actor = self.cache.get("actors").get(id) + + if actor.state == 0: + return + actor.instance.off() + actor.state = 0 + self.emit("SWITCH_ACTOR", actor) + +class SensorAPI(object): + + def init_sensors(self): + ''' + Initialize all sensors + :return: + ''' + + self.app.logger.info("Init Sensors") + + t = self.cache.get("sensor_types") + for key, value in t.iteritems(): + value.get("class").init_global() + + for key in self.cache.get("sensors"): + self.init_sensor(key) + + def stop_sensor(self, id): + + try: + self.cache.get("sensors").get(id).instance.stop() + except Exception as e: + + self.app.logger.info("Stop Sensor Error") + pass + + + def init_sensor(self, id): + ''' + initialize sensor by id + :param id: + :return: + ''' + + def start_active_sensor(instance): + ''' + start active sensors as background job + :param instance: + :return: + ''' + instance.execute() + + try: + if id in self.cache.get("sensor_instances"): + self.cache.get("sensor_instances").get(id).stop() + value = self.cache.get("sensors").get(id) + + cfg = value.config.copy() + cfg.update(dict(api=self, id=id, name=value.name)) + clazz = self.cache.get("sensor_types").get(value.type).get("class") + value.instance = clazz(**cfg) + value.instance.init() + if isinstance(value.instance, SensorPassive): + # Passive Sensors + value.mode = "P" + else: + # Active Sensors + value.mode = "A" + t = self.socketio.start_background_task(target=start_active_sensor, instance=value.instance) + + except Exception as e: + + self.notify("Sensor Error", "Failed to setup Sensor %s. Please check the configuraiton" % value.name, type="danger", timeout=None) + self.app.logger.error("Initializing of Sensor %s failed" % id) + + def receive_sensor_value(self, id, value): + self.emit("SENSOR_UPDATE", self.cache.get("sensors")[id]) + self.save_to_file(id, value) + + def save_to_file(self, id, value, prefix="sensor"): + filename = "./logs/%s_%s.log" % (prefix, str(id)) + formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime()) + msg = str(formatted_time) + "," +str(value) + "\n" + + with open(filename, "a") as file: + file.write(msg) + + def log_action(self, text): + filename = "./logs/action.log" + formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime()) + with open(filename, "a") as file: + text = text.encode("utf-8") + file.write("%s,%s\n" % (formatted_time, text)) + + def shutdown_sensor(self, id): + self.cache.get("sensors")[id].stop() + + + def get_sensor_value(self, id): + try: + id = int(id) + return float(self.cache.get("sensors")[id].instance.last_value) + except Exception as e: + + return None + +class CacheAPI(object): + + def get_sensor(self, id): + try: + return self.cache["sensors"][id] + except: + return None + + def get_actor(self, id): + try: + return self.cache["actors"][id] + except: + return None + +class CraftBeerPi(ActorAPI, SensorAPI): + + cache = { + "init": {}, + "config": {}, + "actor_types": {}, + "sensor_types": {}, + "sensors": {}, + "sensor_instances": {}, + "init": [], + "background":[], + "step_types": {}, + "controller_types": {}, + "messages": [], + "plugins": {}, + "fermentation_controller_types": {}, + "fermenter_task": {} + } + buzzer = None + eventbus = {} + + + # constructor + def __init__(self, app, socketio): + self.app = app + self.socketio = socketio + + + def emit(self, key, data): + self.socketio.emit(key, data, namespace='/brew') + + def notify(self, headline, message, type="success", timeout=5000): + self.beep() + msg = {"id": str(uuid.uuid1()), "type": type, "headline": headline, "message": message, "timeout": timeout} + self.emit_message(msg) + + + def beep(self): + if self.buzzer is not None: + self.buzzer.beep() + + + def MashStepEndBeep(self): + if self.buzzer is not None: + self.buzzer.MashStepEndBeep() + + + def MashInStepEndBeep(self): + if self.buzzer is not None: + self.buzzer.MashInStepEndBeep() + + + def ChilStepEndBeep(self): + if self.buzzer is not None: + self.buzzer.ChilStepEndBeep() + + + def PumpStepEndBeep(self): + if self.buzzer is not None: + self.buzzer.PumpStepEndBeep() + + + def BoilStepEndBeep(self): + if self.buzzer is not None: + self.buzzer.BoilStepEndBeep() + + + + def add_cache_callback(self, key, method): + method.callback = True + self.cache[key] = method + + def get_config_parameter(self, key, default): + cfg = self.cache.get("config").get(key) + + if cfg is None: + return default + else: + return cfg.value + + def set_config_parameter(self, name, value): + from modules.config import Config + with self.app.app_context(): + update_data = {"name": name, "value": value} + self.cache.get("config")[name].__dict__.update(**update_data) + c = Config.update(**update_data) + self.emit("UPDATE_CONFIG", c) + + + def add_config_parameter(self, name, value, type, description, options=None): + from modules.config import Config + with self.app.app_context(): + c = Config.insert(**{"name":name, "value": value, "type": type, "description": description, "options": options}) + if self.cache.get("config") is not None: + self.cache.get("config")[c.name] = c + + def clear_cache(self, key, is_array=False): + if is_array: + self.cache[key] = [] + else: + self.cache[key] = {} + + # helper method for parsing props + def __parseProps(self, key, cls): + name = cls.__name__ + self.cache[key][name] = {"name": name, "class": cls, "properties": [], "actions": []} + tmpObj = cls() + members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")] + for m in members: + if isinstance(tmpObj.__getattribute__(m), Property.Number): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append( + {"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Text): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append( + {"name": m, "label": t.label, "type": "text", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Select): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append( + {"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Actor): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Sensor): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), Property.Kettle): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description}) + + for name, method in cls.__dict__.iteritems(): + if hasattr(method, "action"): + label = method.__getattribute__("label") + self.cache[key][cls.__name__]["actions"].append({"method": name, "label": label}) + + + return cls + + + def actor(self, cls): + return self.__parseProps("actor_types", cls) + + + + def actor2(self, description="", power=True, **options): + + def decorator(f): + print f() + print f + print options + print description + return f + return decorator + + def sensor(self, cls): + return self.__parseProps("sensor_types", cls) + + def controller(self, cls): + return self.__parseProps("controller_types", cls) + + def fermentation_controller(self, cls): + return self.__parseProps("fermentation_controller_types", cls) + + def get_controller(self, name): + return self.cache["controller_types"].get(name) + + def get_fermentation_controller(self, name): + return self.cache["fermentation_controller_types"].get(name) + + + # Step action + def action(self,label): + def real_decorator(func): + func.action = True + func.label = label + return func + return real_decorator + + # step decorator + def step(self, cls): + + key = "step_types" + name = cls.__name__ + self.cache[key][name] = {"name": name, "class": cls, "properties": [], "actions": []} + + tmpObj = cls() + members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")] + for m in members: + if isinstance(tmpObj.__getattribute__(m), StepProperty.Number): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "default_value": t.default_value, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), StepProperty.Text): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "text", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), StepProperty.Select): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), StepProperty.Actor): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), StepProperty.Sensor): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description}) + elif isinstance(tmpObj.__getattribute__(m), StepProperty.Kettle): + t = tmpObj.__getattribute__(m) + self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description}) + + for name, method in cls.__dict__.iteritems(): + if hasattr(method, "action"): + label = method.__getattribute__("label") + self.cache[key][cls.__name__]["actions"].append({"method": name, "label": label}) + + return cls + + + # Event Bus + def event(self, name, async=False): + + def real_decorator(function): + if self.eventbus.get(name) is None: + self.eventbus[name] = [] + self.eventbus[name].append({"function": function, "async": async}) + def wrapper(*args, **kwargs): + return function(*args, **kwargs) + return wrapper + return real_decorator + + def emit_message(self, message): + self.emit_event(name="MESSAGE", message=message) + + def emit_event(self, name, **kwargs): + for i in self.eventbus.get(name, []): + if i["async"] is False: + i["function"](**kwargs) + else: + t = self.socketio.start_background_task(target=i["function"], **kwargs) + + # initializer decorator + def initalizer(self, order=0): + def real_decorator(function): + self.cache["init"].append({"function": function, "order": order}) + def wrapper(*args, **kwargs): + return function(*args, **kwargs) + return wrapper + return real_decorator + + + + def try_catch(self, errorResult="ERROR"): + def real_decorator(function): + def wrapper(*args, **kwargs): + try: + return function(*args, **kwargs) + except: + self.app.logger.error("Exception in function %s. Return default %s" % (function.__name__, errorResult)) + return errorResult + return wrapper + + return real_decorator + + def nocache(self, view): + @wraps(view) + def no_cache(*args, **kwargs): + response = make_response(view(*args, **kwargs)) + response.headers['Last-Modified'] = datetime.now() + response.headers[ + 'Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0' + response.headers['Pragma'] = 'no-cache' + response.headers['Expires'] = '-1' + return response + + return update_wrapper(no_cache, view) + + def init_kettle(self, id): + try: + value = self.cache.get("kettle").get(id) + value["state"] = False + except: + self.notify("Kettle Setup Faild", "Please check %s configuration" % value.name, type="danger", timeout=None) + self.app.logger.error("Initializing of Kettle %s failed" % id) + + + def run_init(self): + ''' + call all initialziers after startup + :return: + ''' + self.app.logger.info("Invoke Init") + self.cache["init"] = sorted(self.cache["init"], key=lambda k: k['order']) + for i in self.cache.get("init"): + self.app.logger.info("INITIALIZER - METHOD %s PAHT %s: " % (i.get("function").__name__, str(inspect.getmodule(i.get("function")).__file__) )) + i.get("function")(self) + + + + def backgroundtask(self, key, interval, config_parameter=None): + + ''' + Background Task Decorator + :param key: + :param interval: + :param config_parameter: + :return: + ''' + def real_decorator(function): + self.cache["background"].append({"function": function, "key": key, "interval": interval, "config_parameter": config_parameter}) + def wrapper(*args, **kwargs): + return function(*args, **kwargs) + return wrapper + return real_decorator + + def run_background_processes(self): + ''' + call all background task after startup + :return: + ''' + self.app.logger.info("Start Background") + + def job(interval, method): + while True: + try: + method(self) + except Exception as e: + self.app.logger.error("Exception" + method.__name__ + ": " + str(e)) + self.socketio.sleep(interval) + + + for value in self.cache.get("background"): + t = self.socketio.start_background_task(target=job, interval=value.get("interval"), method=value.get("function")) From 91a7b658556483c69249318abd500e2a4b41d1d8 Mon Sep 17 00:00:00 2001 From: cocothenut Date: Sat, 22 Jul 2017 11:36:01 +0200 Subject: [PATCH 4/9] Add files via upload --- modules/base_plugins/brew_steps/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/base_plugins/brew_steps/__init__.py b/modules/base_plugins/brew_steps/__init__.py index c3dbd9f3..07c2aa48 100644 --- a/modules/base_plugins/brew_steps/__init__.py +++ b/modules/base_plugins/brew_steps/__init__.py @@ -56,9 +56,10 @@ def execute(self): # Check if timer finished and go to next step if self.is_timer_finished() == True: + self.notify("Mash Step Completed!", "Starting the next step", timeout=None) # if you dont want a beep sound comment out like : # cbpi.MashStepEndBeep() cbpi.MashStepEndBeep() - self.next() + self.next() @cbpi.step @@ -224,6 +225,7 @@ def execute(self): self.check_hop_timer(3, self.hop_3) # Check if timer finished and go to next step if self.is_timer_finished() == True: + self.notify("Boil Step Completed!", "Starting the next step", timeout=None) # if you dont want a beep sound comment out like : # cbpi.BoilStepEndBeep() - cbpi.BoilStepEndBeep() - self.next() + cbpi.BoilStepEndBeep() + self.next() From 44dec5440176c268a936fcb4ad2b22fbd497bd3e Mon Sep 17 00:00:00 2001 From: cocothenut Date: Sat, 22 Jul 2017 11:36:32 +0200 Subject: [PATCH 5/9] Add files via upload --- modules/buzzer/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/buzzer/__init__.py b/modules/buzzer/__init__.py index 0db76d5f..24021e77 100644 --- a/modules/buzzer/__init__.py +++ b/modules/buzzer/__init__.py @@ -11,7 +11,7 @@ class Buzzer(object): # custom beep sounds - sound = ["H", 0.1, "L"] + sound = ["H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L"] melodie1 = ["H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L"] melodie2 = ["H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L"] melodie3 = ["H", 0.4, "L", 0.1, "H", 0.4, "L", 0.1, "H", 0.4, "L"] From f2fc5033efcb048daf166e0d9e719b320968ca79 Mon Sep 17 00:00:00 2001 From: cocothenut Date: Sat, 22 Jul 2017 11:38:01 +0200 Subject: [PATCH 6/9] Add files via upload From 73948731ad67a7e3c61269e3c7572f600a65149d Mon Sep 17 00:00:00 2001 From: cocothenut Date: Sat, 22 Jul 2017 17:21:51 +0200 Subject: [PATCH 7/9] Add files via upload From 213e15d31bdc368aa81e134f3c96b52c3d813b76 Mon Sep 17 00:00:00 2001 From: cocothenut Date: Sat, 22 Jul 2017 17:22:22 +0200 Subject: [PATCH 8/9] Add files via upload --- modules/base_plugins/brew_steps/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/base_plugins/brew_steps/__init__.py b/modules/base_plugins/brew_steps/__init__.py index 07c2aa48..e829cd08 100644 --- a/modules/base_plugins/brew_steps/__init__.py +++ b/modules/base_plugins/brew_steps/__init__.py @@ -95,8 +95,8 @@ def execute(self): # Check if Target Temp is reached if self.get_kettle_temp(self.kettle) >= float(self.temp) and self.s is False: - self.s = True - self.notify("Step Temp Reached!", "Please press the next button to continue", timeout=None) + self.s = True + self.notify("Step Temp Reached!", "Please press the next button to continue", timeout=None) # if you dont want a beep sound comment out like : # cbpi.MashInStepEndBeep() cbpi.MashInStepEndBeep() @@ -125,7 +125,7 @@ def execute(self): if self.is_timer_finished() == True: # if you dont want a beep sound comment out like : # cbpi.ChilStepEndBeep() cbpi.ChilStepEndBeep() - self.next() + self.next() @cbpi.step class PumpStep(StepBase): @@ -155,7 +155,7 @@ def execute(self): if self.is_timer_finished() == True: # if you dont want a beep sound comment out like : # cbpi.PumpStepEndBeep() cbpi.PumpStepEndBeep() - self.next() + self.next() @cbpi.step class BoilStep(StepBase): @@ -225,7 +225,7 @@ def execute(self): self.check_hop_timer(3, self.hop_3) # Check if timer finished and go to next step if self.is_timer_finished() == True: - self.notify("Boil Step Completed!", "Starting the next step", timeout=None) + self.notify("Boil Step Completed!", "Starting the next step", timeout=None) # if you dont want a beep sound comment out like : # cbpi.BoilStepEndBeep() cbpi.BoilStepEndBeep() self.next() From 9d41e61032428112afac3fdbc5b362cbfe7eac09 Mon Sep 17 00:00:00 2001 From: cocothenut Date: Sat, 22 Jul 2017 17:22:43 +0200 Subject: [PATCH 9/9] Add files via upload