浏览代码

- Refactoring

- Action Button with Parameter
- Actor Action with Parameter
- Sensor Action with Parameter
core_refactoring
Manuel83 8 年前
父节点
当前提交
9b7908c9c5
共有 41 个文件被更改,包括 8098 次插入271 次删除
  1. +4
    -0
      modules/__init__.py
  2. +7
    -4
      modules/action/__init__.py
  3. +14
    -7
      modules/actor/__init__.py
  4. +31
    -9
      modules/base_plugins/actor.py
  5. +33
    -13
      modules/base_plugins/sensor.py
  6. +7
    -4
      modules/base_plugins/steps.py
  7. +5
    -5
      modules/buzzer/__init__.py
  8. +5
    -5
      modules/config/__init__.py
  9. +63
    -27
      modules/core/baseapi.py
  10. +7
    -6
      modules/core/basetypes.py
  11. +4
    -4
      modules/core/baseview.py
  12. +53
    -53
      modules/core/core.py
  13. +5
    -6
      modules/core/db_migrate.py
  14. +2
    -0
      modules/core/proptypes.py
  15. +0
    -0
      modules/core/step.py
  16. +3
    -3
      modules/example_plugins/WebViewJquery/__init__.py
  17. +3
    -3
      modules/example_plugins/WebViewReactJs/__init__.py
  18. +4
    -4
      modules/example_plugins/swagger/__init__.py
  19. +10
    -11
      modules/fermenter/__init__.py
  20. +5
    -5
      modules/kettle/__init__.py
  21. +24
    -7
      modules/login/__init__.py
  22. +2
    -2
      modules/logs/__init__.py
  23. +2
    -2
      modules/notification/__init__.py
  24. +3
    -3
      modules/plugin/__init__.py
  25. +4
    -4
      modules/recipe_book/__init__.py
  26. +3
    -3
      modules/recipe_import/beerxml.py
  27. +3
    -3
      modules/recipe_import/kbh.py
  28. +2
    -2
      modules/recipe_import/restapi.py
  29. +16
    -10
      modules/sensor/__init__.py
  30. +9
    -8
      modules/step/__init__.py
  31. +2
    -2
      modules/system/__init__.py
  32. +3
    -3
      modules/ui/__init__.py
  33. 二进制
      modules/ui/static/bg.jpg
  34. 二进制
      modules/ui/static/bg1.jpg
  35. 二进制
      modules/ui/static/bg2.jpg
  36. +7713
    -2
      modules/ui/static/bootstrap.dark.css
  37. +37
    -36
      modules/ui/static/bundle.js
  38. +6
    -0
      modules/ui/static/index.html
  39. +3
    -8
      modules/ui/templates/index.html
  40. +0
    -4
      name.py
  41. +1
    -3
      run.py

+ 4
- 0
modules/__init__.py 查看文件

@@ -0,0 +1,4 @@
from modules.core.core import CraftBeerPI, Addon

cbpi = CraftBeerPI()
cbpi.addon = Addon(cbpi)

+ 7
- 4
modules/action/__init__.py 查看文件

@@ -1,6 +1,8 @@
import json import json

from flask import request
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from modules.core.core import cbpi
from modules import cbpi


class ActionView(FlaskView): class ActionView(FlaskView):


@@ -15,9 +17,10 @@ class ActionView(FlaskView):
200: 200:
description: action invoked description: action invoked
""" """
data = request.json


self.cbpi.cache["actions"][action]["function"](self.cbpi)
obj = self.cbpi.cache["actions"][action]["class"](self.cbpi)
obj.execute(**data)
return ('',204) return ('',204)


@cbpi.addon.core.initializer() @cbpi.addon.core.initializer()
@@ -28,4 +31,4 @@ def init(cbpi):
:return: None :return: None
""" """
ActionView.cbpi = cbpi ActionView.cbpi = cbpi
ActionView.register(cbpi._app, route_base='/api/action')
ActionView.register(cbpi.web, route_base='/api/action')

+ 14
- 7
modules/actor/__init__.py 查看文件

@@ -1,14 +1,16 @@
import time import time
from flask import request
from flask_classy import route from flask_classy import route
from flask_login import login_required from flask_login import login_required
from modules.core.db import DBModel from modules.core.db import DBModel
from modules.core.core import cbpi
from modules.core.baseview import BaseView
from modules import cbpi
from modules.core.baseview import RestApi
from modules.database.dbmodel import Actor from modules.database.dbmodel import Actor
class ActorView(BaseView):
class ActorView(RestApi):
model = Actor model = Actor
cache_key = "actors" cache_key = "actors"
@@ -121,7 +123,7 @@ class ActorView(BaseView):
def toggleTimeJob(self, id, t): def toggleTimeJob(self, id, t):
self.api.cache.get("actors").get(int(id)).timer = int(time.time()) + int(t) self.api.cache.get("actors").get(int(id)).timer = int(time.time()) + int(t)
self.toggle(int(id)) self.toggle(int(id))
self.api._socketio.sleep(t)
self.api.sleep(t)
self.api.cache.get("actors").get(int(id)).timer = None self.api.cache.get("actors").get(int(id)).timer = None
self.toggle(int(id)) self.toggle(int(id))
@@ -179,13 +181,18 @@ class ActorView(BaseView):
200: 200:
description: Actor Action called description: Actor Action called
""" """
self.api.actor.action(id, method)
data = request.json
if data:
cbpi.actor.action(id, method, **data)
else:
cbpi.actor.action(id, method)
return ('', 204) return ('', 204)
@cbpi.addon.core.initializer(order=1000) @cbpi.addon.core.initializer(order=1000)
def init(cbpi): def init(cbpi):
ActorView.register(cbpi._app, route_base='/api/actor')
ActorView.register(cbpi.web, route_base='/api/actor')
ActorView.init_cache() ActorView.init_cache()
#cbpi.init_actors() #cbpi.init_actors()

+ 31
- 9
modules/base_plugins/actor.py 查看文件

@@ -1,15 +1,37 @@
from modules.core.baseapi import Buzzer from modules.core.baseapi import Buzzer
from modules.core.basetypes import Actor, KettleController, FermenterController from modules.core.basetypes import Actor, KettleController, FermenterController
from modules.core.core import cbpi
from modules import cbpi
from modules.core.proptypes import Property


@cbpi.addon.actor.type("Dummy Actor") @cbpi.addon.actor.type("Dummy Actor")
class Dummy(Actor): class Dummy(Actor):




@cbpi.addon.actor.action("WOHOO")
def myaction(self):
print "WOOHOO"
pass
# Decorator to create a parameter based action
@cbpi.addon.actor.action("Run until Temp reached", parameters={"t": Property.Text(label="Target Temp")})
def check_sensor_value(self, t=1):

def check(api, id, value):
'''
Background Prozess which checks the sensor value every second
:param api:
:param id:
:param value:
:return:
'''
while api.sensor.get_value(1) < value:
api.sleep(1)
api.actor.off(id)

target_value = int(t)

