- Refactoring

- Action Button with Parameter
- Actor Action with Parameter
- Sensor Action with Parameter
This commit is contained in:
Manuel83
2017-11-29 22:37:18 +01:00
parent 13836a5680
commit 9b7908c9c5
41 changed files with 8098 additions and 271 deletions
+62 -26
View File
@@ -22,6 +22,9 @@ class BaseAPI(object):
except:
doc = ""
if self.cbpi.cache.get(key) is None:
self.cbpi.cache[key] = {}
self.cbpi.logger.debug(name)
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("__")]
@@ -29,23 +32,39 @@ class BaseAPI(object):
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})
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, "unit": t.unit})
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):
elif isinstance(t, 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):
elif isinstance(t, 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):
elif isinstance(t, 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):
elif isinstance(t, 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})
parameters = method.__getattribute__("parameters")
props = []
if parameters is not None:
for k, t in parameters.iteritems():
if isinstance(t, Property.Number):
props.append({"name": k, "label": t.label, "type": "number", "configurable": t.configurable, "description": t.description, "default_value": t.default_value, "unit": t.unit})
elif isinstance(t, Property.Text):
props.append({"name": k, "label": t.label, "type": "text", "required": t.required, "configurable": t.configurable, "description": t.description, "default_value": t.default_value})
elif isinstance(t, Property.Select):
props.append({"name": k, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description})
elif isinstance(t, Property.Actor):
props.append({"name": k, "label": t.label, "type": "actor", "configurable": True, "description": t.description})
elif isinstance(t, Property.Sensor):
props.append({"name": k, "label": t.label, "type": "sensor", "configurable": True, "description": t.description})
elif isinstance(t, Property.Kettle):
props.append({"name": k, "label": t.label, "type": "kettle", "configurable": True, "description": t.description})
self.cbpi.cache.get(key)[name]["actions"].append({"method": method_name, "label": label, "properties":props })
return cls
@@ -59,9 +78,11 @@ class SensorAPI(BaseAPI):
return f
return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func):
func.action = True
func.parameters = parameters
func.label = label
return func
return real_decorator
@@ -80,10 +101,11 @@ class StepAPI(BaseAPI):
return f
return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func):
func.action = True
func.label = label
func.parameters = parameters
return func
return real_decorator
@@ -100,10 +122,11 @@ class ActorAPI(BaseAPI):
return f
return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func):
func.action = True
func.label = label
func.parameters = parameters
return func
return real_decorator
@@ -119,10 +142,11 @@ class KettleAPI(BaseAPI):
return f
return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func):
func.action = True
func.label = label
func.parameters = parameters
return func
return real_decorator
@@ -136,10 +160,11 @@ class FermenterAPI(BaseAPI):
return f
return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func):
func.action = True
func.label = label
func.parameters = parameters
return func
return real_decorator
@@ -156,7 +181,6 @@ class CoreAPI(BaseAPI):
self.cbpi.cache["web_menu"] =[]
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"):
@@ -168,12 +192,17 @@ class CoreAPI(BaseAPI):
try:
method(self.cbpi)
except Exception as e:
print e
self.cbpi._socketio.sleep(interval)
self.cbpi.logger.error(e)
self.cbpi.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"))
t = self.cbpi.start_background_task(target=job, interval=value.get("interval"), method=value.get("function"))
def action(self, **options):
def decorator(f):
BaseAPI.parseProps(self, "actions", f)
return f
return decorator
def add_js(self, name, file):
self.cbpi.cache["js"][name] = file
@@ -187,15 +216,7 @@ class CoreAPI(BaseAPI):
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 backgroundtask(self, key, interval, **options):
def decorator(f):
self.cbpi.cache.get("background").append({"function": f, "key": key, "interval": interval})
return f
@@ -220,5 +241,20 @@ class CoreAPI(BaseAPI):
class Buzzer(object):
def beep():
pass
def beep(self):
pass
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()
+7 -6
View File
@@ -12,11 +12,15 @@ class Base(object):
self.value = None
self.__dirty = False
class Action(Base):
def execute(self):
pass
class Actor(Base):
@classmethod
def init_global(cls):
pass
def init(self):
@@ -68,9 +72,6 @@ class Sensor(Base):
print "EXECUTE"
pass
class ControllerBase(object):
__dirty = False
__running = False
@@ -271,7 +272,6 @@ class Step(Base, Timer):
def set_target_temp(self, temp, id=None):
temp = float(temp)
try:
if id is None:
self.api.emit("SET_TARGET_TEMP", id=self.kettle_id, temp=temp)
@@ -281,7 +281,6 @@ class Step(Base, Timer):
self.api.notify("Faild to set Target Temp", "", type="warning")
def get_kettle_temp(self, id=None):
id = int(id)
if id is None:
@@ -294,6 +293,8 @@ class Step(Base, Timer):
def reset_dirty(self):
self.__dirty = False
def notify(self, headline, messsage, timeout=None):
self.api.notify(headline, messsage, timeout)
def __setattr__(self, name, value):
if name != "_StepBase__dirty" and name in self.managed_fields:
+4 -4
View File
@@ -2,10 +2,10 @@ from flask import request, json
from flask_classy import route, FlaskView
from flask_login import login_required
from modules.core.core import cbpi
from modules import cbpi
class BaseView(FlaskView):
class RestApi(FlaskView):
as_array = False
cache_key = None
@@ -39,7 +39,7 @@ class BaseView(FlaskView):
def post(self):
data = request.json
self.api._app.logger.info("INSERT Model %s", self.model.__name__)
self.api.web.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:
@@ -101,7 +101,7 @@ class BaseView(FlaskView):
@classmethod
def init_cache(cls):
with cls.api._app.app_context():
with cls.api.web.app_context():
if cls.model.__as_array__ is True:
cls.api.cache[cls.cache_key] = []
+53 -53
View File
@@ -22,7 +22,6 @@ 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):
@@ -33,31 +32,11 @@ class ComplexEncoder(json.JSONEncoder):
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"
@@ -82,8 +61,7 @@ class ActorCore(object):
actor.power = 100
self.cbpi.emit("INIT_ACTOR", id=id)
except Exception as e:
print e
self.cbpi._app.logger.error(e)
self.cbpi.web.logger.error(e)
def stop_one(self, id):
self.cbpi.cache["actors"][id]["instance"].stop()
@@ -99,7 +77,7 @@ class ActorCore(object):
self.cbpi.emit("SWITCH_ACTOR_ON", id=id, power=power)
return True
except Exception as e:
print e
self.cbpi.logger.error(e)
return False
def off(self, id):
@@ -111,7 +89,7 @@ class ActorCore(object):
self.cbpi.emit("SWITCH_ACTOR_OFF", id=id)
return True
except Exception as e:
print e
self.cbpi.logger.error(e)
return False
def toggle(self, id):
@@ -129,11 +107,11 @@ class ActorCore(object):
self.cbpi.emit("SWITCH_ACTOR_POWER_CHANGE", id=id, power=power)
return True
except Exception as e:
print e
self.cbpi.logger.error(e)
return False
def action(self, id, method):
self.cbpi.cache.get("actors").get(id).instance.__getattribute__(method)()
def action(self, id, method, **data):
self.cbpi.cache.get("actors").get(id).instance.__getattribute__(method)(**data)
def toggle_timeout(self, id, seconds):
@@ -182,7 +160,7 @@ class SensorCore(object):
except Exception as e:
print "ERROR"
self.cbpi._app.logger.error(e)
self.cbpi.web.logger.error(e)
def stop_one(self, id):
@@ -206,12 +184,12 @@ class SensorCore(object):
with open(filename, "a") as file:
file.write(msg)
def action(self, id, method):
self.cbpi.cache.get("sensors").get(id).instance.__getattribute__(method)()
def action(self, id, method, **data):
self.cbpi.cache.get("sensors").get(id).instance.__getattribute__(method)(**data)
class BrewingCore(object):
def __init__(self, cbpi):
self.cbpi = cbpi
self.cbpi.cache["step_types"] = {}
@@ -240,7 +218,7 @@ class BrewingCore(object):
# Start controller
if kettle.logic is not None:
cfg = kettle.config.copy()
cfg.update(dict(api=cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor))
cfg.update(dict(api=self.cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor))
instance = self.get_controller(kettle.logic).get("class")(**cfg)
instance.init()
kettle.instance = instance
@@ -250,13 +228,13 @@ class BrewingCore(object):
t = self.cbpi._socketio.start_background_task(target=run, instance=instance)
kettle.state = not kettle.state
self.cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
self.cbpi.ws_emit("UPDATE_KETTLE", self.cbpi.cache.get("kettle").get(id))
self.cbpi.emit("KETTLE_CONTROLLER_STARTED", id=id)
else:
# Stop controller
kettle.instance.stop()
kettle.state = not kettle.state
self.cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
self.cbpi.ws_emit("UPDATE_KETTLE", self.cbpi.cache.get("kettle").get(id))
self.cbpi.emit("KETTLE_CONTROLLER_STOPPED", id=id)
@@ -270,28 +248,50 @@ class FermentationCore(object):
return self.cbpi.cache["fermentation_controller_types"].get(name)
class Logger(object):
def __init__(self, cbpi):
self.cbpi = cbpi
def error(self, msg, *args, **kwargs):
self.cbpi.web.logger.error(msg, *args, **kwargs)
def info(self, msg, *args, **kwargs):
self.cbpi.web.logger.info(msg, *args, **kwargs)
def debug(self, msg, *args, **kwargs):
self.cbpi.web.logger.debug(msg, *args, **kwargs)
def warning(self, msg, *args, **kwargs):
self.cbpi.web.logger.warning(msg, *args, **kwargs)
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.cache["version"] = "3.1"
self.modules = {}
FORMAT = '%(asctime)-15s - %(levelname)s - %(message)s'
logging.basicConfig(filename='./logs/app.log', level=logging.INFO, format=FORMAT)
logging.getLogger('socketio').setLevel(logging.ERROR)
logging.getLogger('engineio').setLevel(logging.ERROR)
self.web = Flask(__name__)
self.logger = Logger(self)
self.logger.info("###Startup CraftBeerPi %s ###" % self.cache.get("version"))
self.web.secret_key = 'Cr4ftB33rP1'
self.web.json_encoder = ComplexEncoder
self._socketio = SocketIO(self.web, json=json, logging=False)
self.modules = {}
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('/')
@self.web.route('/')
def index():
return redirect('ui')
@@ -303,11 +303,11 @@ class CraftBeerPI(object):
self.actor.init()
self.beep()
try:
port = int(cbpi.get_config_parameter('port', '5000'))
port = int(self.get_config_parameter('port', '5000'))
except ValueError:
port = 5000
print port
self._socketio.run(self._app, host='0.0.0.0', port=port)
self._socketio.run(self.web, host='0.0.0.0', port=port)
def beep(self):
self.buzzer.beep()
@@ -315,6 +315,10 @@ class CraftBeerPI(object):
def sleep(self, seconds):
self._socketio.sleep(seconds)
def start_background_task(self, target, *args, **kwargs):
self._socketio.start_background_task(target, *args, **kwargs)
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)
@@ -324,10 +328,10 @@ class CraftBeerPI(object):
def __init_db(self, ):
with self._app.app_context():
with self.web.app_context():
db = self.get_db()
try:
with self._app.open_resource('../../config/schema.sql', mode='r') as f:
with self.web.open_resource('../../config/schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
except Exception as e:
@@ -373,7 +377,7 @@ class CraftBeerPI(object):
def set_config_parameter(self, name, value):
from modules.config import Config
with self._app.app_context():
with self.web.app_context():
update_data = {"name": name, "value": value}
self.cache.get("config")[name].__dict__.update(**update_data)
c = Config.update(**update_data)
@@ -381,7 +385,6 @@ class CraftBeerPI(object):
def emit(self, key, **kwargs):
if self.eventbus.get(key) is not None:
for value in self.eventbus[key]:
if value["async"] is False:
@@ -400,6 +403,3 @@ class CraftBeerPI(object):
self.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
cbpi = CraftBeerPI()
addon = cbpi.addon
+5 -6
View File
@@ -1,11 +1,11 @@
import sqlite3
import os
from modules.core.core import cbpi
from modules import cbpi
from modules.core.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"])
cbpi.web.logger.info("SKIP DB FILE: %s" % data["file"])
return
try:
with sqlite3.connect("craftbeerpi.db") as conn:
@@ -18,14 +18,13 @@ def execute_file(curernt_version, data):
cur.execute("INSERT INTO schema_info (version,filename) values (?,?)", (data["version"], data["file"]))
conn.commit()
except sqlite3.OperationalError as err:
print err
except sqlite3.OperationalError as e:
cbpi.logger.error(e)
@cbpi.addon.core.initializer(order=-9999)
def init(cbpi):
with cbpi._app.app_context():
with cbpi.web.app_context():
conn = get_db()
cur = conn.cursor()
current_version = None
+2
View File
@@ -16,6 +16,7 @@ class Property(object):
self.configurable = configurable
self.default_value = default_value
self.description = description
self.unit = unit
class Text(PropertyType):
def __init__(self, label, configurable=False, required=False, default_value="", description=""):
@@ -44,5 +45,6 @@ class Property(object):
def __init__(self, label, description=""):
PropertyType.__init__(self)
self.label = label
self.unit = ""
self.configurable = True
self.description = description
View File