|
- 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").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:
- 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}
- if timeout is None:
- self.cache["messages"].append(msg)
- self.emit("NOTIFY", 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 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": []}
- 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})
- 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})
- 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})
- return cls
-
-
- def actor(self, cls):
- return self.__parseProps("actor_types", cls)
-
- 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})
- 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})
- elif isinstance(tmpObj.__getattribute__(m), StepProperty.Select):
- t = tmpObj.__getattribute__(m)
- self.cache[key][name]["properties"].append({"name": m, "label": t.label, "type": "select", "options": t.options})
- 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})
- 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})
- 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})
-
- 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("-> %s " % i.get("function").__name__)
- 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()
- 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"))
|