# Create notificaiton
self.api.notify(headline="Waiting", message="Waiting for temp %s" % target_value)
# Switch actor on
self.api.actor.on(self.id, 100)
# Start Background task
self.api.start_background_task(check, self.api, id=self.id, value=target_value)



def on(self, power=100): def on(self, power=100):
''' '''
@@ -17,11 +39,10 @@ class Dummy(Actor):
:param power: int value between 0 - 100 :param power: int value between 0 - 100
:return: :return:
''' '''
print "ON"
print "ID %s ON" % self.id


def off(self): def off(self):
print "OFF"

print "ID %s OFF" % self.id




@cbpi.addon.kettle.controller() @cbpi.addon.kettle.controller()
@@ -29,7 +50,7 @@ class MyController(KettleController):


def run(self): def run(self):
while self.is_running(): while self.is_running():
print "HALLO"


self.sleep(1) self.sleep(1)


@@ -49,6 +70,7 @@ def init(cbpi):


class MyBuzzer(Buzzer): class MyBuzzer(Buzzer):
def beep(self): def beep(self):
print "BEEEEEP"
pass pass


cbpi.buzzer = MyBuzzer() cbpi.buzzer = MyBuzzer()

+ 33
- 13
modules/base_plugins/sensor.py 查看文件

@@ -3,11 +3,12 @@ import os


from os.path import join from os.path import join


from modules.core.basetypes import Actor, Sensor
from modules.core.core import cbpi
from modules.core.basetypes import Actor, Sensor, Action
from modules import cbpi
from modules.core.proptypes import Property from modules.core.proptypes import Property
import random import random



@cbpi.addon.sensor.type("Dummy Sensor") @cbpi.addon.sensor.type("Dummy Sensor")
class Dummy(Sensor): class Dummy(Sensor):


@@ -21,10 +22,15 @@ class Dummy(Sensor):
else: else:
self.unit = "°F" self.unit = "°F"


@cbpi.addon.sensor.action("WOHOO")
def myaction(self):
@cbpi.addon.sensor.action(label="Set Dummy Temp", parameters={
"p1":Property.Select(label="Temp",options=[1,2,3]),

})
def myaction(self, p1):
self.text = p1
self.update_value(int(p1))



self.api.notify(headline="WOHOO", message="HALLO")


def execute(self): def execute(self):
while True: while True:
@@ -34,14 +40,28 @@ class Dummy(Sensor):
pass pass
self.api.sleep(5) self.api.sleep(5)


@cbpi.addon.core.action(key="clear", label="Clear all Logs")
def woohoo(cbpi):


dir = "./logs"
test = os.listdir(dir)
@cbpi.addon.core.action(name="Delete All Logs")
class ParameterAction(Action):

p1 = Property.Number("P1", configurable=True, description="Target Temperature of Mash Step", unit="C")
p2 = Property.Number("P2", configurable=True, description="Target Temperature of Mash Step", unit="C")


def execute(self, p1, p2, **kwargs):
for i in range(5):
cbpi.sleep(1)
cbpi.notify(headline="Woohoo", message="%s %s" % (p1, p2))


@cbpi.addon.core.action(name="Delete All Logs")
class DeleteAllLogs(Action):
def execute(self, **kwargs):
dir = "./logs"
test = os.listdir(dir)


for item in test:
for item in test:


if item.endswith(".log"):
os.remove(join(dir, item))
cbpi.notify(headline="Logs Deleted",message="All Logs Cleared")
if item.endswith(".log"):
os.remove(join(dir, item))
cbpi.notify(headline="Logs Deleted", message="All Logs Cleared")

+ 7
- 4
modules/base_plugins/steps.py 查看文件

@@ -1,5 +1,5 @@
from modules.core.basetypes import Step from modules.core.basetypes import Step
from modules.core.core import cbpi
from modules import cbpi
from modules.core.proptypes import Property from modules.core.proptypes import Property
import time import time


@@ -18,7 +18,7 @@ class Dummy(Step):
time = Property.Text(label="Text", configurable=True, description="WOHOOO") time = Property.Text(label="Text", configurable=True, description="WOHOOO")


def execute(self): def execute(self):
#print self.text
pass pass


def reset(self): def reset(self):
@@ -36,8 +36,8 @@ class MashStep(Step):
Just put the decorator @cbpi.step on top of a method Just put the decorator @cbpi.step on top of a method
''' '''
# Properties # Properties
temp = Property.Number("Temperature", configurable=True, description="Target Temperature of Mash Step")
kettle = Property.Kettle("Kettle", description="Kettle in which the mashing takes place")
temp = Property.Number("Temperature", configurable=True, description="Target Temperature of Mash Step", unit="C")
kettle = Property.Kettle("Kettle", description="Kettle in which the mashing takes place" )
timer = Property.Number("Timer in Minutes", configurable=True, description="Timer is started when the target temperature is reached") timer = Property.Number("Timer in Minutes", configurable=True, description="Timer is started when the target temperature is reached")


def init(self): def init(self):
@@ -79,6 +79,7 @@ class MashStep(Step):


# Check if timer finished and go to next step # Check if timer finished and go to next step
if self.is_timer_finished() == True: if self.is_timer_finished() == True:
self.api.beep()
self.notify("Mash Step Completed!", "Starting the next step", timeout=None) self.notify("Mash Step Completed!", "Starting the next step", timeout=None)
self.next() self.next()


@@ -243,3 +244,5 @@ class BoilStep(Step):
if self.is_timer_finished() == True: if self.is_timer_finished() == True:
self.notify("Boil Step Completed!", "Starting the next step", timeout=None) self.notify("Boil Step Completed!", "Starting the next step", timeout=None)
self.next() self.next()



+ 5
- 5
modules/buzzer/__init__.py 查看文件

@@ -2,7 +2,7 @@ import time
from thread import start_new_thread from thread import start_new_thread
from modules.core.baseapi import Buzzer from modules.core.baseapi import Buzzer
from modules.core.core import cbpi
from modules import cbpi
try: try:
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
@@ -16,19 +16,19 @@ class GPIOBuzzer(Buzzer):
def __init__(self, gpio): def __init__(self, gpio):
try: try:
cbpi._app.logger.info("INIT BUZZER NOW GPIO%s" % gpio)
cbpi.web.logger.info("INIT BUZZER NOW GPIO%s" % gpio)
self.gpio = int(gpio) self.gpio = int(gpio)
GPIO.setmode(GPIO.BCM) GPIO.setmode(GPIO.BCM)
GPIO.setup(self.gpio, GPIO.OUT) GPIO.setup(self.gpio, GPIO.OUT)
self.state = True self.state = True
cbpi._app.logger.info("BUZZER SETUP OK")
cbpi.web.logger.info("BUZZER SETUP OK")
except Exception as e: except Exception as e:
cbpi._app.logger.info("BUZZER EXCEPTION %s" % str(e))
cbpi.web.logger.info("BUZZER EXCEPTION %s" % str(e))
self.state = False self.state = False
def beep(self): def beep(self):
if self.state is False: if self.state is False:
cbpi._app.logger.error("BUZZER not working")
cbpi.web.logger.error("BUZZER not working")
return return
def play(sound): def play(sound):


