소스 검색

- Import KBH

- Import BeerXML
- Import REST API
- Migration DB
- Set Default Screen after Start
- Cleanup
tags/3.1_alpha
Manuel83 8 년 전
부모
커밋
291f09dcd1
30개의 변경된 파일6519개의 추가작업 그리고 120개의 파일을 삭제
  1. +1
    -1
      config/version.yaml
  2. +2
    -0
      modules/__init__.py
  3. +2
    -4
      modules/actor/__init__.py
  4. +2
    -2
      modules/addon/endpoints.py
  5. +1
    -1
      modules/base_plugins/brew_steps/__init__.py
  6. +2
    -0
      modules/base_plugins/gpio_actor/__init__.py
  7. +1
    -1
      modules/base_plugins/one_wire/__init__.py
  8. +2
    -4
      modules/config/__init__.py
  9. +15
    -15
      modules/core/baseview.py
  10. +14
    -3
      modules/core/core.py
  11. +47
    -0
      modules/core/db_mirgrate.py
  12. +6
    -6
      modules/core/hardware.py
  13. +5
    -5
      modules/core/step.py
  14. +7
    -6
      modules/fermenter/__init__.py
  15. +6
    -6
      modules/kettle/__init__.py
  16. +0
    -1
      modules/logs/endpoints.py
  17. +3
    -0
      modules/recipe_import/__init__.py
  18. +110
    -0
      modules/recipe_import/beerxml.py
  19. +109
    -0
      modules/recipe_import/kbh.py
  20. +62
    -0
      modules/recipe_import/restapi.py
  21. +5
    -5
      modules/sensors/__init__.py
  22. +1
    -1
      modules/stats/__init__.py
  23. +3
    -12
      modules/steps/__init__.py
  24. +40
    -2
      modules/system/endpoints.py
  25. +1
    -2
      modules/ui/endpoints.py
  26. +6006
    -0
      modules/ui/package-lock.json
  27. +43
    -42
      modules/ui/static/bundle.js
  28. +5
    -1
      modules/ui/static/index.html
  29. +18
    -0
      update/1_schema_info.sql
  30. +0
    -0
      update/empty

+ 1
- 1
config/version.yaml 파일 보기

@@ -1 +1 @@
3.0.1
3.0.2

+ 2
- 0
modules/__init__.py 파일 보기

@@ -35,6 +35,8 @@ import modules.system
import modules.buzzer
import modules.stats
import modules.kettle
import modules.recipe_import
import modules.core.db_mirgrate
from app_config import cbpi
# Build the database:
# This will create the database file using SQLAlchemy


+ 2
- 4
modules/actor/__init__.py 파일 보기

@@ -17,10 +17,10 @@ class ActorView(BaseView):
obj.state = 0
obj.power = 100

def post_post_callback(self, m):
def _post_post_callback(self, m):
self.api.init_actor(m.id)

def post_put_callback(self, m):
def _post_put_callback(self, m):

self.api.init_actor(m.id)

@@ -62,8 +62,6 @@ class ActorView(BaseView):

@cbpi.initalizer(order=1000)
def init(cbpi):
print "INITIALIZE ACTOR MODULE"
cbpi.app.logger.info("INITIALIZE ACTOR MODULE")
ActorView.register(cbpi.app, route_base='/api/actor')
ActorView.init_cache()
cbpi.init_actors()

+ 2
- 2
modules/addon/endpoints.py 파일 보기

@@ -188,11 +188,11 @@ def loadPlugins():

@cbpi.initalizer(order=1)
def initPlugins(app):
print "INITIALIZE CUSTOM PLUGINS"
loadCorePlugins()
loadPlugins()

@cbpi.initalizer(order=2)
def init(cbpi):
print "INITIALIZE ADDON MODULE"
cbpi.app.register_blueprint(blueprint, url_prefix='/api/editor')

+ 1
- 1
modules/base_plugins/brew_steps/__init__.py 파일 보기

