mirror of
https://github.com/Manuel83/craftbeerpi3
synced 2026-08-09 18:52:40 +02:00
First Version
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
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>')
|
||||
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('/')
|
||||
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
|
||||
@@ -0,0 +1,134 @@
|
||||
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))
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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):
|
||||
|
||||
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 k.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 k.heater is not None:
|
||||
self.actor_off(int(f.heater))
|
||||
|
||||
@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))
|
||||
|
||||
@@ -0,0 +1,452 @@
|
||||
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 flask_sqlalchemy import SQLAlchemy
|
||||
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 int(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 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"))
|
||||
@@ -0,0 +1,115 @@
|
||||
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'" % (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()
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
class Base(object):
|
||||
__dirty = False
|
||||
|
||||
@classmethod
|
||||
def init_global(cls):
|
||||
print "GLOBAL ACTOR INIT"
|
||||
|
||||
def get_config_parameter(self, key, default_value):
|
||||
return self.api.get_config_parameter(key, default_value)
|
||||
|
||||
def init(self):
|
||||
print "INIT BASE"
|
||||
|
||||
def stop(self):
|
||||
print "STOP HARDWARE"
|
||||
|
||||
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
|
||||
print "INIT ACTIVE SENSOR"
|
||||
|
||||
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):
|
||||
print "SET POWER TO %s" % power
|
||||
|
||||
def on(self, power=0):
|
||||
print "ON"
|
||||
|
||||
def off(self):
|
||||
print "OFF"
|
||||
@@ -0,0 +1,38 @@
|
||||
class PropertyType(object):
|
||||
pass
|
||||
|
||||
class Property(object):
|
||||
class Select(PropertyType):
|
||||
def __init__(self, label, options):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.options = options
|
||||
|
||||
class Number(PropertyType):
|
||||
def __init__(self, label, configurable=False, default_value=0, unit=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = configurable
|
||||
|
||||
class Text(PropertyType):
|
||||
def __init__(self, label, configurable=False, default_value=""):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = configurable
|
||||
|
||||
class StepProperty(Property):
|
||||
class Actor(PropertyType):
|
||||
def __init__(self, label):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
class Sensor(PropertyType):
|
||||
def __init__(self, label):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
class Kettle(PropertyType):
|
||||
def __init__(self, label):
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
@@ -0,0 +1,132 @@
|
||||
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))
|
||||
|
||||
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 = int(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 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):
|
||||
print "INIT STEP"
|
||||
|
||||
def finish(self):
|
||||
print "FINSIH STEP"
|
||||
|
||||
def reset(self):
|
||||
print "REST STEP"
|
||||
|
||||
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