+ 5
- 5
modules/config/__init__.py 查看文件

@@ -2,13 +2,13 @@ import time
from flask import json, request from flask import json, request
from flask_classy import route from flask_classy import route
from modules.core.core import cbpi
from modules import cbpi
from modules.core.db import DBModel from modules.core.db import DBModel
from modules.core.baseview import BaseView
from modules.core.baseview import RestApi
from modules.database.dbmodel import Config from modules.database.dbmodel import Config
class ConfigView(BaseView):
class ConfigView(RestApi):
model = Config model = Config
cache_key = "config" cache_key = "config"
@@ -77,7 +77,7 @@ class ConfigView(BaseView):
@classmethod @classmethod
def init_cache(cls): def init_cache(cls):
with cls.api._app.app_context():
with cls.api.web.app_context():
cls.api.cache[cls.cache_key] = {} cls.api.cache[cls.cache_key] = {}
for key, value in cls.model.get_all().iteritems(): for key, value in cls.model.get_all().iteritems():
cls.post_init_callback(value) cls.post_init_callback(value)
@@ -85,5 +85,5 @@ class ConfigView(BaseView):
@cbpi.addon.core.initializer(order=0) @cbpi.addon.core.initializer(order=0)
def init(cbpi): def init(cbpi):
ConfigView.register(cbpi._app, route_base='/api/config')
ConfigView.register(cbpi.web, route_base='/api/config')
ConfigView.init_cache() ConfigView.init_cache()

+ 63
- 27
modules/core/baseapi.py 查看文件

@@ -22,6 +22,9 @@ class BaseAPI(object):
except: except:
doc = "" 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] = {"name": name, "class": cls, "description":doc, "properties": [], "actions": []}
self.cbpi.cache.get(key)[name].update(options) 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("__")] 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) t = tmpObj.__getattribute__(m)
if isinstance(t, Property.Number): 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): 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}) 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}) 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}) 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}) 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}) 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(): for method_name, method in cls.__dict__.iteritems():
if hasattr(method, "action"): if hasattr(method, "action"):
label = method.__getattribute__("label") 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 return cls
@@ -59,9 +78,11 @@ class SensorAPI(BaseAPI):
return f return f
return decorator return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func): def real_decorator(func):
func.action = True func.action = True
func.parameters = parameters
func.label = label func.label = label
return func return func
return real_decorator return real_decorator
@@ -80,10 +101,11 @@ class StepAPI(BaseAPI):
return f return f
return decorator return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func): def real_decorator(func):
func.action = True func.action = True
func.label = label func.label = label
func.parameters = parameters
return func return func
return real_decorator return real_decorator
@@ -100,10 +122,11 @@ class ActorAPI(BaseAPI):
return f return f
return decorator return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func): def real_decorator(func):
func.action = True func.action = True
func.label = label func.label = label
func.parameters = parameters
return func return func
return real_decorator return real_decorator
@@ -119,10 +142,11 @@ class KettleAPI(BaseAPI):
return f return f
return decorator return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func): def real_decorator(func):
func.action = True func.action = True
func.label = label func.label = label
func.parameters = parameters
return func return func
return real_decorator return real_decorator
@@ -136,10 +160,11 @@ class FermenterAPI(BaseAPI):
return f return f
return decorator return decorator
def action(self, label):
def action(self, label, parameters=None):
def real_decorator(func): def real_decorator(func):
func.action = True func.action = True
func.label = label func.label = label
func.parameters = parameters
return func return func
return real_decorator return real_decorator
@@ -156,7 +181,6 @@ class CoreAPI(BaseAPI):
self.cbpi.cache["web_menu"] =[] self.cbpi.cache["web_menu"] =[]
def init(self): def init(self):
self.cbpi.cache["init"] = sorted(self.cbpi.cache["init"], key=lambda k: k['order']) self.cbpi.cache["init"] = sorted(self.cbpi.cache["init"], key=lambda k: k['order'])
for value in self.cbpi.cache.get("init"): for value in self.cbpi.cache.get("init"):
@@ -168,12 +192,17 @@ class CoreAPI(BaseAPI):
try: try:
method(self.cbpi) method(self.cbpi)
except Exception as e: 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"): 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): def add_js(self, name, file):
self.cbpi.cache["js"][name] = file self.cbpi.cache["js"][name] = file
@@ -187,15 +216,7 @@ class CoreAPI(BaseAPI):
return f return f
return decorator 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): def decorator(f):
self.cbpi.cache.get("background").append({"function": f, "key": key, "interval": interval}) self.cbpi.cache.get("background").append({"function": f, "key": key, "interval": interval})
return f return f
@@ -220,5 +241,20 @@ class CoreAPI(BaseAPI):
class Buzzer(object): 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
modules/core/basetypes.py 查看文件

@@ -12,11 +12,15 @@ class Base(object):
self.value = None self.value = None
self.__dirty = False self.__dirty = False
class Action(Base):
def execute(self):
pass
class Actor(Base): class Actor(Base):
@classmethod @classmethod
def init_global(cls): def init_global(cls):
pass pass
def init(self): def init(self):
@@ -68,9 +72,6 @@ class Sensor(Base):
print "EXECUTE" print "EXECUTE"
pass pass
class ControllerBase(object): class ControllerBase(object):
__dirty = False __dirty = False
__running = False __running = False
@@ -271,7 +272,6 @@ class Step(Base, Timer):
def set_target_temp(self, temp, id=None): def set_target_temp(self, temp, id=None):
temp = float(temp) temp = float(temp)
try: try:
if id is None: if id is None:
self.api.emit("SET_TARGET_TEMP", id=self.kettle_id, temp=temp) 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") self.api.notify("Faild to set Target Temp", "", type="warning")
def get_kettle_temp(self, id=None): def get_kettle_temp(self, id=None):
id = int(id) id = int(id)
if id is None: if id is None:
@@ -294,6 +293,8 @@ class Step(Base, Timer):
def reset_dirty(self): def reset_dirty(self):
self.__dirty = False self.__dirty = False
def notify(self, headline, messsage, timeout=None):
self.api.notify(headline, messsage, timeout)
def __setattr__(self, name, value): def __setattr__(self, name, value):
if name != "_StepBase__dirty" and name in self.managed_fields: if name != "_StepBase__dirty" and name in self.managed_fields:


+ 4
- 4
modules/core/baseview.py 查看文件