@@ -50,7 +50,7 @@ class MashStep(StepBase):
'''

# Check if Target Temp is reached
if self.get_kettle_temp(self.kettle) >= int(self.temp):
if self.get_kettle_temp(self.kettle) >= float(self.temp):
# Check if Timer is Running
if self.is_timer_finished() is None:
self.start_timer(int(self.timer) * 60)


+ 2
- 0
modules/base_plugins/gpio_actor/__init__.py 파일 보기

@@ -102,3 +102,5 @@ class Dummy(ActorBase):
def off(self):
print "OFF"




+ 1
- 1
modules/base_plugins/one_wire/__init__.py 파일 보기

@@ -113,5 +113,5 @@ def set_temp(t):

@cbpi.initalizer()
def init(cbpi):
cbpi.app.logger.info("INITIALIZE ONE WIRE MODULE")
cbpi.app.register_blueprint(blueprint, url_prefix='/api/one_wire')

+ 2
- 4
modules/config/__init__.py 파일 보기

@@ -24,11 +24,9 @@ class ConfigView(BaseView):
update_data = {"name": data["name"], "value": data["value"]}

if self.api.cache.get(self.cache_key) is not None:
#self.pre_post_callback(self.api.cache.get(self.cache_key)[name])
print self.api.cache.get(self.cache_key)[name]
self.api.cache.get(self.cache_key)[name].__dict__.update(**update_data)
m = self.model.update(**self.api.cache.get(self.cache_key)[name].__dict__)
self.post_put_callback(self.api.cache.get(self.cache_key)[name])
self._post_put_callback(self.api.cache.get(self.cache_key)[name])
return json.dumps(self.api.cache.get(self.cache_key)[name].__dict__)

@route('/<id>', methods=["GET"])
@@ -54,6 +52,6 @@ class ConfigView(BaseView):

@cbpi.initalizer(order=1)
def init(cbpi):
print "INITIALIZE CONFIG MODULE"
ConfigView.register(cbpi.app, route_base='/api/config')
ConfigView.init_cache()

+ 15
- 15
modules/core/baseview.py 파일 보기

@@ -9,7 +9,7 @@ class BaseView(FlaskView):
cache_key = None
api = cbpi

@route('/<int:id>')
@route('/<int:id>', methods=["GET"])
def getOne(self, id):

if self.api.cache.get(self.cache_key) is not None:
@@ -17,36 +17,36 @@ class BaseView(FlaskView):
else:
return json.dumps(self.model.get_one(id))

@route('/')
@route('/', methods=["GET"])
def getAll(self):
if self.api.cache.get(self.cache_key) is not None:
return json.dumps(self.api.cache.get(self.cache_key))
else:
return json.dumps(self.model.get_all())

def pre_post_callback(self, data):
def _pre_post_callback(self, data):
pass


def post_post_callback(self, m):
def _post_post_callback(self, m):
pass

@route('/', methods=["POST"])
def post(self):
data = request.json
self.pre_post_callback(data)
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)
self._post_post_callback(m)

return json.dumps(m)

def pre_put_callback(self, m):
def _pre_put_callback(self, m):
pass

def post_put_callback(self, m):
def _post_put_callback(self, m):
pass


@@ -59,32 +59,32 @@ class BaseView(FlaskView):
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._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])
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)
self._post_put_callback(m)
return json.dumps(m)


def pre_delete_callback(self, m):
def _pre_delete_callback(self, m):
pass

def post_delete_callback(self, id):
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])
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):
def _post_delete_callback(self, id):
pass
return ('',204)



+ 14
- 3
modules/core/core.py 파일 보기

@@ -159,9 +159,8 @@ class SensorAPI(object):
def log_action(self, text):
filename = "./logs/action.log"
formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime())


with open(filename, "a") as file:
text = text.encode("utf-8")
file.write("%s,%s\n" % (formatted_time, text))

def shutdown_sensor(self, id):
@@ -243,6 +242,15 @@ class CraftBeerPi(ActorAPI, SensorAPI):
else:
return cfg.value

def set_config_parameter(self, name, value):
from modules.config import Config
with self.app.app_context():
update_data = {"name": name, "value": value}
self.cache.get("config")[name].__dict__.update(**update_data)
c = Config.update(**update_data)
self.emit("UPDATE_CONFIG", c)


def add_config_parameter(self, name, value, type, description, options=None):
from modules.config import Config
with self.app.app_context():
@@ -281,10 +289,13 @@ class CraftBeerPi(ActorAPI, SensorAPI):
def actor(self, cls):
return self.__parseProps("actor_types", cls)



def actor2(self, description="", power=True, **options):

def decorator(f):
print f()
print f
print options
print description
return f
@@ -458,7 +469,7 @@ class CraftBeerPi(ActorAPI, SensorAPI):
def job(interval, method):
while True:
try:
method()
method(self)
except Exception as e:
self.app.logger.error("Exception" + method.__name__ + ": " + str(e))
self.socketio.sleep(interval)


+ 47
- 0
modules/core/db_mirgrate.py 파일 보기

@@ -0,0 +1,47 @@
import sqlite3
import os
from modules import cbpi
from db import get_db

def execute_file(curernt_version, data):
if curernt_version >= data["version"]:
cbpi.app.logger.info("SKIP DB FILE: %s" % data["file"])
return
try:
with sqlite3.connect("craftbeerpi.db") as conn:
with open('./update/%s' % data["file"], 'r') as f:
d = f.read()
sqlCommands = d.split(";")
cur = conn.cursor()
for s in sqlCommands:
cur.execute(s)
cur.execute("INSERT INTO schema_info (version,filename) values (?,?)", (data["version"], data["file"]))
conn.commit()

except sqlite3.OperationalError as err:
print "EXCEPT"
print err

@cbpi.initalizer(order=-9999)
def init(app=None):

with cbpi.app.app_context():
conn = get_db()
cur = conn.cursor()
current_version = None
try:
cur.execute("SELECT max(version) as m FROM schema_info")
m = cur.fetchone()
current_version = m["m"]
except:
pass
result = []
for filename in os.listdir("./update"):
if filename.endswith(".sql"):
d = {"version": int(filename[:filename.index('_')]), "file": filename}
result.append(d)
execute_file(current_version, d)





+ 6
- 6
modules/core/hardware.py 파일 보기

@@ -5,7 +5,7 @@ class Base(object):

@classmethod
def init_global(cls):
print "GLOBAL ACTOR INIT"
pass

def get_config_parameter(self, key, default_value):
return self.api.get_config_parameter(key, default_value)
@@ -14,10 +14,10 @@ class Base(object):
self.api.socketio.sleep(seconds)

def init(self):
print "INIT BASE"
pass

def stop(self):
print "STOP HARDWARE"
pass

def update(self, **kwds):
pass
@@ -99,10 +99,10 @@ class ActorBase(Base):
return 1

def set_power(self, power):
print "SET POWER TO %s" % power
pass

def on(self, power=0):
print "ON"
pass

def off(self):
print "OFF"
pass

+ 5
- 5
modules/core/step.py 파일 보기

@@ -44,7 +44,7 @@ class KettleAPI(NotificationAPI):
return self.api.cache.get("kettle").get(id).target_temp

def set_target_temp(self, temp, id=None):
temp = int(temp)
temp = float(temp)

try:
if id is None:
@@ -59,7 +59,7 @@ class Timer(object):
timer_end = Property.Number("TIMER_END", configurable=False)

def start_timer(self, timer):
print "START TIMER NEW"
if self.timer_end is not None:
return
self.timer_end = int(time.time()) + timer
@@ -100,13 +100,13 @@ class StepBase(Timer, ActorAPI, SensorAPI, KettleAPI):
self.n = True

def init(self):
print "INIT STEP"
pass

def finish(self):
print "FINSIH STEP"
pass

def reset(self):
print "REST STEP"
pass

def execute(self):
print "-------------"


+ 7
- 6
modules/fermenter/__init__.py 파일 보기

@@ -63,18 +63,19 @@ class FermenterView(BaseView):
model = Fermenter
cache_key = "fermenter"

def post_post_callback(self, m):

def _post_post_callback(self, m):
m.state = False
m.steps = []

def pre_put_callback(self, m):
def _pre_put_callback(self, m):
m.state = False
try:
m.instance.stop()
except:
pass

def post_put_callback(self, m):
def _post_put_callback(self, m):
m.state = False

@route('/<int:id>/targettemp/<temp>', methods=['POST'])
@@ -282,7 +283,7 @@ class FermenterView(BaseView):


@cbpi.backgroundtask(key="read_target_temps_fermenter", interval=5)
def read_target_temps():
def read_target_temps(api):
"""
background process that reads all passive sensors in interval of 1 second
:return: None
@@ -295,7 +296,7 @@ def read_target_temps():
instance = FermenterView()

@cbpi.backgroundtask(key="fermentation_task", interval=1)
def execute_fermentation_step():
def execute_fermentation_step(api):
with cbpi.app.app_context():
instance.check_step()

@@ -310,6 +311,6 @@ def init_active_steps():

@cbpi.initalizer(order=1)
def init(cbpi):
print "INITIALIZE CONFIG MODULE"
FermenterView.register(cbpi.app, route_base='/api/fermenter')
FermenterView.init_cache()

+ 6
- 6
modules/kettle/__init__.py 파일 보기

@@ -15,7 +15,7 @@ class Kettle2View(BaseView):
cache_key = "kettle"

@classmethod
def pre_post_callback(self, data):
def _pre_post_callback(self, data):
data["target_temp"] = 0

@classmethod
@@ -23,16 +23,16 @@ class Kettle2View(BaseView):
obj.state = False


def post_post_callback(self, m):
def _post_post_callback(self, m):
m.state = False

def pre_put_callback(self, m):
def _pre_put_callback(self, m):
try:
m.instance.stop()
except:
pass

def post_put_callback(self, m):
def _post_put_callback(self, m):
m.state = False

@route('/<int:id>/targettemp/<temp>', methods=['POST'])
@@ -76,11 +76,11 @@ def set_target_temp(id, temp):
:param temp: target temp to set
:return: None
'''
print "GOT EVENT %s %s" % (id, temp)
Kettle2View().postTargetTemp(id,temp)

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


