mirror of
https://github.com/Manuel83/craftbeerpi3
synced 2026-08-10 02:55:27 +02:00
First Refactoring
- Major API Changes in Core Module - Will be changed further. Still work in progress
This commit is contained in:
Regular → Executable
Executable
+216
@@ -0,0 +1,216 @@
|
||||
from proptypes import *
|
||||
|
||||
class BaseAPI(object):
|
||||
|
||||
def __init__(self, cbpi):
|
||||
self.cbpi = cbpi
|
||||
self.cbpi.cache[self.key] = {}
|
||||
|
||||
|
||||
def init(self):
|
||||
for name, value in self.cbpi.cache[self.key].iteritems():
|
||||
|
||||
value["class"].init_global()
|
||||
|
||||
def parseProps(self, key, cls, **options):
|
||||
|
||||
name = cls.__name__
|
||||
tmpObj = cls()
|
||||
|
||||
try:
|
||||
doc = tmpObj.__doc__.strip()
|
||||
except:
|
||||
doc = ""
|
||||
|
||||
self.cbpi.cache.get(key)[name] = {"name": name, "class": cls, "description":doc, "properties": [], "actions": []}
|
||||
self.cbpi.cache.get(key)[name].update(options)
|
||||
members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")]
|
||||
for m in members:
|
||||
t = tmpObj.__getattribute__(m)
|
||||
|
||||
if isinstance(t, Property.Number):
|
||||
self.cbpi.cache.get(key)[name]["properties"].append({"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "description": t.description, "default_value": t.default_value})
|
||||
elif isinstance(t, Property.Text):
|
||||
self.cbpi.cache.get(key)[name]["properties"].append({"name": m, "label": t.label, "type": "text", "required": t.required, "configurable": t.configurable, "description": t.description, "default_value": t.default_value})
|
||||
elif isinstance(tmpObj.__getattribute__(m), Property.Select):
|
||||
self.cbpi.cache.get(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):
|
||||
self.cbpi.cache.get(key)[name]["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": True, "description": t.description})
|
||||
elif isinstance(tmpObj.__getattribute__(m), Property.Sensor):
|
||||
self.cbpi.cache.get(key)[name]["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": True, "description": t.description})
|
||||
elif isinstance(tmpObj.__getattribute__(m), Property.Kettle):
|
||||
self.cbpi.cache.get(key)[name]["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": True, "description": t.description})
|
||||
|
||||
for method_name, method in cls.__dict__.iteritems():
|
||||
if hasattr(method, "action"):
|
||||
label = method.__getattribute__("label")
|
||||
self.cbpi.cache.get(key)[name]["actions"].append({"method": method_name, "label": label})
|
||||
|
||||
return cls
|
||||
|
||||
|
||||
class SensorAPI(BaseAPI):
|
||||
|
||||
key = "sensor_types"
|
||||
|
||||
def type(self, description="Step", **options):
|
||||
def decorator(f):
|
||||
BaseAPI.parseProps(self, self.key,f, description=description)
|
||||
return f
|
||||
return decorator
|
||||
|
||||
def action(self, label):
|
||||
def real_decorator(func):
|
||||
func.action = True
|
||||
func.label = label
|
||||
return func
|
||||
return real_decorator
|
||||
|
||||
|
||||
class StepAPI(BaseAPI):
|
||||
|
||||
key = "step_types"
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def type(self, description="Step", **options):
|
||||
def decorator(f):
|
||||
BaseAPI.parseProps(self, self.key,f, description=description)
|
||||
return f
|
||||
return decorator
|
||||
|
||||
def action(self, label):
|
||||
def real_decorator(func):
|
||||
func.action = True
|
||||
func.label = label
|
||||
return func
|
||||
return real_decorator
|
||||
|
||||
class ActorAPI(BaseAPI):
|
||||
|
||||
key = "actor_types"
|
||||
|
||||
def type(self, description="", **options):
|
||||
def decorator(f):
|
||||
BaseAPI.parseProps(self, self.key, f, description=description)
|
||||
return f
|
||||
return decorator
|
||||
|
||||
def action(self, label):
|
||||
def real_decorator(func):
|
||||
func.action = True
|
||||
func.label = label
|
||||
return func
|
||||
return real_decorator
|
||||
|
||||
|
||||
|
||||
class KettleAPI(BaseAPI):
|
||||
|
||||
key = "controller_types"
|
||||
|
||||
def controller(self, description="", **options):
|
||||
def decorator(f):
|
||||
BaseAPI.parseProps(self, self.key,f,description=description)
|
||||
return f
|
||||
return decorator
|
||||
|
||||
def action(self, label):
|
||||
def real_decorator(func):
|
||||
func.action = True
|
||||
func.label = label
|
||||
return func
|
||||
return real_decorator
|
||||
|
||||
class FermenterAPI(BaseAPI):
|
||||
|
||||
key = "fermentation_controller_types"
|
||||
|
||||
def controller(self, description="Step", **options):
|
||||
def decorator(f):
|
||||
BaseAPI.parseProps(self, self.key,f,description=description)
|
||||
return f
|
||||
return decorator
|
||||
|
||||
def action(self, label):
|
||||
def real_decorator(func):
|
||||
func.action = True
|
||||
func.label = label
|
||||
return func
|
||||
return real_decorator
|
||||
|
||||
class CoreAPI(BaseAPI):
|
||||
|
||||
key = "core"
|
||||
|
||||
def __init__(self, cbpi):
|
||||
self.cbpi = cbpi
|
||||
self.cbpi.cache["actions"] = {}
|
||||
self.cbpi.cache["init"] = []
|
||||
self.cbpi.cache["js"] = {}
|
||||
self.cbpi.cache["background"] = []
|
||||
def init(self):
|
||||
|
||||
self.cbpi.cache["init"] = sorted(self.cbpi.cache["init"], key=lambda k: k['order'])
|
||||
for value in self.cbpi.cache.get("init"):
|
||||
|
||||
print value
|
||||
value["function"](self.cbpi)
|
||||
|
||||
def job(interval, method):
|
||||
while True:
|
||||
try:
|
||||
method(self.cbpi)
|
||||
except Exception as e:
|
||||
print e
|
||||
self.cbpi._socketio.sleep(interval)
|
||||
|
||||
for value in self.cbpi.cache.get("background"):
|
||||
t = self.cbpi._socketio.start_background_task(target=job, interval=value.get("interval"), method=value.get("function"))
|
||||
|
||||
|
||||
def add_js(self, name, file):
|
||||
self.cbpi.cache["js"][name] = file
|
||||
|
||||
def initializer(self, order=0, **options):
|
||||
def decorator(f):
|
||||
self.cbpi.cache.get("init").append({"function": f, "order": order})
|
||||
return f
|
||||
return decorator
|
||||
|
||||
|
||||
def action(self, key, label, **options):
|
||||
def decorator(f):
|
||||
self.cbpi.cache.get("actions")[key] = {"label": label, "function": f}
|
||||
return f
|
||||
return decorator
|
||||
|
||||
|
||||
def backgroundjob(self, key, interval, **options):
|
||||
def decorator(f):
|
||||
self.cbpi.cache.get("background").append({"function": f, "key": key, "interval": interval})
|
||||
return f
|
||||
return decorator
|
||||
|
||||
def listen(self, name, method=None, async=False):
|
||||
|
||||
if method is not None:
|
||||
if self.cbpi.eventbus.get(name) is None:
|
||||
self.cbpi.eventbus[name] = []
|
||||
self.cbpi.eventbus[name].append({"function": method, "async": async})
|
||||
else:
|
||||
def real_decorator(function):
|
||||
if self.cbpi.eventbus.get(name) is None:
|
||||
self.cbpi.eventbus[name] = []
|
||||
self.cbpi.eventbus[name].append({"function": function, "async": async})
|
||||
def wrapper(*args, **kwargs):
|
||||
return function(*args, **kwargs)
|
||||
return wrapper
|
||||
return real_decorator
|
||||
|
||||
|
||||
class Buzzer(object):
|
||||
|
||||
def beep():
|
||||
pass
|
||||
Regular → Executable
+249
-168
@@ -1,168 +1,249 @@
|
||||
from modules import cbpi
|
||||
|
||||
|
||||
class ActorController(object):
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def actor_on(self, power=100, id=None):
|
||||
|
||||
if id is None:
|
||||
id = self.heater
|
||||
self.api.switch_actor_on(int(id), power=power)
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def actor_off(self, id=None):
|
||||
if id is None:
|
||||
id = self.heater
|
||||
|
||||
self.api.switch_actor_off(int(id))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def actor_power(self, power, id=None):
|
||||
if id is None:
|
||||
id = self.heater
|
||||
self.api.actor_power(int(id), power)
|
||||
|
||||
|
||||
class SensorController(object):
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_sensor_value(self, id=None):
|
||||
|
||||
if id is None:
|
||||
id = self.sensor
|
||||
|
||||
return cbpi.get_sensor_value(id)
|
||||
|
||||
|
||||
|
||||
class ControllerBase(object):
|
||||
__dirty = False
|
||||
__running = False
|
||||
|
||||
@staticmethod
|
||||
def init_global():
|
||||
print "GLOBAL CONTROLLER INIT"
|
||||
|
||||
def notify(self, headline, message, type="success", timeout=5000):
|
||||
self.api.notify(headline, message, type, timeout)
|
||||
|
||||
def is_running(self):
|
||||
return self.__running
|
||||
|
||||
def init(self):
|
||||
self.__running = True
|
||||
|
||||
|
||||
def sleep(self, seconds):
|
||||
self.api.socketio.sleep(seconds)
|
||||
|
||||
def stop(self):
|
||||
self.__running = False
|
||||
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
for a in kwds:
|
||||
super(ControllerBase, self).__setattr__(a, kwds.get(a))
|
||||
self.api = kwds.get("api")
|
||||
self.heater = kwds.get("heater")
|
||||
self.sensor = kwds.get("sensor")
|
||||
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
class KettleController(ControllerBase, ActorController, SensorController):
|
||||
|
||||
@staticmethod
|
||||
def chart(kettle):
|
||||
result = []
|
||||
result.append({"name": "Temp", "data_type": "sensor", "data_id": kettle.sensor})
|
||||
result.append({"name": "Target Temp", "data_type": "kettle", "data_id": kettle.id})
|
||||
|
||||
return result
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
ControllerBase.__init__(self, *args, **kwds)
|
||||
self.kettle_id = kwds.get("kettle_id")
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def heater_on(self, power=100):
|
||||
k = self.api.cache.get("kettle").get(self.kettle_id)
|
||||
if k.heater is not None:
|
||||
self.actor_on(power, int(k.heater))
|
||||
|
||||
|
||||
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def heater_off(self):
|
||||
k = self.api.cache.get("kettle").get(self.kettle_id)
|
||||
if k.heater is not None:
|
||||
self.actor_off(int(k.heater))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_temp(self, id=None):
|
||||
if id is None:
|
||||
id = self.kettle_id
|
||||
return self.get_sensor_value(int(self.api.cache.get("kettle").get(id).sensor))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_target_temp(self, id=None):
|
||||
if id is None:
|
||||
id = self.kettle_id
|
||||
return self.api.cache.get("kettle").get(id).target_temp
|
||||
|
||||
class FermenterController(ControllerBase, ActorController, SensorController):
|
||||
|
||||
@staticmethod
|
||||
def chart(fermenter):
|
||||
result = []
|
||||
result.append({"name": "Temp", "data_type": "sensor", "data_id": fermenter.sensor})
|
||||
result.append({"name": "Target Temp", "data_type": "fermenter", "data_id": fermenter.id})
|
||||
return result
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
ControllerBase.__init__(self, *args, **kwds)
|
||||
self.fermenter_id = kwds.get("fermenter_id")
|
||||
self.cooler = kwds.get("cooler")
|
||||
|
||||
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_target_temp(self, id=None):
|
||||
if id is None:
|
||||
id = self.fermenter_id
|
||||
return self.api.cache.get("fermenter").get(id).target_temp
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def heater_on(self, power=100):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.heater is not None:
|
||||
self.actor_on(int(f.heater))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def heater_off(self):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.heater is not None:
|
||||
self.actor_off(int(f.heater))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def cooler_on(self, power=100):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.cooler is not None:
|
||||
self.actor_on(power, int(f.cooler))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def cooler_off(self):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.cooler is not None:
|
||||
self.actor_off(int(f.cooler))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_temp(self, id=None):
|
||||
|
||||
if id is None:
|
||||
id = self.fermenter_id
|
||||
return self.get_sensor_value(int(self.api.cache.get("fermenter").get(id).sensor))
|
||||
|
||||
|
||||
class Base(object):
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
for a in kwds:
|
||||
|
||||
super(Base, self).__setattr__(a, kwds.get(a))
|
||||
self.api = kwds.get("cbpi")
|
||||
self.id = kwds.get("id")
|
||||
self.value = None
|
||||
self.__dirty = False
|
||||
|
||||
class Actor(Base):
|
||||
|
||||
@classmethod
|
||||
def init_global(cls):
|
||||
print "GLOBAL INIT ACTOR"
|
||||
pass
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def on(self, power=100):
|
||||
print "SWITCH ON"
|
||||
pass
|
||||
|
||||
def off(self):
|
||||
print "SWITCH OFF"
|
||||
pass
|
||||
|
||||
def power(self, power):
|
||||
print "SET POWER", power
|
||||
pass
|
||||
|
||||
def state(self):
|
||||
pass
|
||||
|
||||
|
||||
class Sensor(Base):
|
||||
|
||||
unit = ""
|
||||
|
||||
@classmethod
|
||||
def init_global(cls):
|
||||
pass
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def get_unit(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def update_value(self, value):
|
||||
self.value = value
|
||||
self.cbpi.sensor.write_log(self.id, value)
|
||||
self.cbpi.emit("SENSOR_UPDATE", id=self.id, value=value)
|
||||
self.cbpi.ws_emit("SENSOR_UPDATE", self.cbpi.cache["sensors"][self.id])
|
||||
|
||||
def execute(self):
|
||||
print "EXECUTE"
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
class ControllerBase(object):
|
||||
__dirty = False
|
||||
__running = False
|
||||
|
||||
@staticmethod
|
||||
def init_global():
|
||||
print "GLOBAL CONTROLLER INIT"
|
||||
|
||||
def notify(self, headline, message, type="success", timeout=5000):
|
||||
self.api.notify(headline, message, type, timeout)
|
||||
|
||||
def is_running(self):
|
||||
return self.__running
|
||||
|
||||
def init(self):
|
||||
self.__running = True
|
||||
|
||||
def sleep(self, seconds):
|
||||
self.api.sleep(seconds)
|
||||
|
||||
def stop(self):
|
||||
self.__running = False
|
||||
|
||||
def get_sensor_value(self, id):
|
||||
return self.api.sensor.get_sensor_value(id)
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
for a in kwds:
|
||||
super(ControllerBase, self).__setattr__(a, kwds.get(a))
|
||||
self.api = kwds.get("api")
|
||||
self.heater = kwds.get("heater")
|
||||
self.sensor = kwds.get("sensor")
|
||||
|
||||
def actor_on(self,id, power=100):
|
||||
self.api.actor.on(id, power=power)
|
||||
|
||||
def actor_off(self, id):
|
||||
self.api.actor.off(id)
|
||||
|
||||
def actor_power(self, power, id=None):
|
||||
self.api.actor.power(id, power)
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
class KettleController(ControllerBase):
|
||||
|
||||
@staticmethod
|
||||
def chart(kettle):
|
||||
result = []
|
||||
result.append({"name": "Temp", "data_type": "sensor", "data_id": kettle.sensor})
|
||||
result.append({"name": "Target Temp", "data_type": "kettle", "data_id": kettle.id})
|
||||
return result
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
ControllerBase.__init__(self, *args, **kwds)
|
||||
self.kettle_id = kwds.get("kettle_id")
|
||||
|
||||
def heater_on(self, power=100):
|
||||
k = self.api.cache.get("kettle").get(self.kettle_id)
|
||||
if k.heater is not None:
|
||||
self.actor_on(k.heater, power)
|
||||
|
||||
def heater_off(self):
|
||||
k = self.api.cache.get("kettle").get(self.kettle_id)
|
||||
if k.heater is not None:
|
||||
self.actor_off(k.heater)
|
||||
|
||||
def get_temp(self, id=None):
|
||||
if id is None:
|
||||
id = self.kettle_id
|
||||
return self.get_sensor_value(int(self.api.cache.get("kettle").get(id).sensor))
|
||||
|
||||
def get_target_temp(self, id=None):
|
||||
if id is None:
|
||||
id = self.kettle_id
|
||||
return self.api.cache.get("kettle").get(id).target_temp
|
||||
|
||||
class FermenterController(ControllerBase):
|
||||
|
||||
@staticmethod
|
||||
def chart(fermenter):
|
||||
result = []
|
||||
result.append({"name": "Temp", "data_type": "sensor", "data_id": fermenter.sensor})
|
||||
result.append({"name": "Target Temp", "data_type": "fermenter", "data_id": fermenter.id})
|
||||
return result
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
ControllerBase.__init__(self, *args, **kwds)
|
||||
self.fermenter_id = kwds.get("fermenter_id")
|
||||
self.cooler = kwds.get("cooler")
|
||||
|
||||
def get_target_temp(self, id=None):
|
||||
if id is None:
|
||||
id = self.fermenter_id
|
||||
return self.api.cache.get("fermenter").get(id).target_temp
|
||||
|
||||
def heater_on(self, power=100):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.heater is not None:
|
||||
self.actor_on(int(f.heater))
|
||||
|
||||
def heater_off(self):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.heater is not None:
|
||||
self.actor_off(int(f.heater))
|
||||
|
||||
def cooler_on(self, power=100):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.cooler is not None:
|
||||
self.actor_on(power, int(f.cooler))
|
||||
|
||||
def cooler_off(self):
|
||||
f = self.api.cache.get("fermenter").get(self.fermenter_id)
|
||||
if f.cooler is not None:
|
||||
self.actor_off(int(f.cooler))
|
||||
|
||||
def get_temp(self, id=None):
|
||||
if id is None:
|
||||
id = self.fermenter_id
|
||||
return self.get_sensor_value(int(self.api.cache.get("fermenter").get(id).sensor))
|
||||
|
||||
|
||||
|
||||
class Step(Base):
|
||||
|
||||
|
||||
@classmethod
|
||||
def init_global(cls):
|
||||
pass
|
||||
|
||||
__dirty = False
|
||||
managed_fields = []
|
||||
n = False
|
||||
|
||||
def next(self):
|
||||
self.n = True
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def finish(self):
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
def execute(self):
|
||||
print "-------------"
|
||||
print "Step Info"
|
||||
print "Kettle ID: %s" % self.kettle_id
|
||||
print "ID: %s" % self.id
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
|
||||
for a in kwds:
|
||||
super(Step, self).__setattr__(a, kwds.get(a))
|
||||
|
||||
self.api = kwds.get("api")
|
||||
self.id = kwds.get("id")
|
||||
self.name = kwds.get("name")
|
||||
self.kettle_id = kwds.get("kettleid")
|
||||
self.value = None
|
||||
self.__dirty = False
|
||||
|
||||
def is_dirty(self):
|
||||
return self.__dirty
|
||||
|
||||
def reset_dirty(self):
|
||||
self.__dirty = False
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
if name != "_StepBase__dirty" and name in self.managed_fields:
|
||||
self.__dirty = True
|
||||
super(Step, self).__setattr__(name, value)
|
||||
else:
|
||||
super(Step, self).__setattr__(name, value)
|
||||
Regular → Executable
+110
-109
@@ -1,109 +1,110 @@
|
||||
from flask import request, json
|
||||
from flask_classy import route, FlaskView
|
||||
from modules import cbpi
|
||||
|
||||
|
||||
class BaseView(FlaskView):
|
||||
|
||||
as_array = False
|
||||
cache_key = None
|
||||
api = cbpi
|
||||
|
||||
@route('/<int:id>', methods=["GET"])
|
||||
def getOne(self, id):
|
||||
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
return json.dumps(self.api.cache.get(self.cache_key).get(id))
|
||||
else:
|
||||
return json.dumps(self.model.get_one(id))
|
||||
|
||||
@route('/', methods=["GET"])
|
||||
def getAll(self):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
return json.dumps(self.api.cache.get(self.cache_key))
|
||||
else:
|
||||
return json.dumps(self.model.get_all())
|
||||
|
||||
def _pre_post_callback(self, data):
|
||||
pass
|
||||
|
||||
|
||||
def _post_post_callback(self, m):
|
||||
pass
|
||||
|
||||
@route('/', methods=["POST"])
|
||||
def post(self):
|
||||
data = request.json
|
||||
self._pre_post_callback(data)
|
||||
m = self.model.insert(**data)
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
self.api.cache.get(self.cache_key)[m.id] = m
|
||||
|
||||
self._post_post_callback(m)
|
||||
|
||||
return json.dumps(m)
|
||||
|
||||
def _pre_put_callback(self, m):
|
||||
pass
|
||||
|
||||
def _post_put_callback(self, m):
|
||||
pass
|
||||
|
||||
|
||||
@route('/<int:id>', methods=["PUT"])
|
||||
def put(self, id):
|
||||
data = request.json
|
||||
data["id"] = id
|
||||
try:
|
||||
del data["instance"]
|
||||
except:
|
||||
pass
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
self._pre_put_callback(self.api.cache.get(self.cache_key)[id])
|
||||
self.api.cache.get(self.cache_key)[id].__dict__.update(**data)
|
||||
m = self.model.update(**self.api.cache.get(self.cache_key)[id].__dict__)
|
||||
self._post_put_callback(self.api.cache.get(self.cache_key)[id])
|
||||
return json.dumps(self.api.cache.get(self.cache_key)[id])
|
||||
else:
|
||||
m = self.model.update(**data)
|
||||
|
||||
self._post_put_callback(m)
|
||||
return json.dumps(m)
|
||||
|
||||
|
||||
def _pre_delete_callback(self, m):
|
||||
pass
|
||||
|
||||
def _post_delete_callback(self, id):
|
||||
pass
|
||||
|
||||
@route('/<int:id>', methods=["DELETE"])
|
||||
def delete(self, id):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
self._pre_delete_callback(self.api.cache.get(self.cache_key)[id])
|
||||
del self.api.cache.get(self.cache_key)[id]
|
||||
m = self.model.delete(id)
|
||||
|
||||
def _post_delete_callback(self, id):
|
||||
pass
|
||||
return ('',204)
|
||||
|
||||
@classmethod
|
||||
def post_init_callback(cls, obj):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def init_cache(cls):
|
||||
with cls.api.app.app_context():
|
||||
|
||||
if cls.model.__as_array__ is True:
|
||||
cls.api.cache[cls.cache_key] = []
|
||||
|
||||
for value in cls.model.get_all():
|
||||
cls.post_init_callback(value)
|
||||
cls.api.cache[cls.cache_key].append(value)
|
||||
else:
|
||||
cls.api.cache[cls.cache_key] = {}
|
||||
for key, value in cls.model.get_all().iteritems():
|
||||
cls.post_init_callback(value)
|
||||
cls.api.cache[cls.cache_key][key] = value
|
||||
from flask import request, json
|
||||
from flask_classy import route, FlaskView
|
||||
from modules.core.core import cbpi
|
||||
|
||||
|
||||
class BaseView(FlaskView):
|
||||
|
||||
as_array = False
|
||||
cache_key = None
|
||||
api = cbpi
|
||||
|
||||
@route('/<int:id>', methods=["GET"])
|
||||
def getOne(self, id):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
return json.dumps(self.api.cache.get(self.cache_key).get(id))
|
||||
else:
|
||||
return json.dumps(self.model.get_one(id))
|
||||
|
||||
@route('/', methods=["GET"])
|
||||
def getAll(self):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
return json.dumps(self.api.cache.get(self.cache_key))
|
||||
else:
|
||||
return json.dumps(self.model.get_all())
|
||||
|
||||
def _pre_post_callback(self, data):
|
||||
pass
|
||||
|
||||
|
||||
def _post_post_callback(self, m):
|
||||
pass
|
||||
|
||||
@route('/', methods=["POST"])
|
||||
def post(self):
|
||||
|
||||
data = request.json
|
||||
self.api._app.logger.info("INSERT Model %s", self.model.__name__)
|
||||
self._pre_post_callback(data)
|
||||
m = self.model.insert(**data)
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
self.api.cache.get(self.cache_key)[m.id] = m
|
||||
|
||||
self._post_post_callback(m)
|
||||
|
||||
return json.dumps(m)
|
||||
|
||||
def _pre_put_callback(self, m):
|
||||
pass
|
||||
|
||||
def _post_put_callback(self, m):
|
||||
pass
|
||||
|
||||
|
||||
@route('/<int:id>', methods=["PUT"])
|
||||
def put(self, id):
|
||||
data = request.json
|
||||
data["id"] = id
|
||||
try:
|
||||
del data["instance"]
|
||||
except:
|
||||
pass
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
self._pre_put_callback(self.api.cache.get(self.cache_key)[id])
|
||||
self.api.cache.get(self.cache_key)[id].__dict__.update(**data)
|
||||
m = self.model.update(**self.api.cache.get(self.cache_key)[id].__dict__)
|
||||
self._post_put_callback(self.api.cache.get(self.cache_key)[id])
|
||||
return json.dumps(self.api.cache.get(self.cache_key)[id])
|
||||
else:
|
||||
m = self.model.update(**data)
|
||||
|
||||
self._post_put_callback(m)
|
||||
return json.dumps(m)
|
||||
|
||||
|
||||
def _pre_delete_callback(self, m):
|
||||
pass
|
||||
|
||||
def _post_delete_callback(self, id):
|
||||
pass
|
||||
|
||||
@route('/<int:id>', methods=["DELETE"])
|
||||
def delete(self, id):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
self._pre_delete_callback(self.api.cache.get(self.cache_key)[id])
|
||||
del self.api.cache.get(self.cache_key)[id]
|
||||
m = self.model.delete(id)
|
||||
|
||||
def _post_delete_callback(self, id):
|
||||
pass
|
||||
return ('',204)
|
||||
|
||||
@classmethod
|
||||
def post_init_callback(cls, obj):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def init_cache(cls):
|
||||
with cls.api._app.app_context():
|
||||
|
||||
if cls.model.__as_array__ is True:
|
||||
cls.api.cache[cls.cache_key] = []
|
||||
|
||||
for value in cls.model.get_all():
|
||||
cls.post_init_callback(value)
|
||||
cls.api.cache[cls.cache_key].append(value)
|
||||
else:
|
||||
cls.api.cache[cls.cache_key] = {}
|
||||
for key, value in cls.model.get_all().iteritems():
|
||||
cls.post_init_callback(value)
|
||||
cls.api.cache[cls.cache_key][key] = value
|
||||
|
||||
Regular → Executable
+337
-494
@@ -1,494 +1,337 @@
|
||||
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, "default_value": t.default_value})
|
||||
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, "default_value": t.default_value, "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, "default_value": t.default_value, "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 json
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from functools import wraps, update_wrapper
|
||||
from importlib import import_module
|
||||
from time import localtime, strftime
|
||||
|
||||
from flask import Flask, redirect, json, g, make_response
|
||||
from flask_socketio import SocketIO
|
||||
|
||||
from baseapi import *
|
||||
from db import DBModel
|
||||
from modules.core.basetypes import Sensor, Actor
|
||||
from modules.database.dbmodel import Kettle
|
||||
|
||||
|
||||
class ComplexEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
try:
|
||||
|
||||
if isinstance(obj, DBModel):
|
||||
return obj.__dict__
|
||||
elif isinstance(obj, Actor):
|
||||
return {"state": obj.value}
|
||||
elif isinstance(obj, Sensor):
|
||||
return {"value": obj.value, "unit": obj.unit}
|
||||
elif hasattr(obj, "callback"):
|
||||
return obj()
|
||||
else:
|
||||
return None
|
||||
|
||||
return None
|
||||
except TypeError as e:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
class Addon(object):
|
||||
def __init__(self, cbpi):
|
||||
self.step = StepAPI(cbpi)
|
||||
self.actor = ActorAPI(cbpi)
|
||||
self.sensor = SensorAPI(cbpi)
|
||||
self.kettle = KettleAPI(cbpi)
|
||||
self.fermenter = FermenterAPI(cbpi)
|
||||
self.core = CoreAPI(cbpi)
|
||||
|
||||
def init(self):
|
||||
self.core.init()
|
||||
self.step.init()
|
||||
self.actor.init()
|
||||
self.sensor.init()
|
||||
# self.kettle.init()
|
||||
# self.fermenter.init()
|
||||
|
||||
|
||||
class ActorCore(object):
|
||||
key = "actor_types"
|
||||
|
||||
def __init__(self, cbpi):
|
||||
self.cbpi = cbpi
|
||||
self.cbpi.cache["actors"] = {}
|
||||
self.cbpi.cache[self.key] = {}
|
||||
|
||||
def init(self):
|
||||
for key, value in self.cbpi.cache["actors"].iteritems():
|
||||
self.init_one(key)
|
||||
|
||||
def init_one(self, id):
|
||||
try:
|
||||
actor = self.cbpi.cache["actors"][id]
|
||||
clazz = self.cbpi.cache[self.key].get(actor.type)["class"]
|
||||
cfg = actor.config.copy()
|
||||
cfg.update(dict(cbpi=self.cbpi, id=id))
|
||||
self.cbpi.cache["actors"][id].instance = clazz(**cfg)
|
||||
self.cbpi.emit("INIT_ACTOR", id=id)
|
||||
except Exception as e:
|
||||
print e
|
||||
self.cbpi._app.logger.error(e)
|
||||
|
||||
def stop_one(self, id):
|
||||
self.cbpi.cache["actors"][id]["instance"].stop()
|
||||
self.cbpi.emit("STOP_ACTOR", id=id)
|
||||
|
||||
def on(self, id, power=100):
|
||||
try:
|
||||
actor = self.cbpi.cache["actors"].get(int(id))
|
||||
actor.instance.on()
|
||||
actor.state = 1
|
||||
actor.power = power
|
||||
self.cbpi.ws_emit("SWITCH_ACTOR", actor)
|
||||
self.cbpi.emit("SWITCH_ACTOR_ON", id=id, power=power)
|
||||
return True
|
||||
except Exception as e:
|
||||
print e
|
||||
return False
|
||||
|
||||
def off(self, id):
|
||||
try:
|
||||
actor = self.cbpi.cache["actors"].get(int(id))
|
||||
actor.instance.off()
|
||||
actor.state = 0
|
||||
self.cbpi.ws_emit("SWITCH_ACTOR", actor)
|
||||
self.cbpi.emit("SWITCH_ACTOR_OFF", id=id)
|
||||
return True
|
||||
except Exception as e:
|
||||
print e
|
||||
return False
|
||||
|
||||
def power(self, id, power):
|
||||
try:
|
||||
actor = self.cbpi.cache["actors"].get(int(id))
|
||||
actor.instance.power(power)
|
||||
actor.power = power
|
||||
self.cbpi.ws_emit("SWITCH_ACTOR", actor)
|
||||
self.cbpi.emit("SWITCH_ACTOR_POWER_CHANGE", id=id, power=power)
|
||||
return True
|
||||
except Exception as e:
|
||||
print e
|
||||
return False
|
||||
|
||||
def get_state(self, actor_id):
|
||||
print actor_id
|
||||
print self.cbpi
|
||||
|
||||
|
||||
class SensorCore(object):
|
||||
key = "sensor_types"
|
||||
|
||||
def __init__(self, cbpi):
|
||||
self.cbpi = cbpi
|
||||
self.cbpi.cache["sensors"] = {}
|
||||
self.cbpi.cache["sensor_instances"] = {}
|
||||
self.cbpi.cache["sensor_types"] = {}
|
||||
|
||||
def init(self):
|
||||
for key, value in self.cbpi.cache["sensors"].iteritems():
|
||||
self.init_one(key)
|
||||
|
||||
def init_one(self, id):
|
||||
try:
|
||||
sensor = self.cbpi.cache["sensors"][id]
|
||||
clazz = self.cbpi.cache[self.key].get(sensor.type)["class"]
|
||||
cfg = sensor.config.copy()
|
||||
cfg.update(dict(cbpi=self.cbpi, id=id))
|
||||
self.cbpi.cache["sensors"][id].instance = clazz(**cfg)
|
||||
self.cbpi.cache["sensors"][id].instance.init()
|
||||
print self.cbpi.cache["sensors"][id].instance
|
||||
self.cbpi.emit("INIT_SENSOR", id=id)
|
||||
|
||||
def job(obj):
|
||||
obj.execute()
|
||||
|
||||
t = self.cbpi._socketio.start_background_task(target=job, obj=self.cbpi.cache["sensors"][id].instance)
|
||||
self.cbpi.emit("INIT_SENSOR", id=id)
|
||||
|
||||
except Exception as e:
|
||||
print "ERROR"
|
||||
self.cbpi._app.logger.error(e)
|
||||
|
||||
def stop_one(self, id):
|
||||
print "OBJ", self.cbpi.cache["sensors"][id]
|
||||
self.cbpi.cache["sensors"][id].instance.stop()
|
||||
self.cbpi.emit("STOP_SENSOR", id=id)
|
||||
|
||||
def get_value(self, sensorid):
|
||||
try:
|
||||
return self.cbpi.cache["sensors"][sensorid].instance.value
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_state(self, actor_id):
|
||||
print actor_id
|
||||
print self.cbpi
|
||||
|
||||
def write_log(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)
|
||||
|
||||
|
||||
class BrewingCore(object):
|
||||
def __init__(self, cbpi):
|
||||
self.cbpi = cbpi
|
||||
self.cbpi.cache["step_types"] = {}
|
||||
self.cbpi.cache["controller_types"] = {}
|
||||
|
||||
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 get_controller(self, name):
|
||||
return self.cbpi.cache["controller_types"].get(name)
|
||||
|
||||
def set_target_temp(self, id, temp):
|
||||
self.cbpi.cache.get("kettle")[id].target_temp = float(temp)
|
||||
Kettle.update(**self.cbpi.cache.get("kettle")[id].__dict__)
|
||||
self.cbpi.ws_emit("UPDATE_KETTLE_TARGET_TEMP", {"id": id, "target_temp": temp})
|
||||
self.cbpi.emit("SET_KETTLE_TARGET_TEMP", id=id, temp=temp)
|
||||
|
||||
|
||||
class FermentationCore(object):
|
||||
def __init__(self, cbpi):
|
||||
self.cbpi = cbpi
|
||||
self.cbpi.cache["fermenter"] = {}
|
||||
self.cbpi.cache["fermentation_controller_types"] = {}
|
||||
|
||||
def get_controller(self, name):
|
||||
return self.cbpi.cache["fermentation_controller_types"].get(name)
|
||||
|
||||
|
||||
class CraftBeerPI(object):
|
||||
cache = {}
|
||||
eventbus = {}
|
||||
|
||||
def __init__(self):
|
||||
FORMAT = '%(asctime)-15s - %(levelname)s - %(message)s'
|
||||
logging.basicConfig(filename='./logs/app.log', level=logging.INFO, format=FORMAT)
|
||||
self.cache["messages"] = []
|
||||
self.modules = {}
|
||||
self.cache["users"] = {'manuel': {'pw': 'secret'}}
|
||||
self.addon = Addon(self)
|
||||
self.actor = ActorCore(self)
|
||||
self.sensor = SensorCore(self)
|
||||
self.brewing = BrewingCore(self)
|
||||
self.fermentation = FermentationCore(self)
|
||||
self._app = Flask(__name__)
|
||||
self._app.secret_key = 'Cr4ftB33rP1'
|
||||
self._app.json_encoder = ComplexEncoder
|
||||
self._socketio = SocketIO(self._app, json=json, logging=False)
|
||||
|
||||
@self._app.route('/')
|
||||
def index():
|
||||
return redirect('ui')
|
||||
|
||||
def run(self):
|
||||
self.__init_db()
|
||||
self.loadPlugins()
|
||||
self.addon.init()
|
||||
self.sensor.init()
|
||||
self.actor.init()
|
||||
self.beep()
|
||||
self._socketio.run(self._app, host='0.0.0.0', port=5000)
|
||||
|
||||
def beep(self):
|
||||
self.buzzer.beep()
|
||||
|
||||
def sleep(self, seconds):
|
||||
self._socketio.sleep(seconds)
|
||||
|
||||
def notify(self, headline, message, type="success", timeout=5000):
|
||||
msg = {"id": str(uuid.uuid1()), "type": type, "headline": headline, "message": message, "timeout": timeout}
|
||||
self.ws_emit("NOTIFY", msg)
|
||||
|
||||
def ws_emit(self, key, data):
|
||||
self._socketio.emit(key, data, namespace='/brew')
|
||||
|
||||
def __init_db(self, ):
|
||||
print "INIT DB"
|
||||
with self._app.app_context():
|
||||
db = self.get_db()
|
||||
try:
|
||||
with self._app.open_resource('../../config/schema.sql', mode='r') as f:
|
||||
db.cursor().executescript(f.read())
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
print e
|
||||
pass
|
||||
|
||||
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 get_db(self):
|
||||
db = getattr(g, '_database', None)
|
||||
if db is None:
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
|
||||
db = g._database = sqlite3.connect('craftbeerpi.db')
|
||||
db.row_factory = dict_factory
|
||||
return db
|
||||
|
||||
def add_cache_callback(self, key, method):
|
||||
method.callback = True
|
||||
self.cache[key] = method
|
||||
|
||||
def get_config_parameter(self, key, default):
|
||||
cfg = self.cache["config"].get(key)
|
||||
if cfg is None:
|
||||
return default
|
||||
else:
|
||||
return cfg.value
|
||||
|
||||
def emit(self, key, **kwargs):
|
||||
print key, kwargs
|
||||
if self.eventbus.get(key) is not None:
|
||||
for value in self.eventbus[key]:
|
||||
if value["async"] is False:
|
||||
value["function"](**kwargs)
|
||||
else:
|
||||
t = self.cbpi._socketio.start_background_task(target=value["function"], **kwargs)
|
||||
|
||||
def loadPlugins(self):
|
||||
for filename in os.listdir("./modules/plugins"):
|
||||
print filename
|
||||
if os.path.isdir("./modules/plugins/" + filename) is False:
|
||||
continue
|
||||
try:
|
||||
self.modules[filename] = import_module("modules.plugins.%s" % (filename))
|
||||
except Exception as e:
|
||||
print e
|
||||
self.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
|
||||
|
||||
|
||||
cbpi = CraftBeerPI()
|
||||
addon = cbpi.addon
|
||||
|
||||
Regular → Executable
+133
-134
@@ -1,134 +1,133 @@
|
||||
import sqlite3
|
||||
|
||||
from flask import json, g
|
||||
|
||||
|
||||
def get_db():
|
||||
db = getattr(g, '_database', None)
|
||||
if db is None:
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
db = g._database = sqlite3.connect('craftbeerpi.db')
|
||||
db.row_factory = dict_factory
|
||||
return db
|
||||
|
||||
class DBModel(object):
|
||||
|
||||
__priamry_key__ = "id"
|
||||
__as_array__ = False
|
||||
__order_by__ = None
|
||||
__json_fields__ = []
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
self.__setattr__(self.__priamry_key__, args.get(self.__priamry_key__))
|
||||
for f in self.__fields__:
|
||||
if f in self.__json_fields__:
|
||||
if args.get(f) is not None:
|
||||
|
||||
if isinstance(args.get(f) , dict) or isinstance(args.get(f) , list) :
|
||||
self.__setattr__(f, args.get(f))
|
||||
else:
|
||||
self.__setattr__(f, json.loads(args.get(f)))
|
||||
else:
|
||||
self.__setattr__(f, None)
|
||||
else:
|
||||
self.__setattr__(f, args.get(f))
|
||||
|
||||
@classmethod
|
||||
def get_all(cls):
|
||||
cur = get_db().cursor()
|
||||
if cls.__order_by__ is not None:
|
||||
|
||||
cur.execute("SELECT * FROM %s ORDER BY %s.'%s'" % (cls.__table_name__,cls.__table_name__,cls.__order_by__))
|
||||
else:
|
||||
cur.execute("SELECT * FROM %s" % cls.__table_name__)
|
||||
|
||||
if cls.__as_array__ is True:
|
||||
result = []
|
||||
for r in cur.fetchall():
|
||||
|
||||
result.append( cls(r))
|
||||
else:
|
||||
result = {}
|
||||
for r in cur.fetchall():
|
||||
result[r.get(cls.__priamry_key__)] = cls(r)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_one(cls, id):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("SELECT * FROM %s WHERE %s = ?" % (cls.__table_name__, cls.__priamry_key__), (id,))
|
||||
r = cur.fetchone()
|
||||
if r is not None:
|
||||
return cls(r)
|
||||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def delete(cls, id):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("DELETE FROM %s WHERE %s = ? " % (cls.__table_name__, cls.__priamry_key__), (id,))
|
||||
get_db().commit()
|
||||
|
||||
@classmethod
|
||||
def insert(cls, **kwargs):
|
||||
cur = get_db().cursor()
|
||||
|
||||
|
||||
if cls.__priamry_key__ is not None and kwargs.has_key(cls.__priamry_key__):
|
||||
query = "INSERT INTO %s (%s, %s) VALUES (?, %s)" % (
|
||||
cls.__table_name__,
|
||||
cls.__priamry_key__,
|
||||
', '.join("'%s'" % str(x) for x in cls.__fields__),
|
||||
', '.join(['?'] * len(cls.__fields__)))
|
||||
data = ()
|
||||
data = data + (kwargs.get(cls.__priamry_key__),)
|
||||
for f in cls.__fields__:
|
||||
if f in cls.__json_fields__:
|
||||
data = data + (json.dumps(kwargs.get(f)),)
|
||||
else:
|
||||
data = data + (kwargs.get(f),)
|
||||
else:
|
||||
|
||||
query = 'INSERT INTO %s (%s) VALUES (%s)' % (
|
||||
cls.__table_name__,
|
||||
', '.join("'%s'" % str(x) for x in cls.__fields__),
|
||||
', '.join(['?'] * len(cls.__fields__)))
|
||||
|
||||
data = ()
|
||||
for f in cls.__fields__:
|
||||
if f in cls.__json_fields__:
|
||||
data = data + (json.dumps(kwargs.get(f)),)
|
||||
else:
|
||||
data = data + (kwargs.get(f),)
|
||||
|
||||
|
||||
cur.execute(query, data)
|
||||
get_db().commit()
|
||||
i = cur.lastrowid
|
||||
kwargs["id"] = i
|
||||
|
||||
return cls(kwargs)
|
||||
|
||||
@classmethod
|
||||
def update(cls, **kwargs):
|
||||
cur = get_db().cursor()
|
||||
query = 'UPDATE %s SET %s WHERE %s = ?' % (
|
||||
cls.__table_name__,
|
||||
', '.join("'%s' = ?" % str(x) for x in cls.__fields__),cls.__priamry_key__)
|
||||
|
||||
data = ()
|
||||
for f in cls.__fields__:
|
||||
if f in cls.__json_fields__:
|
||||
data = data + (json.dumps(kwargs.get(f)),)
|
||||
else:
|
||||
data = data + (kwargs.get(f),)
|
||||
|
||||
data = data + (kwargs.get(cls.__priamry_key__),)
|
||||
cur.execute(query, data)
|
||||
get_db().commit()
|
||||
return cls(kwargs)
|
||||
import sqlite3
|
||||
from flask import json, g
|
||||
|
||||
|
||||
def get_db():
|
||||
db = getattr(g, '_database', None)
|
||||
if db is None:
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
db = g._database = sqlite3.connect('craftbeerpi.db')
|
||||
db.row_factory = dict_factory
|
||||
return db
|
||||
|
||||
class DBModel(object):
|
||||
|
||||
__priamry_key__ = "id"
|
||||
__as_array__ = False
|
||||
__order_by__ = None
|
||||
__json_fields__ = []
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
self.__setattr__(self.__priamry_key__, args.get(self.__priamry_key__))
|
||||
for f in self.__fields__:
|
||||
if f in self.__json_fields__:
|
||||
if args.get(f) is not None:
|
||||
|
||||
if isinstance(args.get(f) , dict) or isinstance(args.get(f) , list) :
|
||||
self.__setattr__(f, args.get(f))
|
||||
else:
|
||||
self.__setattr__(f, json.loads(args.get(f)))
|
||||
else:
|
||||
self.__setattr__(f, None)
|
||||
else:
|
||||
self.__setattr__(f, args.get(f))
|
||||
|
||||
@classmethod
|
||||
def get_all(cls):
|
||||
cur = get_db().cursor()
|
||||
if cls.__order_by__ is not None:
|
||||
|
||||
cur.execute("SELECT * FROM %s ORDER BY %s.'%s'" % (cls.__table_name__,cls.__table_name__,cls.__order_by__))
|
||||
else:
|
||||
cur.execute("SELECT * FROM %s" % cls.__table_name__)
|
||||
|
||||
if cls.__as_array__ is True:
|
||||
result = []
|
||||
for r in cur.fetchall():
|
||||
|
||||
result.append( cls(r))
|
||||
else:
|
||||
result = {}
|
||||
for r in cur.fetchall():
|
||||
result[r.get(cls.__priamry_key__)] = cls(r)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_one(cls, id):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("SELECT * FROM %s WHERE %s = ?" % (cls.__table_name__, cls.__priamry_key__), (id,))
|
||||
r = cur.fetchone()
|
||||
if r is not None:
|
||||
return cls(r)
|
||||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def delete(cls, id):
|
||||
cur = get_db().cursor()
|
||||
cur.execute("DELETE FROM %s WHERE %s = ? " % (cls.__table_name__, cls.__priamry_key__), (id,))
|
||||
get_db().commit()
|
||||
|
||||
@classmethod
|
||||
def insert(cls, **kwargs):
|
||||
cur = get_db().cursor()
|
||||
|
||||
|
||||
if cls.__priamry_key__ is not None and kwargs.has_key(cls.__priamry_key__):
|
||||
query = "INSERT INTO %s (%s, %s) VALUES (?, %s)" % (
|
||||
cls.__table_name__,
|
||||
cls.__priamry_key__,
|
||||
', '.join("'%s'" % str(x) for x in cls.__fields__),
|
||||
', '.join(['?'] * len(cls.__fields__)))
|
||||
data = ()
|
||||
data = data + (kwargs.get(cls.__priamry_key__),)
|
||||
for f in cls.__fields__:
|
||||
if f in cls.__json_fields__:
|
||||
data = data + (json.dumps(kwargs.get(f)),)
|
||||
else:
|
||||
data = data + (kwargs.get(f),)
|
||||
else:
|
||||
|
||||
query = 'INSERT INTO %s (%s) VALUES (%s)' % (
|
||||
cls.__table_name__,
|
||||
', '.join("'%s'" % str(x) for x in cls.__fields__),
|
||||
', '.join(['?'] * len(cls.__fields__)))
|
||||
|
||||
data = ()
|
||||
for f in cls.__fields__:
|
||||
if f in cls.__json_fields__:
|
||||
data = data + (json.dumps(kwargs.get(f)),)
|
||||
else:
|
||||
data = data + (kwargs.get(f),)
|
||||
|
||||
|
||||
cur.execute(query, data)
|
||||
get_db().commit()
|
||||
i = cur.lastrowid
|
||||
kwargs["id"] = i
|
||||
|
||||
return cls(kwargs)
|
||||
|
||||
@classmethod
|
||||
def update(cls, **kwargs):
|
||||
cur = get_db().cursor()
|
||||
query = 'UPDATE %s SET %s WHERE %s = ?' % (
|
||||
cls.__table_name__,
|
||||
', '.join("'%s' = ?" % str(x) for x in cls.__fields__),cls.__priamry_key__)
|
||||
|
||||
data = ()
|
||||
for f in cls.__fields__:
|
||||
if f in cls.__json_fields__:
|
||||
data = data + (json.dumps(kwargs.get(f)),)
|
||||
else:
|
||||
data = data + (kwargs.get(f),)
|
||||
|
||||
data = data + (kwargs.get(cls.__priamry_key__),)
|
||||
cur.execute(query, data)
|
||||
get_db().commit()
|
||||
return cls(kwargs)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import sqlite3
|
||||
import os
|
||||
from modules import cbpi
|
||||
from db import get_db
|
||||
|
||||
def execute_file(curernt_version, data):
|
||||
if curernt_version >= data["version"]:
|
||||
cbpi.app.logger.info("SKIP DB FILE: %s" % data["file"])
|
||||
return
|
||||
try:
|
||||
with sqlite3.connect("craftbeerpi.db") as conn:
|
||||
with open('./update/%s' % data["file"], 'r') as f:
|
||||
d = f.read()
|
||||
sqlCommands = d.split(";")
|
||||
cur = conn.cursor()
|
||||
for s in sqlCommands:
|
||||
cur.execute(s)
|
||||
cur.execute("INSERT INTO schema_info (version,filename) values (?,?)", (data["version"], data["file"]))
|
||||
conn.commit()
|
||||
|
||||
except sqlite3.OperationalError as err:
|
||||
print "EXCEPT"
|
||||
print err
|
||||
|
||||
@cbpi.initalizer(order=-9999)
|
||||
def init(app=None):
|
||||
|
||||
with cbpi.app.app_context():
|
||||
conn = get_db()
|
||||
cur = conn.cursor()
|
||||
current_version = None
|
||||
try:
|
||||
cur.execute("SELECT max(version) as m FROM schema_info")
|
||||
m = cur.fetchone()
|
||||
current_version = m["m"]
|
||||
except:
|
||||
pass
|
||||
result = []
|
||||
for filename in os.listdir("./update"):
|
||||
if filename.endswith(".sql"):
|
||||
d = {"version": int(filename[:filename.index('_')]), "file": filename}
|
||||
result.append(d)
|
||||
execute_file(current_version, d)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
class Base(object):
|
||||
__dirty = False
|
||||
|
||||
@classmethod
|
||||
def init_global(cls):
|
||||
pass
|
||||
|
||||
def get_config_parameter(self, key, default_value):
|
||||
return self.api.get_config_parameter(key, default_value)
|
||||
|
||||
def sleep(self, seconds):
|
||||
self.api.socketio.sleep(seconds)
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def update(self, **kwds):
|
||||
pass
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
for a in kwds:
|
||||
super(Base, self).__setattr__(a, kwds.get(a))
|
||||
self.api = kwds.get("api")
|
||||
self.id = kwds.get("id")
|
||||
self.value = None
|
||||
self.__dirty = False
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
if name != "_Base__dirty":
|
||||
self.__dirty = True
|
||||
super(Base, self).__setattr__(name, value)
|
||||
else:
|
||||
super(Base, self).__setattr__(name, value)
|
||||
|
||||
|
||||
class SensorBase(Base):
|
||||
|
||||
last_value = 0
|
||||
|
||||
def init(self):
|
||||
print "INIT Base SENSOR"
|
||||
|
||||
def stop(self):
|
||||
print "STOP SENSOR"
|
||||
|
||||
def data_received(self, data):
|
||||
|
||||
|
||||
self.last_value = data
|
||||
self.api.receive_sensor_value(self.id, data)
|
||||
|
||||
def get_unit(self):
|
||||
if self.get_config_parameter("unit", "C") == "C":
|
||||
return "°C"
|
||||
else:
|
||||
return "°F"
|
||||
|
||||
def get_value(self):
|
||||
|
||||
return {"value": self.last_value, "unit": self.get_unit()}
|
||||
|
||||
class SensorActive(SensorBase):
|
||||
|
||||
__running = False
|
||||
|
||||
def is_running(self):
|
||||
|
||||
return self.__running
|
||||
|
||||
def init(self):
|
||||
self.__running = True
|
||||
|
||||
def stop(self):
|
||||
self.__running = False
|
||||
|
||||
|
||||
def execute(self):
|
||||
pass
|
||||
|
||||
|
||||
class SensorPassive(SensorBase):
|
||||
def init(self):
|
||||
print "INIT PASSIV SENSOR"
|
||||
pass
|
||||
|
||||
def read(self):
|
||||
return 0
|
||||
|
||||
|
||||
class ActorBase(Base):
|
||||
|
||||
def state(self):
|
||||
return 1
|
||||
|
||||
def set_power(self, power):
|
||||
pass
|
||||
|
||||
def on(self, power=0):
|
||||
pass
|
||||
|
||||
def off(self):
|
||||
pass
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
import flask_login
|
||||
from modules.core.core import cbpi, addon
|
||||
|
||||
class User(flask_login.UserMixin):
|
||||
pass
|
||||
|
||||
@addon.core.initializer(order=0)
|
||||
def log(cbpi):
|
||||
|
||||
|
||||
cbpi._login_manager = flask_login.LoginManager()
|
||||
cbpi._login_manager.init_app(cbpi._app)
|
||||
@cbpi._app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
user = User()
|
||||
user.id = "manuel"
|
||||
flask_login.login_user(user)
|
||||
return "OK"
|
||||
|
||||
@cbpi._app.route('/logout')
|
||||
def logout():
|
||||
flask_login.logout_user()
|
||||
return 'Logged out'
|
||||
|
||||
@cbpi._login_manager.user_loader
|
||||
def user_loader(email):
|
||||
if email not in cbpi.cache["users"]:
|
||||
return
|
||||
|
||||
user = User()
|
||||
user.id = email
|
||||
return user
|
||||
|
||||
@cbpi._login_manager.unauthorized_handler
|
||||
def unauthorized_handler():
|
||||
return 'Unauthorized :-('
|
||||
Regular → Executable
+48
-68
@@ -1,68 +1,48 @@
|
||||
class PropertyType(object):
|
||||
pass
|
||||
|
||||
class Property(object):
|
||||
class Select(PropertyType):
|
||||
def __init__(self, label, options, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.options = options
|
||||
self.description = description
|
||||
|
||||
class Number(PropertyType):
|
||||
def __init__(self, label, configurable=False, default_value=None, unit="", description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = configurable
|
||||
self.default_value = default_value
|
||||
self.description = description
|
||||
|
||||
class Text(PropertyType):
|
||||
def __init__(self, label, configurable=False, default_value="", description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = configurable
|
||||
self.default_value = default_value
|
||||
self.description = description
|
||||
|
||||
class Actor(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
|
||||
class Sensor(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
|
||||
class Kettle(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
|
||||
|
||||
class StepProperty(Property):
|
||||
class Actor(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
class Sensor(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
class Kettle(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
class PropertyType(object):
|
||||
pass
|
||||
|
||||
class Property(object):
|
||||
class Select(PropertyType):
|
||||
def __init__(self, label, options, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.options = options
|
||||
self.description = description
|
||||
|
||||
class Number(PropertyType):
|
||||
def __init__(self, label, configurable=False, default_value=None, unit="", description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = configurable
|
||||
self.default_value = default_value
|
||||
self.description = description
|
||||
|
||||
class Text(PropertyType):
|
||||
def __init__(self, label, configurable=False, required=False, default_value="", description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.required = required
|
||||
self.configurable = configurable
|
||||
self.default_value = default_value
|
||||
self.description = description
|
||||
|
||||
class Actor(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
|
||||
class Sensor(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
|
||||
class Kettle(PropertyType):
|
||||
def __init__(self, label, description=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
Regular → Executable
-146
@@ -1,146 +0,0 @@
|
||||
from modules import cbpi
|
||||
from modules.core.props import StepProperty, Property
|
||||
import time
|
||||
|
||||
|
||||
class NotificationAPI(object):
|
||||
def notify(self, headline, message, type="success", timeout=5000):
|
||||
self.api.notify(headline, message, type, timeout)
|
||||
|
||||
class ActorAPI(NotificationAPI):
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def actor_on(self, id, power=100):
|
||||
self.api.switch_actor_on(int(id), power=power)
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def actor_off(self, id):
|
||||
self.api.switch_actor_off(int(id))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def actor_power(self, id, power):
|
||||
self.api.actor_power(int(id), power)
|
||||
|
||||
class SensorAPI(NotificationAPI):
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_sensor_value(self, id):
|
||||
return cbpi.get_sensor_value(id)
|
||||
|
||||
class KettleAPI(NotificationAPI):
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_kettle_temp(self, id=None):
|
||||
id = int(id)
|
||||
if id is None:
|
||||
id = self.kettle_id
|
||||
return cbpi.get_sensor_value(int(self.api.cache.get("kettle").get(id).sensor))
|
||||
|
||||
@cbpi.try_catch(None)
|
||||
def get_target_temp(self, id=None):
|
||||
id = int(id)
|
||||
if id is None:
|
||||
id = self.kettle_id
|
||||
return self.api.cache.get("kettle").get(id).target_temp
|
||||
|
||||
def set_target_temp(self, temp, id=None):
|
||||
temp = float(temp)
|
||||
|
||||
try:
|
||||
if id is None:
|
||||
self.api.emit_event("SET_TARGET_TEMP", id=self.kettle_id, temp=temp)
|
||||
else:
|
||||
self.api.emit_event("SET_TARGET_TEMP", id=id, temp=temp)
|
||||
except Exception as e:
|
||||
|
||||
self.notify("Faild to set Target Temp", "", type="warning")
|
||||
|
||||
class Timer(object):
|
||||
timer_end = Property.Number("TIMER_END", configurable=False)
|
||||
|
||||
def start_timer(self, timer):
|
||||
|
||||
if self.timer_end is not None:
|
||||
return
|
||||
self.timer_end = int(time.time()) + timer
|
||||
|
||||
|
||||
def stop_timer(self):
|
||||
if self.timer_end is not None:
|
||||
self.timer_end = None
|
||||
|
||||
def is_timer_running(self):
|
||||
if self.timer_end is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def timer_remaining(self):
|
||||
if self.timer_end is not None:
|
||||
return self.timer_end - int(time.time())
|
||||
else:
|
||||
return None
|
||||
|
||||
def is_timer_finished(self):
|
||||
if self.timer_end is None:
|
||||
return None
|
||||
if self.timer_end <= int(time.time()):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class StepBase(Timer, ActorAPI, SensorAPI, KettleAPI):
|
||||
|
||||
__dirty = False
|
||||
managed_fields = []
|
||||
n = False
|
||||
|
||||
def next(self):
|
||||
self.n = True
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def finish(self):
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
def execute(self):
|
||||
print "-------------"
|
||||
print "Step Info"
|
||||
print "Kettle ID: %s" % self.kettle_id
|
||||
print "ID: %s" % self.id
|
||||
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
|
||||
for a in kwds:
|
||||
|
||||
super(StepBase, self).__setattr__(a, kwds.get(a))
|
||||
|
||||
|
||||
self.api = kwds.get("api")
|
||||
self.id = kwds.get("id")
|
||||
self.name = kwds.get("name")
|
||||
self.kettle_id = kwds.get("kettleid")
|
||||
self.value = None
|
||||
self.__dirty = False
|
||||
|
||||
|
||||
def is_dirty(self):
|
||||
return self.__dirty
|
||||
|
||||
def reset_dirty(self):
|
||||
self.__dirty = False
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
if name != "_StepBase__dirty" and name in self.managed_fields:
|
||||
self.__dirty = True
|
||||
super(StepBase, self).__setattr__(name, value)
|
||||
else:
|
||||
super(StepBase, self).__setattr__(name, value)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user