@@ -2,10 +2,10 @@ from flask import request, json
from flask_classy import route, FlaskView from flask_classy import route, FlaskView
from flask_login import login_required 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 as_array = False
cache_key = None cache_key = None
@@ -39,7 +39,7 @@ class BaseView(FlaskView):
def post(self): def post(self):
data = request.json 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) self._pre_post_callback(data)
m = self.model.insert(**data) m = self.model.insert(**data)
if self.api.cache.get(self.cache_key) is not None: if self.api.cache.get(self.cache_key) is not None:
@@ -101,7 +101,7 @@ class BaseView(FlaskView):
@classmethod @classmethod
def init_cache(cls): def init_cache(cls):
with cls.api._app.app_context():
with cls.api.web.app_context():
if cls.model.__as_array__ is True: if cls.model.__as_array__ is True:
cls.api.cache[cls.cache_key] = [] cls.api.cache[cls.cache_key] = []


+ 53
- 53
modules/core/core.py 查看文件

@@ -22,7 +22,6 @@ from modules.database.dbmodel import Kettle
class ComplexEncoder(json.JSONEncoder): class ComplexEncoder(json.JSONEncoder):
def default(self, obj): def default(self, obj):
try: try:
if isinstance(obj, DBModel): if isinstance(obj, DBModel):
return obj.__dict__ return obj.__dict__
elif isinstance(obj, Actor): elif isinstance(obj, Actor):
@@ -33,31 +32,11 @@ class ComplexEncoder(json.JSONEncoder):
return obj() return obj()
else: else:
return None return None
return None return None
except TypeError as e: except TypeError as e:
pass pass
return None 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): class ActorCore(object):
key = "actor_types" key = "actor_types"
@@ -82,8 +61,7 @@ class ActorCore(object):
actor.power = 100 actor.power = 100
self.cbpi.emit("INIT_ACTOR", id=id) self.cbpi.emit("INIT_ACTOR", id=id)
except Exception as e: except Exception as e:
print e
self.cbpi._app.logger.error(e)
self.cbpi.web.logger.error(e)
def stop_one(self, id): def stop_one(self, id):
self.cbpi.cache["actors"][id]["instance"].stop() self.cbpi.cache["actors"][id]["instance"].stop()
@@ -99,7 +77,7 @@ class ActorCore(object):
self.cbpi.emit("SWITCH_ACTOR_ON", id=id, power=power) self.cbpi.emit("SWITCH_ACTOR_ON", id=id, power=power)
return True return True
except Exception as e: except Exception as e:
print e
self.cbpi.logger.error(e)
return False return False
def off(self, id): def off(self, id):
@@ -111,7 +89,7 @@ class ActorCore(object):
self.cbpi.emit("SWITCH_ACTOR_OFF", id=id) self.cbpi.emit("SWITCH_ACTOR_OFF", id=id)
return True return True
except Exception as e: except Exception as e:
print e
self.cbpi.logger.error(e)
return False return False
def toggle(self, id): def toggle(self, id):
@@ -129,11 +107,11 @@ class ActorCore(object):
self.cbpi.emit("SWITCH_ACTOR_POWER_CHANGE", id=id, power=power) self.cbpi.emit("SWITCH_ACTOR_POWER_CHANGE", id=id, power=power)
return True return True
except Exception as e: except Exception as e:
print e
self.cbpi.logger.error(e)
return False 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): def toggle_timeout(self, id, seconds):
@@ -182,7 +160,7 @@ class SensorCore(object):
except Exception as e: except Exception as e:
print "ERROR" print "ERROR"
self.cbpi._app.logger.error(e)
self.cbpi.web.logger.error(e)
def stop_one(self, id): def stop_one(self, id):
@@ -206,12 +184,12 @@ class SensorCore(object):
with open(filename, "a") as file: with open(filename, "a") as file:
file.write(msg) 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): class BrewingCore(object):
def __init__(self, cbpi): def __init__(self, cbpi):
self.cbpi = cbpi self.cbpi = cbpi
self.cbpi.cache["step_types"] = {} self.cbpi.cache["step_types"] = {}
@@ -240,7 +218,7 @@ class BrewingCore(object):
# Start controller # Start controller
if kettle.logic is not None: if kettle.logic is not None:
cfg = kettle.config.copy() 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 = self.get_controller(kettle.logic).get("class")(**cfg)
instance.init() instance.init()
kettle.instance = instance kettle.instance = instance
@@ -250,13 +228,13 @@ class BrewingCore(object):
t = self.cbpi._socketio.start_background_task(target=run, instance=instance) t = self.cbpi._socketio.start_background_task(target=run, instance=instance)
kettle.state = not kettle.state 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) self.cbpi.emit("KETTLE_CONTROLLER_STARTED", id=id)
else: else:
# Stop controller # Stop controller
kettle.instance.stop() kettle.instance.stop()
kettle.state = not kettle.state 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) self.cbpi.emit("KETTLE_CONTROLLER_STOPPED", id=id)
@@ -270,28 +248,50 @@ class FermentationCore(object):
return self.cbpi.cache["fermentation_controller_types"].get(name) 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): class CraftBeerPI(object):
cache = {} cache = {}
eventbus = {} eventbus = {}
def __init__(self): 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["messages"] = []
self.cache["version"] = "3.1" 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.addon = Addon(self)
self.actor = ActorCore(self) self.actor = ActorCore(self)
self.sensor = SensorCore(self) self.sensor = SensorCore(self)
self.brewing = BrewingCore(self) self.brewing = BrewingCore(self)
self.fermentation = FermentationCore(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(): def index():
return redirect('ui') return redirect('ui')
@@ -303,11 +303,11 @@ class CraftBeerPI(object):
self.actor.init() self.actor.init()
self.beep() self.beep()
try: try:
port = int(cbpi.get_config_parameter('port', '5000'))
port = int(self.get_config_parameter('port', '5000'))
except ValueError: except ValueError:
port = 5000 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): def beep(self):
self.buzzer.beep() self.buzzer.beep()
@@ -315,6 +315,10 @@ class CraftBeerPI(object):
def sleep(self, seconds): def sleep(self, seconds):
self._socketio.sleep(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): def notify(self, headline, message, type="success", timeout=5000):
msg = {"id": str(uuid.uuid1()), "type": type, "headline": headline, "message": message, "timeout": timeout} msg = {"id": str(uuid.uuid1()), "type": type, "headline": headline, "message": message, "timeout": timeout}
self.ws_emit("NOTIFY", msg) self.ws_emit("NOTIFY", msg)
@@ -324,10 +328,10 @@ class CraftBeerPI(object):
def __init_db(self, ): def __init_db(self, ):
with self._app.app_context():
with self.web.app_context():
db = self.get_db() db = self.get_db()
try: 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.cursor().executescript(f.read())
db.commit() db.commit()
except Exception as e: except Exception as e:
@@ -373,7 +377,7 @@ class CraftBeerPI(object):
def set_config_parameter(self, name, value): def set_config_parameter(self, name, value):
from modules.config import Config from modules.config import Config
with self._app.app_context():
with self.web.app_context():
update_data = {"name": name, "value": value} update_data = {"name": name, "value": value}
self.cache.get("config")[name].__dict__.update(**update_data) self.cache.get("config")[name].__dict__.update(**update_data)
c = Config.update(**update_data) c = Config.update(**update_data)
@@ -381,7 +385,6 @@ class CraftBeerPI(object):
def emit(self, key, **kwargs): def emit(self, key, **kwargs):
if self.eventbus.get(key) is not None: if self.eventbus.get(key) is not None:
for value in self.eventbus[key]: for value in self.eventbus[key]:
if value["async"] is False: 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) self.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
cbpi = CraftBeerPI()
addon = cbpi.addon