+ 0
- 1
modules/logs/endpoints.py 파일 보기

@@ -105,5 +105,4 @@ def init(app):
:param app: the flask app
:return: None
"""
print "INITIALIZE LOG MODULE"
LogView.register(cbpi.app, route_base='/api/logs')

+ 3
- 0
modules/recipe_import/__init__.py 파일 보기

@@ -0,0 +1,3 @@
import beerxml
import kbh
import restapi

+ 110
- 0
modules/recipe_import/beerxml.py 파일 보기

@@ -0,0 +1,110 @@
from flask import json, request
from flask_classy import FlaskView, route
from git import Repo, Git
import sqlite3
from modules.app_config import cbpi
from werkzeug.utils import secure_filename
import pprint
import time
import os
from modules.steps import Step,StepView
import xml.etree.ElementTree


class BeerXMLImport(FlaskView):

BEER_XML_FILE = "./upload/beer.xml"

@route('/', methods=['GET'])
def get(self):
if not os.path.exists(self.BEER_XML_FILE):
self.api.notify(headline="File Not Found", message="Please upload a Beer.xml File",
type="danger")
return ('', 404)

result = []
for idx, r in enumerate(self.getDict().get("RECIPES").get("RECIPE")):
result.append({"id": idx, "name": r.get("NAME")})
return json.dumps(result)


def allowed_file(self, filename):
return '.' in filename and filename.rsplit('.', 1)[1] in set(['xml'])

@route('/upload', methods=['POST'])
def upload_file(self):
try:
if request.method == 'POST':
file = request.files['file']
if file and self.allowed_file(file.filename):
file.save(os.path.join(self.api.app.config['UPLOAD_FOLDER'], "beer.xml"))
self.api.notify(headline="Upload Successful", message="The Beer XML file was uploaded succesfully")
return ('', 204)
return ('', 404)
except Exception as e:
self.api.notify(headline="Upload Failed", message="Failed to upload Beer xml", type="danger")
return ('', 500)

@route('/<int:id>', methods=['POST'])
def load(self, id):

recipe = self.getDict().get("RECIPES").get("RECIPE")[id]
steps = recipe.get("MASH",{}).get("MASH_STEPS",{}).get("MASH_STEP",[])
name = recipe.get("NAME")

self.api.set_config_parameter("brew_name", name)
boil_time = recipe.get("BOIL_TIME", 90)
mashstep_type = cbpi.get_config_parameter("step_mash", "MashStep")
mash_kettle = cbpi.get_config_parameter("step_mash_kettle", None)

boilstep_type = cbpi.get_config_parameter("step_boil", "BoilStep")
boil_kettle = cbpi.get_config_parameter("step_boil_kettle", None)
boil_temp = 100 if cbpi.get_config_parameter("unit", "C") == "C" else 212

# READ KBH DATABASE
Step.delete_all()
StepView().reset()

conn = None
try:
conn = sqlite3.connect(self.api.app.config['UPLOAD_FOLDER'] + '/kbh.db')
c = conn.cursor()
for row in steps:
Step.insert(**{"name": row.get("NAME"), "type": mashstep_type, "config": {"kettle": mash_kettle, "temp": float(row.get("STEP_TEMP")), "timer": row.get("STEP_TIME")}})
Step.insert(**{"name": "ChilStep", "type": "ChilStep", "config": {"timer": 15}})
## Add cooking step
Step.insert(**{"name": "Boil", "type": boilstep_type, "config": {"kettle": boil_kettle, "temp": boil_temp, "timer": boil_time}})
## Add Whirlpool step
Step.insert(**{"name": "Whirlpool", "type": "ChilStep", "config": {"timer": 15}})
# setBrewName(name)
self.api.emit("UPDATE_ALL_STEPS", Step.get_all())
self.api.notify(headline="Recipe %s loaded successfully" % name, message="")
except Exception as e:
self.api.notify(headline="Failed to load Recipe", message=e.message, type="danger")
return ('', 500)
finally:
if conn:
conn.close()
return ('', 204)


def getDict(self):
'''
Beer XML file to dict
:return: beer.xml file as dict
'''
try:
import xmltodict
with open(self.BEER_XML_FILE) as fd:
doc = xmltodict.parse(fd.read())
return doc
except:
self.api.notify(headline="Failed to load Beer.xml", message="Please check if you uploaded an beer.xml", type="danger")



@cbpi.initalizer()
def init(cbpi):

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

+ 109
- 0
modules/recipe_import/kbh.py 파일 보기

@@ -0,0 +1,109 @@
from flask import json, request
from flask_classy import FlaskView, route
from git import Repo, Git
import sqlite3
from modules.app_config import cbpi
from werkzeug.utils import secure_filename
import pprint
import time
import os
from modules.steps import Step, StepView


class KBH(FlaskView):

@route('/', methods=['GET'])
def get(self):
conn = None
try:
if not os.path.exists(self.api.app.config['UPLOAD_FOLDER'] + '/kbh.db'):
self.api.notify(headline="File Not Found", message="Please upload a Kleiner Brauhelfer Database", type="danger")
return ('', 404)

conn = sqlite3.connect(self.api.app.config['UPLOAD_FOLDER'] + '/kbh.db')
c = conn.cursor()
c.execute('SELECT ID, Sudname, BierWurdeGebraut FROM Sud')
data = c.fetchall()
result = []
for row in data:
result.append({"id": row[0], "name": row[1], "brewed": row[2]})
return json.dumps(result)
except Exception as e:
print e
self.api.notify(headline="Failed to load KHB database", message="ERROR", type="danger")
return ('', 500)
finally:
if conn:
conn.close()

def allowed_file(self, filename):
return '.' in filename and filename.rsplit('.', 1)[1] in set(['sqlite'])

@route('/upload', methods=['POST'])
def upload_file(self):
try:
if request.method == 'POST':
file = request.files['file']
if file and self.allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(self.api.app.config['UPLOAD_FOLDER'], "kbh.db"))
self.api.notify(headline="Upload Successful", message="The Kleiner Brauhelfer Database was uploaded succesfully")
return ('', 204)
return ('', 404)
except Exception as e:
self.api.notify(headline="Upload Failed", message="Failed to upload Kleiner Brauhelfer", type="danger")

return ('', 500)

@route('/<int:id>', methods=['POST'])
def load(self, id):
mashstep_type = cbpi.get_config_parameter("step_mash", "MashStep")
mashinstep_type = cbpi.get_config_parameter("step_mashin", "MashInStep")
chilstep_type = cbpi.get_config_parameter("step_chil", "ChilStep")
boilstep_type = cbpi.get_config_parameter("step_boil", "BoilStep")
mash_kettle = cbpi.get_config_parameter("step_mash_kettle", None)
boil_kettle = cbpi.get_config_parameter("step_boil_kettle", None)
boil_temp = 100 if cbpi.get_config_parameter("unit", "C") == "C" else 212

# READ KBH DATABASE
Step.delete_all()
StepView().reset()
conn = None
try:
conn = sqlite3.connect(self.api.app.config['UPLOAD_FOLDER'] + '/kbh.db')
c = conn.cursor()
c.execute('SELECT EinmaischenTemp, Sudname FROM Sud WHERE ID = ?', (id,))
row = c.fetchone()
name = row[1]

self.api.set_config_parameter("brew_name", name)
Step.insert(**{"name": "MashIn", "type": mashinstep_type, "config": {"kettle": mash_kettle, "temp": row[0]}})
### add rest step
for row in c.execute('SELECT * FROM Rasten WHERE SudID = ?', (id,)):
Step.insert(**{"name": row[5], "type": mashstep_type, "config": {"kettle": mash_kettle, "temp": row[3], "timer": row[4]}})
Step.insert(**{"name": "Chil", "type": chilstep_type, "config": {"timer": 15}})
## Add cooking step
c.execute('SELECT max(Zeit) FROM Hopfengaben WHERE SudID = ?', (id,))
row = c.fetchone()
Step.insert(**{"name": "Boil", "type": boilstep_type, "config": {"kettle": boil_kettle, "temp": boil_temp, "timer": row[0]}})
## Add Whirlpool step
Step.insert(**{"name": "Whirlpool", "type": chilstep_type, "config": {"timer": 15}})

#setBrewName(name)
self.api.emit("UPDATE_ALL_STEPS", Step.get_all())
self.api.notify(headline="Recipe %s loaded successfully" % name, message="")
except Exception as e:
self.api.notify(headline="Failed to load Recipe", message=e.message, type="danger")
return ('', 500)
finally:
if conn:
conn.close()
return ('', 204)



@cbpi.initalizer()
def init(cbpi):

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

+ 62
- 0
modules/recipe_import/restapi.py 파일 보기

@@ -0,0 +1,62 @@
from flask import json, request
from flask_classy import FlaskView, route
from git import Repo, Git
import sqlite3
from modules.app_config import cbpi
from werkzeug.utils import secure_filename
import pprint
import time
import os
from modules.steps import Step,StepView
import xml.etree.ElementTree


class RESTImport(FlaskView):


@route('/', methods=['POST'])
def load(self):

try:
data = request.json

name = data.get("name", "No Name")

self.api.set_config_parameter("brew_name", name)
chilstep_type = cbpi.get_config_parameter("step_chil", "ChilStep")
mashstep_type = cbpi.get_config_parameter("step_mash", "MashStep")
mash_kettle = cbpi.get_config_parameter("step_mash_kettle", None)

boilstep_type = cbpi.get_config_parameter("step_boil", "BoilStep")
boil_kettle = cbpi.get_config_parameter("step_boil_kettle", None)
boil_temp = 100 if cbpi.get_config_parameter("unit", "C") == "C" else 212

# READ KBH DATABASE
Step.delete_all()
StepView().reset()


for step in data.get("steps"):
if step.get("type", None) == "MASH":
Step.insert(**{"name": step.get("name","Mash Step"), "type": mashstep_type, "config": {"kettle": mash_kettle, "temp": step.get("temp",0), "timer": step.get("timer",0)}})
elif step.get("type", None) == "CHIL":
Step.insert(**{"name": step.get("name","Chil"), "type": chilstep_type, "config": {"timer": step.get("timer")}})
elif step.get("type", None) == "BOIL":
Step.insert(**{"name": step.get("name", "Boil"), "type": boilstep_type, "config": {"kettle": boil_kettle, "timer": step.get("timer"), "temp": boil_temp}})
else:
pass

self.api.emit("UPDATE_ALL_STEPS", Step.get_all())
self.api.notify(headline="Recipe %s loaded successfully" % name, message="")
except Exception as e:
self.api.notify(headline="Failed to load Recipe", type="danger", message=str(e))
m = str(e.message)
return (str(e), 500)

return ('', 204)


@cbpi.initalizer()
def init(cbpi):
RESTImport.api = cbpi
RESTImport.register(cbpi.app, route_base='/api/recipe/import/v1')

+ 5
- 5
modules/sensors/__init__.py 파일 보기

@@ -13,26 +13,26 @@ class SensorView(BaseView):
cache_key = "sensors"


def post_post_callback(self, m):
def _post_post_callback(self, m):
cbpi.init_sensor(m.id)

def post_put_callback(self, m):
def _post_put_callback(self, m):
cbpi.stop_sensor(m.id)
cbpi.init_sensor(m.id)

def pre_delete_callback(self, m):
def _pre_delete_callback(self, m):
cbpi.stop_sensor(m.id)

@cbpi.initalizer(order=1000)
def init(cbpi):
print "INITIALIZE SENSOR MODULE"
SensorView.register(cbpi.app, route_base='/api/sensor')
SensorView.init_cache()
cbpi.init_sensors()


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


+ 1
- 1
modules/stats/__init__.py 파일 보기

@@ -16,7 +16,7 @@ def getserial():

@cbpi.initalizer(order=9999)
def sendStats(cbpi):
print "INITIALIZE STATS"
try:
serial = getserial()



+ 3
- 12
modules/steps/__init__.py 파일 보기

@@ -66,16 +66,14 @@ class Step(DBModel):

class StepView(BaseView):
model = Step
def pre_post_callback(self, data):
def _pre_post_callback(self, data):
order = self.model.get_max_order()
data["order"] = 1 if order is None else order + 1
data["state"] = "I"

@route('/sort', methods=["POST"])
def sort_steps(self):

Step.sort(request.json)

cbpi.emit("UPDATE_ALL_STEPS", self.model.get_all())
return ('', 204)

@@ -87,16 +85,12 @@ class StepView(BaseView):

@route('/action/<method>', methods=["POST"])
def action(self, method):

cbpi.cache["active_step"].__getattribute__(method)()

return ('', 204)

@route('/reset', methods=["POST"])
def reset(self):

self.model.reset_all_steps()
#db.session.commit()
self.stop_step()
cbpi.emit("UPDATE_ALL_STEPS", self.model.get_all())
return ('', 204)
@@ -133,7 +127,6 @@ class StepView(BaseView):
return ('', 204)

def init_step(self, step):

cbpi.log_action("Start Step %s" % step.name)
type_cfg = cbpi.cache.get("step_types").get(step.type)
if type_cfg is None:
@@ -146,7 +139,6 @@ class StepView(BaseView):
cfg.update(dict(name=step.name, api=cbpi, id=step.id, timer_end=None, managed_fields=get_manged_fields_as_array(type_cfg)))
instance = type_cfg.get("class")(**cfg)
instance.init()

# set step instance to ache
cbpi.cache["active_step"] = instance

@@ -204,7 +196,6 @@ def init_after_startup():
# step type not found. cant restart step
return

print "STEP SATE......", step.stepstate
cfg = step.stepstate.copy()
cfg.update(dict(api=cbpi, id=step.id, managed_fields=get_manged_fields_as_array(type_cfg)))
instance = type_cfg.get("class")(**cfg)
@@ -213,7 +204,7 @@ def init_after_startup():

@cbpi.initalizer(order=2000)
def init(cbpi):
print "INITIALIZE STEPS MODULE"
StepView.register(cbpi.app, route_base='/api/step')

def get_all():
@@ -225,7 +216,7 @@ def init(cbpi):
cbpi.add_cache_callback("steps", get_all)

@cbpi.backgroundtask(key="step_task", interval=0.1)
def execute_step():
def execute_step(api):
'''
Background job which executes the step
:return:


+ 40
- 2
modules/system/endpoints.py 파일 보기

@@ -1,4 +1,5 @@
from flask import json
import yaml
from flask import json, url_for, Response
from flask_classy import FlaskView, route
from git import Repo, Git
@@ -101,7 +102,44 @@ class SystemView(FlaskView):
def dump(self):
return json.dumps(cbpi.cache)
@route('/endpoints', methods=['GET'])
def endpoints(self):
import urllib
output = []
vf = self.api.app.view_functions
for f in self.api.app.view_functions:
print f
endpoints = {}
re = {
"swagger": "2.0",
"host": "",
"info": {
"description":"",
"version": "",
"title": "CraftBeerPi"
},
"schemes": ["http"],
"paths": endpoints}
for rule in self.api.app.url_map.iter_rules():
r = rule
endpoints[rule.rule] = {}
if "HEAD" in r.methods: r.methods.remove("HEAD")
if "OPTIONS" in r.methods: r.methods.remove("OPTIONS")
for m in rule.methods:
endpoints[rule.rule][m] = dict(summary="", description="", consumes=["application/json"],produces=["application/json"])
with open("config/version.yaml", 'r') as stream:
y = yaml.load(stream)
pprint.pprint(y)
pprint.pprint(re)
return Response(yaml.dump(re), mimetype='text/yaml')
@cbpi.initalizer()
def init(cbpi):
print "INITIALIZE SYSTEM MODULE"
SystemView.api = cbpi
SystemView.register(cbpi.app, route_base='/api/system')

+ 1
- 2
modules/ui/endpoints.py 파일 보기

@@ -5,13 +5,12 @@ react = Blueprint('react', __name__, template_folder='templates', static_folder=

@cbpi.initalizer(order=10)
def init(cbpi):
print "INITIALIZE UI"
cbpi.app.register_blueprint(react, url_prefix='/ui')




@react.route('/')
@react.route('/', methods=["GET"])
def index():
return react.send_static_file("index.html")



+ 6006
- 0
modules/ui/package-lock.json
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 43
- 42
modules/ui/static/bundle.js
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 5
- 1
modules/ui/static/index.html 파일 보기

@@ -52,11 +52,15 @@



/* Einschränken des sichtbaren Ausschnitts */



</style>
<title>CraftBeerPi 3.0</title>
</head>
<body>
<div id="root"></div>
<div id="root" ></div>
<script src="static/bundle.js" type="text/javascript"></script>
<!--
This HTML file is a template.


+ 18
- 0
update/1_schema_info.sql 파일 보기

@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS schema_info
(
id INTEGER PRIMARY KEY NOT NULL,
version INTEGER,
filename VARCHAR(80),
creation_data DEFAULT CURRENT_TIMESTAMP
);


INSERT OR IGNORE INTO config VALUES ('step_mashin', 'MashStep', 'step', 'Default MashIn Step type for import', NULL );
INSERT OR IGNORE INTO config VALUES ('step_mash', 'MashStep', 'step', 'Default Mash Step type for import', NULL);
INSERT OR IGNORE INTO config VALUES ('step_boil', 'BoilStep', 'step', 'Default Boil Step type for import', NULL);
INSERT OR IGNORE INTO config VALUES ('step_chil', 'ChilStep', 'step', 'Default Chil Step type for import', NULL);
INSERT OR IGNORE INTO config VALUES ('step_mash_kettle', 1, 'kettle', 'Default Mash Tun', NULL);
INSERT OR IGNORE INTO config VALUES ('step_boil_kettle', 1, 'kettle', 'Default Boil Tun ', NULL);




+ 0
- 0
update/empty 파일 보기


불러오는 중...
취소
저장