mirror of
https://github.com/Manuel83/craftbeerpi3
synced 2026-08-09 18:52:40 +02:00
- Import KBH
- Import BeerXML - Import REST API - Migration DB - Set Default Screen after Start - Cleanup
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
3.0.1
|
||||
3.0.2
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -102,3 +102,5 @@ class Dummy(ActorBase):
|
||||
def off(self):
|
||||
print "OFF"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 "-------------"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import beerxml
|
||||
import kbh
|
||||
import restapi
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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
|
||||
|
||||
@@ -16,7 +16,7 @@ def getserial():
|
||||
|
||||
@cbpi.initalizer(order=9999)
|
||||
def sendStats(cbpi):
|
||||
print "INITIALIZE STATS"
|
||||
|
||||
try:
|
||||
serial = getserial()
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
Generated
+6006
File diff suppressed because it is too large
Load Diff
+43
-42
File diff suppressed because one or more lines are too long
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user