+ 5
- 6
modules/core/db_migrate.py 查看文件

@@ -1,11 +1,11 @@
import sqlite3 import sqlite3
import os import os
from modules.core.core import cbpi
from modules import cbpi
from modules.core.db import get_db from modules.core.db import get_db


def execute_file(curernt_version, data): def execute_file(curernt_version, data):
if curernt_version >= data["version"]: 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 return
try: try:
with sqlite3.connect("craftbeerpi.db") as conn: 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"])) cur.execute("INSERT INTO schema_info (version,filename) values (?,?)", (data["version"], data["file"]))
conn.commit() conn.commit()


except sqlite3.OperationalError as err:

print err
except sqlite3.OperationalError as e:
cbpi.logger.error(e)


@cbpi.addon.core.initializer(order=-9999) @cbpi.addon.core.initializer(order=-9999)
def init(cbpi): def init(cbpi):


with cbpi._app.app_context():
with cbpi.web.app_context():
conn = get_db() conn = get_db()
cur = conn.cursor() cur = conn.cursor()
current_version = None current_version = None


+ 2
- 0
modules/core/proptypes.py 查看文件

@@ -16,6 +16,7 @@ class Property(object):
self.configurable = configurable self.configurable = configurable
self.default_value = default_value self.default_value = default_value
self.description = description self.description = description
self.unit = unit
class Text(PropertyType): class Text(PropertyType):
def __init__(self, label, configurable=False, required=False, default_value="", description=""): def __init__(self, label, configurable=False, required=False, default_value="", description=""):
@@ -44,5 +45,6 @@ class Property(object):
def __init__(self, label, description=""): def __init__(self, label, description=""):
PropertyType.__init__(self) PropertyType.__init__(self)
self.label = label self.label = label
self.unit = ""
self.configurable = True self.configurable = True
self.description = description self.description = description

+ 0
- 0
modules/core/step.py 查看文件


+ 3
- 3
modules/example_plugins/WebViewJquery/__init__.py 查看文件

@@ -1,11 +1,11 @@
from flask import Blueprint from flask import Blueprint


from modules.core.core import cbpi, addon
from modules import cbpi
from flask_swagger import swagger from flask_swagger import swagger
from flask import json from flask import json
from flask import Blueprint from flask import Blueprint


@addon.core.initializer(order=22)
@cbpi.addon.core.initializer(order=22)
def web(cbpi): def web(cbpi):


s = Blueprint('web_view', __name__, template_folder='templates', static_folder='static') s = Blueprint('web_view', __name__, template_folder='templates', static_folder='static')
@@ -16,4 +16,4 @@ def web(cbpi):




cbpi.addon.core.add_menu_link("JQuery View", "/web_view") cbpi.addon.core.add_menu_link("JQuery View", "/web_view")
cbpi._app.register_blueprint(s, url_prefix='/web_view')
cbpi.web.register_blueprint(s, url_prefix='/web_view')

+ 3
- 3
modules/example_plugins/WebViewReactJs/__init__.py 查看文件

@@ -1,11 +1,11 @@
from flask import Blueprint from flask import Blueprint


from modules.core.core import cbpi, addon
from modules import cbpi
from flask_swagger import swagger from flask_swagger import swagger
from flask import json from flask import json
from flask import Blueprint from flask import Blueprint


@addon.core.initializer(order=22)
@cbpi.addon.core.initializer(order=22)
def web(cbpi): def web(cbpi):


s = Blueprint('webviewreact', __name__, template_folder='templates', static_folder='static') s = Blueprint('webviewreact', __name__, template_folder='templates', static_folder='static')
@@ -16,4 +16,4 @@ def web(cbpi):




cbpi.addon.core.add_menu_link("ReactJS View", "/webviewreact") cbpi.addon.core.add_menu_link("ReactJS View", "/webviewreact")
cbpi._app.register_blueprint(s, url_prefix='/webviewreact')
cbpi.web.register_blueprint(s, url_prefix='/webviewreact')

+ 4
- 4
modules/example_plugins/swagger/__init__.py 查看文件

@@ -1,9 +1,9 @@
from modules.core.core import cbpi, addon
from modules import cbpi
from flask_swagger import swagger from flask_swagger import swagger
from flask import json from flask import json
from flask import Blueprint from flask import Blueprint
@addon.core.initializer(order=22)
@cbpi.addon.core.initializer(order=22)
def hello(cbpi): def hello(cbpi):
s = Blueprint('react', __name__, template_folder='templates', static_folder='static') s = Blueprint('react', __name__, template_folder='templates', static_folder='static')
@@ -14,10 +14,10 @@ def hello(cbpi):
@s.route('/swagger.json', methods=["GET"]) @s.route('/swagger.json', methods=["GET"])
def spec(): def spec():
swag = swagger(cbpi._app)
swag = swagger(cbpi.web)
swag['info']['version'] = "3.0" swag['info']['version'] = "3.0"
swag['info']['title'] = "CraftBeerPi" swag['info']['title'] = "CraftBeerPi"
return json.dumps(swag) return json.dumps(swag)
cbpi.addon.core.add_menu_link("Swagger API", "/swagger") cbpi.addon.core.add_menu_link("Swagger API", "/swagger")
cbpi._app.register_blueprint(s, url_prefix='/swagger')
cbpi.web.register_blueprint(s, url_prefix='/swagger')

+ 10
- 11
modules/fermenter/__init__.py 查看文件

@@ -2,13 +2,13 @@ import time
from flask import request from flask import request
from flask_classy import route from flask_classy import route


from modules.core.core import cbpi
from modules import cbpi
from modules.core.db import get_db, DBModel from modules.core.db import get_db, DBModel
from modules.core.baseview import BaseView
from modules.core.baseview import RestApi
from modules.database.dbmodel import Fermenter, FermenterStep from modules.database.dbmodel import Fermenter, FermenterStep




class FermenterView(BaseView):
class FermenterView(RestApi):
model = Fermenter model = Fermenter
cache_key = "fermenter" cache_key = "fermenter"


@@ -212,10 +212,9 @@ class FermenterView(BaseView):
cbpi.ws_emit("UPDATE_FERMENTER", cbpi.cache.get(self.cache_key)[id]) cbpi.ws_emit("UPDATE_FERMENTER", cbpi.cache.get(self.cache_key)[id])


def check_step(self): def check_step(self):
print "CHECK STEP"
print cbpi.cache["fermenter_task"]

for key, value in cbpi.cache["fermenter_task"].iteritems(): for key, value in cbpi.cache["fermenter_task"].iteritems():
print value
try: try:
fermenter = self.get_fermenter(key) fermenter = self.get_fermenter(key)
current_temp = current_temp = cbpi.sensor.get_value(int(fermenter.sensor)) current_temp = current_temp = cbpi.sensor.get_value(int(fermenter.sensor))
@@ -236,11 +235,11 @@ class FermenterView(BaseView):
else: else:
pass pass
except Exception as e: except Exception as e:
print e
self.api.looger.error(e)
pass pass




@cbpi.addon.core.backgroundjob(key="read_target_temps_fermenter", interval=5)
@cbpi.addon.core.backgroundtask(key="read_target_temps_fermenter", interval=5)
def read_target_temps(cbpi): def read_target_temps(cbpi):
""" """
background process that reads all passive sensors in interval of 1 second background process that reads all passive sensors in interval of 1 second
@@ -253,9 +252,9 @@ def read_target_temps(cbpi):


instance = FermenterView() instance = FermenterView()


@cbpi.addon.core.backgroundjob(key="fermentation_task", interval=1)
@cbpi.addon.core.backgroundtask(key="fermentation_task", interval=1)
def execute_fermentation_step(cbpi): def execute_fermentation_step(cbpi):
with cbpi._app.app_context():
with cbpi.web.app_context():
instance.check_step() instance.check_step()




@@ -268,5 +267,5 @@ def init_active_steps():
def init(cbpi): def init(cbpi):


cbpi.cache["fermenter_task"] = {} cbpi.cache["fermenter_task"] = {}
FermenterView.register(cbpi._app, route_base='/api/fermenter')
FermenterView.register(cbpi.web, route_base='/api/fermenter')
FermenterView.init_cache() FermenterView.init_cache()

+ 5
- 5
modules/kettle/__init__.py 查看文件

@@ -1,11 +1,11 @@
from flask import request from flask import request
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from modules.core.core import cbpi
from modules.core.baseview import BaseView
from modules import cbpi
from modules.core.baseview import RestApi
from modules.core.db import DBModel from modules.core.db import DBModel
from modules.database.dbmodel import Kettle from modules.database.dbmodel import Kettle
class KettleView(BaseView):
class KettleView(RestApi):
model = Kettle model = Kettle
cache_key = "kettle" cache_key = "kettle"
@@ -228,7 +228,7 @@ def set_target_temp(id, temp):
''' '''
KettleView().postTargetTemp(id,temp) KettleView().postTargetTemp(id,temp)
@cbpi.addon.core.backgroundjob(key="read_target_temps", interval=5)
@cbpi.addon.core.backgroundtask(key="read_target_temps", interval=5)
def read_target_temps(api): def read_target_temps(api):
""" """
background process that reads all passive sensors in interval of 1 second background process that reads all passive sensors in interval of 1 second
@@ -241,5 +241,5 @@ def read_target_temps(api):
@cbpi.addon.core.initializer() @cbpi.addon.core.initializer()
def init(cbpi): def init(cbpi):
KettleView.api = cbpi KettleView.api = cbpi
KettleView.register(cbpi._app, route_base='/api/kettle')
KettleView.register(cbpi.web, route_base='/api/kettle')
KettleView.init_cache() KettleView.init_cache()

+ 24
- 7
modules/login/__init__.py 查看文件

@@ -1,18 +1,19 @@
import flask_login import flask_login
from flask import request from flask import request


from modules.core.core import cbpi, addon
from modules import cbpi


class User(flask_login.UserMixin): class User(flask_login.UserMixin):
pass pass


@addon.core.initializer(order=0)
@cbpi.addon.core.initializer(order=0)
def log(cbpi): def log(cbpi):




cbpi._login_manager = flask_login.LoginManager() cbpi._login_manager = flask_login.LoginManager()
cbpi._login_manager.init_app(cbpi._app)
@cbpi._app.route('/login', methods=['POST'])
cbpi._login_manager.init_app(cbpi.web)

@cbpi.web.route('/login', methods=['POST'])
def login(): def login():


data = request.json data = request.json
@@ -30,15 +31,29 @@ def log(cbpi):
return ('',401) return ('',401)




@cbpi._app.route('/logout', methods=['POST'])
@cbpi.web.route('/logout', methods=['POST'])
def logout(): def logout():
flask_login.logout_user() flask_login.logout_user()
return 'Logged out' return 'Logged out'


@cbpi._login_manager.user_loader
def user_loader(user):
@cbpi._login_manager.request_loader
def load_user_from_request(request):




api_key = request.args.get('api_key')

if cbpi.get_config_parameter("password_security", "NO") == "NO":
user = User()
user.id = "craftbeerpi"
return user
elif api_key == "123":
user = User()
user.id = "craftbeerpi"
return user
return None

@cbpi._login_manager.user_loader
def user_loader(user):


if cbpi.get_config_parameter("password_security", "NO") == "YES": if cbpi.get_config_parameter("password_security", "NO") == "YES":
if user != "craftbeerpi": if user != "craftbeerpi":
@@ -53,4 +68,6 @@ def log(cbpi):


@cbpi._login_manager.unauthorized_handler @cbpi._login_manager.unauthorized_handler
def unauthorized_handler(): def unauthorized_handler():


return ('Please login',401) return ('Please login',401)

+ 2
- 2
modules/logs/__init__.py 查看文件

@@ -2,7 +2,7 @@ import datetime
import os import os
from flask import Blueprint, request, send_from_directory, json from flask import Blueprint, request, send_from_directory, json
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from modules.core.core import cbpi
from modules import cbpi
class LogView(FlaskView): class LogView(FlaskView):
@@ -172,4 +172,4 @@ def init(cbpi):
:param app: the flask app :param app: the flask app
:return: None :return: None
""" """
LogView.register(cbpi._app, route_base='/api/logs')
LogView.register(cbpi.web, route_base='/api/logs')

+ 2
- 2
modules/notification/__init__.py 查看文件

@@ -1,6 +1,6 @@
import json import json
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from modules.core.core import cbpi
from modules import cbpi


class NotificationView(FlaskView): class NotificationView(FlaskView):


@@ -63,4 +63,4 @@ def init(cbpi):
msg = {"id": len(cbpi.cache["messages"]), "type": "info", "headline": "Support CraftBeerPi with your donation", "message": "You will find the PayPay Donation button in the system menu" , "read": False} msg = {"id": len(cbpi.cache["messages"]), "type": "info", "headline": "Support CraftBeerPi with your donation", "message": "You will find the PayPay Donation button in the system menu" , "read": False}
cbpi.cache["messages"].append(msg) cbpi.cache["messages"].append(msg)


NotificationView.register(cbpi._app, route_base='/api/notification')
NotificationView.register(cbpi.web, route_base='/api/notification')

+ 3
- 3
modules/plugin/__init__.py 查看文件

@@ -1,7 +1,7 @@
import sys import sys
from flask import request, send_from_directory, json from flask import request, send_from_directory, json
from importlib import import_module from importlib import import_module
from modules.core.core import cbpi
from modules import cbpi
from git import Repo from git import Repo
import os import os
import requests import requests
@@ -46,7 +46,7 @@ class PluginView(FlaskView):
response = requests.get("https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins.yaml") response = requests.get("https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins.yaml")
self.api.cache["plugins"] = self.merge(yaml.load(response.text), self.api.cache["plugins"]) self.api.cache["plugins"] = self.merge(yaml.load(response.text), self.api.cache["plugins"])
for key, value in cbpi.cache["plugins"].iteritems(): for key, value in cbpi.cache["plugins"].iteritems():
print key
value["installed"] = os.path.isdir("./plugins/%s/" % (key)) value["installed"] = os.path.isdir("./plugins/%s/" % (key))
return json.dumps(cbpi.cache["plugins"]) return json.dumps(cbpi.cache["plugins"])
@@ -136,4 +136,4 @@ class PluginView(FlaskView):
def init(cbpi): def init(cbpi):
cbpi.cache["plugins"] = {} cbpi.cache["plugins"] = {}
PluginView.api = cbpi PluginView.api = cbpi
PluginView.register(cbpi._app, route_base='/api/plugin')
PluginView.register(cbpi.web, route_base='/api/plugin')

+ 4
- 4
modules/recipe_book/__init__.py 查看文件

@@ -7,8 +7,8 @@ from flask import json, request, send_from_directory
from flask_classy import route, FlaskView from flask_classy import route, FlaskView


from modules.core.db import DBModel from modules.core.db import DBModel
from modules.core.baseview import BaseView
from modules.core.core import cbpi
from modules.core.baseview import RestApi
from modules import cbpi
from modules.database.dbmodel import Step from modules.database.dbmodel import Step
from yaml import Loader, Dumper from yaml import Loader, Dumper
from yaml import load, dump from yaml import load, dump
@@ -59,7 +59,7 @@ class RecipeBook(FlaskView):
description: Log file downloaded description: Log file downloaded
""" """
file = "%s.json" % name file = "%s.json" % name
print file
if not self.check_filename(file): if not self.check_filename(file):
return ('File Not Found111', 404) return ('File Not Found111', 404)
return send_from_directory('../../recipes', file, as_attachment=True, attachment_filename=file) return send_from_directory('../../recipes', file, as_attachment=True, attachment_filename=file)
@@ -143,4 +143,4 @@ class RecipeBook(FlaskView):
@cbpi.addon.core.initializer(order=2000) @cbpi.addon.core.initializer(order=2000)
def init(cbpi): def init(cbpi):
RecipeBook.api = cbpi RecipeBook.api = cbpi
RecipeBook.register(cbpi._app, route_base='/api/recipebook')
RecipeBook.register(cbpi.web, route_base='/api/recipebook')

+ 3
- 3
modules/recipe_import/beerxml.py 查看文件

@@ -2,7 +2,7 @@ from flask import json, request
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from git import Repo, Git from git import Repo, Git
import sqlite3 import sqlite3
from modules.core.core import cbpi
from modules import cbpi
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import pprint import pprint
import time import time
@@ -60,7 +60,7 @@ class BeerXMLImport(FlaskView):
return ('', 204) return ('', 204)
return ('', 404) return ('', 404)
except Exception as e: except Exception as e:
print e
self.api.logger.error(e)
self.api.notify(headline="Upload Failed", message="Failed to upload Beer xml", type="danger") self.api.notify(headline="Upload Failed", message="Failed to upload Beer xml", type="danger")
return ('', 500) return ('', 500)


@@ -143,4 +143,4 @@ class BeerXMLImport(FlaskView):
def init(cbpi): def init(cbpi):


BeerXMLImport.api = cbpi BeerXMLImport.api = cbpi
BeerXMLImport.register(cbpi._app, route_base='/api/beerxml')
BeerXMLImport.register(cbpi.web, route_base='/api/beerxml')

+ 3
- 3
modules/recipe_import/kbh.py 查看文件

@@ -2,7 +2,7 @@ from flask import json, request
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from git import Repo, Git from git import Repo, Git
import sqlite3 import sqlite3
from modules.core.core import cbpi
from modules import cbpi
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import pprint import pprint
import time import time
@@ -39,7 +39,7 @@ class KBH(FlaskView):
result.append({"id": row[0], "name": row[1], "brewed": row[2]}) result.append({"id": row[0], "name": row[1], "brewed": row[2]})
return json.dumps(result) return json.dumps(result)
except Exception as e: except Exception as e:
print e
self.api.logger.error(e)
self.api.notify(headline="Failed to load KHB database", message="ERROR", type="danger") self.api.notify(headline="Failed to load KHB database", message="ERROR", type="danger")
return ('', 500) return ('', 500)
finally: finally:
@@ -143,4 +143,4 @@ class KBH(FlaskView):
def init(cbpi): def init(cbpi):


KBH.api = cbpi KBH.api = cbpi
KBH.register(cbpi._app, route_base='/api/kbh')
KBH.register(cbpi.web, route_base='/api/kbh')

+ 2
- 2
modules/recipe_import/restapi.py 查看文件

@@ -2,7 +2,7 @@ from flask import json, request
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from git import Repo, Git from git import Repo, Git
import sqlite3 import sqlite3
from modules.core.core import cbpi
from modules import cbpi
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import pprint import pprint
import time import time
@@ -59,4 +59,4 @@ class RESTImport(FlaskView):
@cbpi.addon.core.initializer() @cbpi.addon.core.initializer()
def init(cbpi): def init(cbpi):
RESTImport.api = cbpi RESTImport.api = cbpi
RESTImport.register(cbpi._app, route_base='/api/recipe/import/v1')
RESTImport.register(cbpi.web, route_base='/api/recipe/import/v1')

+ 16
- 10
modules/sensor/__init__.py 查看文件

@@ -1,12 +1,12 @@
import time import time
from flask_classy import route from flask_classy import route
from modules.core.core import cbpi
from modules import cbpi
from modules.core.db import DBModel from modules.core.db import DBModel
from modules.core.baseview import BaseView
from modules.core.baseview import RestApi
from modules.database.dbmodel import Sensor from modules.database.dbmodel import Sensor
from flask import request



class SensorView(BaseView):
class SensorView(RestApi):
model = Sensor model = Sensor
cache_key = "sensors" cache_key = "sensors"


@@ -34,7 +34,11 @@ class SensorView(BaseView):
200: 200:
description: Sensor Action called description: Sensor Action called
""" """
cbpi.sensor.action(id, method)
data = request.json
if data:
cbpi.sensor.action(id, method, **data)
else:
cbpi.sensor.action(id, method)
return ('', 204) return ('', 204)


def _post_post_callback(self, m): def _post_post_callback(self, m):
@@ -51,17 +55,19 @@ class SensorView(BaseView):
@cbpi.addon.core.initializer(order=1000) @cbpi.addon.core.initializer(order=1000)
def init(cbpi): def init(cbpi):


SensorView.register(cbpi._app, route_base='/api/sensor')
SensorView.register(cbpi.web, route_base='/api/sensor')
SensorView.init_cache() SensorView.init_cache()




#@cbpi.backgroundtask(key="read_passiv_sensor", interval=5)
#@cbpi.addon.core.backgroundtask(key="read_passiv_sensor", interval=5)
def read_passive_sensor(api): def read_passive_sensor(api):
""" """
background process that reads all passive sensors in interval of 1 second background process that reads all passive sensors in interval of 1 second
:return: None :return: None


""" """
for key, value in cbpi.cache.get("sensors").iteritems():
if value.mode == "P":
value.instance.read()


#for key, value in cbpi.cache.get("sensors").iteritems():
# if value.mode == "P":
# value.instance.read()

+ 9
- 8
modules/step/__init__.py 查看文件

@@ -3,12 +3,12 @@ from flask import json, request
from flask_classy import route from flask_classy import route
from modules.core.db import DBModel from modules.core.db import DBModel
from modules.core.baseview import BaseView
from modules.core.core import cbpi
from modules.core.baseview import RestApi
from modules import cbpi
from modules.database.dbmodel import Step from modules.database.dbmodel import Step
class StepView(BaseView):
class StepView(RestApi):
model = Step model = Step
def _pre_post_callback(self, data): def _pre_post_callback(self, data):
order = self.model.get_max_order() order = self.model.get_max_order()
@@ -207,24 +207,25 @@ def init_after_startup():
@cbpi.addon.core.initializer(order=2000) @cbpi.addon.core.initializer(order=2000)
def init(cbpi): def init(cbpi):
StepView.register(cbpi._app, route_base='/api/step')
StepView.register(cbpi.web, route_base='/api/step')
def get_all(): def get_all():
with cbpi._app.app_context():
with cbpi.web.app_context():
return Step.get_all() return Step.get_all()
with cbpi._app.app_context():
with cbpi.web.app_context():
init_after_startup() init_after_startup()
cbpi.add_cache_callback("steps", get_all) cbpi.add_cache_callback("steps", get_all)
@cbpi.addon.core.backgroundjob(key="step_task", interval=0.1)
@cbpi.addon.core.backgroundtask(key="step_task", interval=0.1)
def execute_step(api): def execute_step(api):
''' '''
Background job which executes the step Background job which executes the step
:return: :return:
''' '''
with cbpi._app.app_context():
with cbpi.web.app_context():
step = cbpi.cache.get("active_step") step = cbpi.cache.get("active_step")
if step is not None: if step is not None:
step.execute() step.execute()


+ 2
- 2
modules/system/__init__.py 查看文件

@@ -5,7 +5,7 @@ from flask import json, url_for, Response, request
from flask_classy import FlaskView, route from flask_classy import FlaskView, route
from flask_login import login_required, current_user from flask_login import login_required, current_user
from git import Repo, Git from git import Repo, Git
from modules.core.core import cbpi
from modules import cbpi
import pprint import pprint
import time import time
@@ -190,4 +190,4 @@ class SystemView(FlaskView):
def init(cbpi): def init(cbpi):
SystemView.api = cbpi SystemView.api = cbpi
SystemView.register(cbpi._app, route_base='/api/system')
SystemView.register(cbpi.web, route_base='/api/system')

+ 3
- 3
modules/ui/__init__.py 查看文件

@@ -1,12 +1,12 @@
from flask import Blueprint,render_template from flask import Blueprint,render_template


from modules.core.core import cbpi
from modules import cbpi


react = Blueprint('ui', __name__, template_folder='templates', static_folder='static') react = Blueprint('ui', __name__, template_folder='templates', static_folder='static')


@cbpi.addon.core.initializer(order=10) @cbpi.addon.core.initializer(order=10)
def init(cbpi): def init(cbpi):
cbpi._app.register_blueprint(react, url_prefix='/ui')
cbpi.web.register_blueprint(react, url_prefix='/ui')




@react.route('/', methods=["GET"]) @react.route('/', methods=["GET"])
@@ -22,7 +22,7 @@ def index():






@cbpi._app.errorhandler(404)
@cbpi.web.errorhandler(404)
def page_not_found(e): def page_not_found(e):
return render_template('404.html'), 404 return render_template('404.html'), 404




二进制
modules/ui/static/bg.jpg 查看文件

之前 之后
宽度: 1023  |  高度: 682  |  大小: 149KB

二进制
modules/ui/static/bg1.jpg 查看文件

之前 之后
宽度: 2506  |  高度: 2000  |  大小: 941KB

二进制
modules/ui/static/bg2.jpg 查看文件

之前 之后
宽度: 1300  |  高度: 866  |  大小: 313KB

+ 7713
- 2
modules/ui/static/bootstrap.dark.css
文件差异内容过多而无法显示
查看文件


+ 37
- 36
modules/ui/static/bundle.js
文件差异内容过多而无法显示
查看文件


+ 6
- 0
modules/ui/static/index.html 查看文件

@@ -10,11 +10,17 @@
<link rel="stylesheet" href="static/bootstrap.dark.css"> <link rel="stylesheet" href="static/bootstrap.dark.css">




<style>


html {
background-image: url('static/bg.png');
}
</style>
<title>CraftBeerPi 3.0</title> <title>CraftBeerPi 3.0</title>
</head> </head>
<body> <body>
<div id="root" ></div> <div id="root" ></div>
HALLO
<script src="static/bundle.js" type="text/javascript"></script> <script src="static/bundle.js" type="text/javascript"></script>






+ 3
- 8
modules/ui/templates/index.html 查看文件

@@ -7,18 +7,13 @@


<link rel="stylesheet" href="static/bootstrap.min.css"> <link rel="stylesheet" href="static/bootstrap.min.css">
<link rel="stylesheet" href="static/css/font-awesome.min.css"> <link rel="stylesheet" href="static/css/font-awesome.min.css">
<link rel="stylesheet" href="static/bootstrap.dark.css">
<link href="https://fonts.googleapis.com/css?family=Dosis:200,500" rel="stylesheet">
<style>
<link rel="stylesheet" href="static/theme.css">
<link href="https://fonts.googleapis.com/css?family=Dosis:200,500" rel="stylesheet"/>


body, h1, h2, h3, h4, h5, h6 {
font-family: 'Dosis', sans-serif;
}


</style>
<title>CraftBeerPi 3.1</title>




<title>CraftBeerPi 3.1</title>
</head> </head>
<body> <body>
<div id="root" ></div> <div id="root" ></div>


+ 0
- 4
name.py 查看文件

@@ -1,4 +0,0 @@
import re

recipe_name = "Manuel 8881881 18181 "
print re.match("^[\sA-Za-z0-9_-]*$", recipe_name)

+ 1
- 3
run.py 查看文件

@@ -1,10 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python


from modules.core.core import *


cbpi = CraftBeerPI()


addon = cbpi.addon
from modules import cbpi




from modules.core.db_migrate import * from modules.core.db_migrate import *


正在加载...
取消
保存