mirror of
https://github.com/Manuel83/craftbeerpi3
synced 2026-08-09 18:52:40 +02:00
- Login Added. Default Password is „beer“
- Several UI Adjustments - still work in progress - New API Method to add custom JavaScript to CraftBeerPi - Global Action Buttons added - Register new Web Modules for complete custom UI
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import time
|
import time
|
||||||
from flask_classy import route
|
from flask_classy import route
|
||||||
|
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.core import cbpi
|
||||||
from modules.core.baseview import BaseView
|
from modules.core.baseview import BaseView
|
||||||
@@ -21,6 +23,7 @@ class ActorView(BaseView):
|
|||||||
def _post_put_callback(self, m):
|
def _post_put_callback(self, m):
|
||||||
self.api.actor.init_one(m.id)
|
self.api.actor.init_one(m.id)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route("<int:id>/switch/on", methods=["POST"])
|
@route("<int:id>/switch/on", methods=["POST"])
|
||||||
def on(self, id):
|
def on(self, id):
|
||||||
"""
|
"""
|
||||||
@@ -42,6 +45,7 @@ class ActorView(BaseView):
|
|||||||
self.api.actor.on(id)
|
self.api.actor.on(id)
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route("<int:id>/switch/off", methods=["POST"])
|
@route("<int:id>/switch/off", methods=["POST"])
|
||||||
def off(self, id):
|
def off(self, id):
|
||||||
"""
|
"""
|
||||||
@@ -63,6 +67,7 @@ class ActorView(BaseView):
|
|||||||
self.api.actor.off(id)
|
self.api.actor.off(id)
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route("<int:id>/power/<int:power>", methods=["POST"])
|
@route("<int:id>/power/<int:power>", methods=["POST"])
|
||||||
def power(self, id, power):
|
def power(self, id, power):
|
||||||
"""
|
"""
|
||||||
@@ -90,6 +95,7 @@ class ActorView(BaseView):
|
|||||||
self.api.actor.power(id, power)
|
self.api.actor.power(id, power)
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route("<int:id>/toggle", methods=["POST"])
|
@route("<int:id>/toggle", methods=["POST"])
|
||||||
def toggle(self, id):
|
def toggle(self, id):
|
||||||
"""
|
"""
|
||||||
@@ -108,10 +114,7 @@ class ActorView(BaseView):
|
|||||||
200:
|
200:
|
||||||
description: Actor toggled
|
description: Actor toggled
|
||||||
"""
|
"""
|
||||||
if self.api.cache.get("actors").get(id).state == 0:
|
cbpi.actor.toggle(id)
|
||||||
self.on(id)
|
|
||||||
else:
|
|
||||||
self.off(id)
|
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
def toggleTimeJob(self, id, t):
|
def toggleTimeJob(self, id, t):
|
||||||
@@ -121,6 +124,7 @@ class ActorView(BaseView):
|
|||||||
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))
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route("/<id>/toggle/<int:t>", methods=["POST"])
|
@route("/<id>/toggle/<int:t>", methods=["POST"])
|
||||||
def toggleTime(self, id, t):
|
def toggleTime(self, id, t):
|
||||||
"""
|
"""
|
||||||
@@ -145,9 +149,11 @@ class ActorView(BaseView):
|
|||||||
200:
|
200:
|
||||||
description: Actor toggled
|
description: Actor toggled
|
||||||
"""
|
"""
|
||||||
t = self.api._socketio.start_background_task(target=self.toggleTimeJob, id=id, t=t)
|
self.api.actor.toggle_timeout(id, t)
|
||||||
|
#t = self.api._socketio.start_background_task(target=self.toggleTimeJob, id=id, t=t)
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('<int:id>/action/<method>', methods=["POST"])
|
@route('<int:id>/action/<method>', methods=["POST"])
|
||||||
def action(self, id, method):
|
def action(self, id, method):
|
||||||
"""
|
"""
|
||||||
@@ -172,7 +178,8 @@ class ActorView(BaseView):
|
|||||||
200:
|
200:
|
||||||
description: Actor Action called
|
description: Actor Action called
|
||||||
"""
|
"""
|
||||||
cbpi.cache.get("actors").get(id).instance.__getattribute__(method)()
|
|
||||||
|
self.api.actor.action(id, method)
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ class Dummy(Actor):
|
|||||||
@cbpi.addon.kettle.controller()
|
@cbpi.addon.kettle.controller()
|
||||||
class MyController(KettleController):
|
class MyController(KettleController):
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while self.is_running():
|
while self.is_running():
|
||||||
print "HALLO"
|
print "HALLO"
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import os
|
||||||
|
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
from modules.core.basetypes import Actor, Sensor
|
from modules.core.basetypes import Actor, Sensor
|
||||||
from modules.core.core import cbpi
|
from modules.core.core import cbpi
|
||||||
from modules.core.proptypes import Property
|
from modules.core.proptypes import Property
|
||||||
@@ -33,4 +37,11 @@ class Dummy(Sensor):
|
|||||||
@cbpi.addon.core.action(key="clear", label="Clear all Logs")
|
@cbpi.addon.core.action(key="clear", label="Clear all Logs")
|
||||||
def woohoo(cbpi):
|
def woohoo(cbpi):
|
||||||
print "COOL"
|
print "COOL"
|
||||||
cbpi.notify(headline="HELLO WORLD",message="")
|
dir = "./logs"
|
||||||
|
test = os.listdir(dir)
|
||||||
|
|
||||||
|
for item in test:
|
||||||
|
|
||||||
|
if item.endswith(".log"):
|
||||||
|
os.remove(join(dir, item))
|
||||||
|
cbpi.notify(headline="Logs Deleted",message="All Logs Cleared")
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ from modules.core.proptypes import Property
|
|||||||
class Dummy(Step):
|
class Dummy(Step):
|
||||||
|
|
||||||
|
|
||||||
|
@cbpi.addon.step.action("WOHOO")
|
||||||
|
def myaction(self):
|
||||||
|
print "HALLO"
|
||||||
|
|
||||||
text = Property.Text(label="Text", configurable=True, description="WOHOOO")
|
text = Property.Text(label="Text", configurable=True, description="WOHOOO")
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ class StepAPI(BaseAPI):
|
|||||||
return func
|
return func
|
||||||
return real_decorator
|
return real_decorator
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ActorAPI(BaseAPI):
|
class ActorAPI(BaseAPI):
|
||||||
|
|
||||||
key = "actor_types"
|
key = "actor_types"
|
||||||
@@ -150,6 +153,8 @@ class CoreAPI(BaseAPI):
|
|||||||
self.cbpi.cache["init"] = []
|
self.cbpi.cache["init"] = []
|
||||||
self.cbpi.cache["js"] = {}
|
self.cbpi.cache["js"] = {}
|
||||||
self.cbpi.cache["background"] = []
|
self.cbpi.cache["background"] = []
|
||||||
|
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'])
|
||||||
@@ -173,6 +178,9 @@ class CoreAPI(BaseAPI):
|
|||||||
def add_js(self, name, file):
|
def add_js(self, name, file):
|
||||||
self.cbpi.cache["js"][name] = file
|
self.cbpi.cache["js"][name] = file
|
||||||
|
|
||||||
|
def add_menu_link(self, name, path):
|
||||||
|
self.cbpi.cache["web_menu"].append(dict(name=name, path=path))
|
||||||
|
|
||||||
def initializer(self, order=0, **options):
|
def initializer(self, order=0, **options):
|
||||||
def decorator(f):
|
def decorator(f):
|
||||||
self.cbpi.cache.get("init").append({"function": f, "order": order})
|
self.cbpi.cache.get("init").append({"function": f, "order": order})
|
||||||
|
|||||||
@@ -246,4 +246,5 @@ class Step(Base):
|
|||||||
self.__dirty = True
|
self.__dirty = True
|
||||||
super(Step, self).__setattr__(name, value)
|
super(Step, self).__setattr__(name, value)
|
||||||
else:
|
else:
|
||||||
super(Step, self).__setattr__(name, value)
|
super(Step, self).__setattr__(name, value)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from flask import request, json
|
from flask import request, json
|
||||||
from flask_classy import route, FlaskView
|
from flask_classy import route, FlaskView
|
||||||
|
from flask_login import login_required
|
||||||
|
|
||||||
from modules.core.core import cbpi
|
from modules.core.core import cbpi
|
||||||
|
|
||||||
|
|
||||||
@@ -9,6 +11,7 @@ class BaseView(FlaskView):
|
|||||||
cache_key = None
|
cache_key = None
|
||||||
api = cbpi
|
api = cbpi
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/<int:id>', methods=["GET"])
|
@route('/<int:id>', methods=["GET"])
|
||||||
def getOne(self, id):
|
def getOne(self, id):
|
||||||
if self.api.cache.get(self.cache_key) is not None:
|
if self.api.cache.get(self.cache_key) is not None:
|
||||||
@@ -16,6 +19,7 @@ class BaseView(FlaskView):
|
|||||||
else:
|
else:
|
||||||
return json.dumps(self.model.get_one(id))
|
return json.dumps(self.model.get_one(id))
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/', methods=["GET"])
|
@route('/', methods=["GET"])
|
||||||
def getAll(self):
|
def getAll(self):
|
||||||
if self.api.cache.get(self.cache_key) is not None:
|
if self.api.cache.get(self.cache_key) is not None:
|
||||||
@@ -30,6 +34,7 @@ class BaseView(FlaskView):
|
|||||||
def _post_post_callback(self, m):
|
def _post_post_callback(self, m):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/', methods=["POST"])
|
@route('/', methods=["POST"])
|
||||||
def post(self):
|
def post(self):
|
||||||
|
|
||||||
@@ -50,7 +55,7 @@ class BaseView(FlaskView):
|
|||||||
def _post_put_callback(self, m):
|
def _post_put_callback(self, m):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/<int:id>', methods=["PUT"])
|
@route('/<int:id>', methods=["PUT"])
|
||||||
def put(self, id):
|
def put(self, id):
|
||||||
data = request.json
|
data = request.json
|
||||||
@@ -78,6 +83,7 @@ class BaseView(FlaskView):
|
|||||||
def _post_delete_callback(self, id):
|
def _post_delete_callback(self, id):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/<int:id>', methods=["DELETE"])
|
@route('/<int:id>', methods=["DELETE"])
|
||||||
def delete(self, id):
|
def delete(self, id):
|
||||||
if self.api.cache.get(self.cache_key) is not None:
|
if self.api.cache.get(self.cache_key) is not None:
|
||||||
|
|||||||
+53
-1
@@ -7,6 +7,7 @@ from datetime import datetime
|
|||||||
from functools import wraps, update_wrapper
|
from functools import wraps, update_wrapper
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from time import localtime, strftime
|
from time import localtime, strftime
|
||||||
|
import time
|
||||||
|
|
||||||
from flask import Flask, redirect, json, g, make_response
|
from flask import Flask, redirect, json, g, make_response
|
||||||
from flask_socketio import SocketIO
|
from flask_socketio import SocketIO
|
||||||
@@ -17,6 +18,7 @@ from modules.core.basetypes import Sensor, Actor
|
|||||||
from modules.database.dbmodel import Kettle
|
from modules.database.dbmodel import Kettle
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ComplexEncoder(json.JSONEncoder):
|
class ComplexEncoder(json.JSONEncoder):
|
||||||
def default(self, obj):
|
def default(self, obj):
|
||||||
try:
|
try:
|
||||||
@@ -109,6 +111,12 @@ class ActorCore(object):
|
|||||||
print e
|
print e
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def toggle(self, id):
|
||||||
|
if self.cbpi.cache.get("actors").get(id).state == 0:
|
||||||
|
self.on(id)
|
||||||
|
else:
|
||||||
|
self.off(id)
|
||||||
|
|
||||||
def power(self, id, power):
|
def power(self, id, power):
|
||||||
try:
|
try:
|
||||||
actor = self.cbpi.cache["actors"].get(int(id))
|
actor = self.cbpi.cache["actors"].get(int(id))
|
||||||
@@ -121,6 +129,20 @@ class ActorCore(object):
|
|||||||
print e
|
print e
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def action(self, id, method):
|
||||||
|
self.cbpi.cache.get("actors").get(id).instance.__getattribute__(method)()
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_timeout(self, id, seconds):
|
||||||
|
|
||||||
|
def toggle( id, seconds):
|
||||||
|
self.cbpi.cache.get("actors").get(int(id)).timer = int(time.time()) + int(seconds)
|
||||||
|
self.toggle(int(id))
|
||||||
|
self.cbpi.sleep(seconds)
|
||||||
|
self.cbpi.cache.get("actors").get(int(id)).timer = None
|
||||||
|
self.toggle(int(id))
|
||||||
|
job = self.cbpi._socketio.start_background_task(target=toggle, id=id, seconds=seconds)
|
||||||
|
|
||||||
def get_state(self, actor_id):
|
def get_state(self, actor_id):
|
||||||
print actor_id
|
print actor_id
|
||||||
print self.cbpi
|
print self.cbpi
|
||||||
@@ -183,6 +205,10 @@ 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)()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BrewingCore(object):
|
class BrewingCore(object):
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
@@ -207,6 +233,32 @@ class BrewingCore(object):
|
|||||||
self.cbpi.emit("SET_KETTLE_TARGET_TEMP", id=id, temp=temp)
|
self.cbpi.emit("SET_KETTLE_TARGET_TEMP", id=id, temp=temp)
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_automatic(self, id):
|
||||||
|
kettle = self.cbpi.cache.get("kettle")[id]
|
||||||
|
if kettle.state is False:
|
||||||
|
# Start controller
|
||||||
|
if kettle.logic is not None:
|
||||||
|
cfg = kettle.config.copy()
|
||||||
|
cfg.update(dict(api=cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor))
|
||||||
|
instance = self.get_controller(kettle.logic).get("class")(**cfg)
|
||||||
|
instance.init()
|
||||||
|
kettle.instance = instance
|
||||||
|
|
||||||
|
def run(instance):
|
||||||
|
instance.run()
|
||||||
|
|
||||||
|
t = self.cbpi._socketio.start_background_task(target=run, instance=instance)
|
||||||
|
kettle.state = not kettle.state
|
||||||
|
self.cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
||||||
|
self.cbpi.emit("KETTLE_CONTROLLER_STARTED", id=id)
|
||||||
|
else:
|
||||||
|
# Stop controller
|
||||||
|
kettle.instance.stop()
|
||||||
|
kettle.state = not kettle.state
|
||||||
|
self.cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
||||||
|
self.cbpi.emit("KETTLE_CONTROLLER_STOPPED", id=id)
|
||||||
|
|
||||||
|
|
||||||
class FermentationCore(object):
|
class FermentationCore(object):
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
@@ -313,7 +365,7 @@ class CraftBeerPI(object):
|
|||||||
return cfg.value
|
return cfg.value
|
||||||
|
|
||||||
def emit(self, key, **kwargs):
|
def emit(self, key, **kwargs):
|
||||||
print 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:
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import sqlite3
|
||||||
|
import os
|
||||||
|
from modules.core.core import cbpi
|
||||||
|
from modules.core.db import get_db
|
||||||
|
|
||||||
|
def execute_file(curernt_version, data):
|
||||||
|
if curernt_version >= data["version"]:
|
||||||
|
cbpi._app.logger.info("SKIP DB FILE: %s" % data["file"])
|
||||||
|
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.addon.core.initializer(order=-9999)
|
||||||
|
def init(cbpi):
|
||||||
|
|
||||||
|
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"):
|
||||||
|
print filename
|
||||||
|
if filename.endswith(".sql"):
|
||||||
|
d = {"version": int(filename[:filename.index('_')]), "file": filename}
|
||||||
|
result.append(d)
|
||||||
|
execute_file(current_version, d)
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import flask_login
|
|
||||||
from modules.core.core import cbpi, addon
|
|
||||||
|
|
||||||
class User(flask_login.UserMixin):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@addon.core.initializer(order=0)
|
|
||||||
def log(cbpi):
|
|
||||||
|
|
||||||
|
|
||||||
cbpi._login_manager = flask_login.LoginManager()
|
|
||||||
cbpi._login_manager.init_app(cbpi._app)
|
|
||||||
@cbpi._app.route('/login', methods=['GET', 'POST'])
|
|
||||||
def login():
|
|
||||||
user = User()
|
|
||||||
user.id = "manuel"
|
|
||||||
flask_login.login_user(user)
|
|
||||||
return "OK"
|
|
||||||
|
|
||||||
@cbpi._app.route('/logout')
|
|
||||||
def logout():
|
|
||||||
flask_login.logout_user()
|
|
||||||
return 'Logged out'
|
|
||||||
|
|
||||||
@cbpi._login_manager.user_loader
|
|
||||||
def user_loader(email):
|
|
||||||
if email not in cbpi.cache["users"]:
|
|
||||||
return
|
|
||||||
|
|
||||||
user = User()
|
|
||||||
user.id = email
|
|
||||||
return user
|
|
||||||
|
|
||||||
@cbpi._login_manager.unauthorized_handler
|
|
||||||
def unauthorized_handler():
|
|
||||||
return 'Unauthorized :-('
|
|
||||||
@@ -214,39 +214,9 @@ class KettleView(BaseView):
|
|||||||
description: User created
|
description: User created
|
||||||
"""
|
"""
|
||||||
|
|
||||||
kettle = cbpi.cache.get("kettle")[id]
|
self.api.brewing.toggle_automatic(id)
|
||||||
if kettle.state is False:
|
|
||||||
# Start controller
|
|
||||||
if kettle.logic is not None:
|
|
||||||
cfg = kettle.config.copy()
|
|
||||||
cfg.update(dict(api=cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor))
|
|
||||||
instance = cbpi.brewing.get_controller(kettle.logic).get("class")(**cfg)
|
|
||||||
instance.init()
|
|
||||||
kettle.instance = instance
|
|
||||||
def run(instance):
|
|
||||||
instance.run()
|
|
||||||
t = self.api._socketio.start_background_task(target=run, instance=instance)
|
|
||||||
kettle.state = not kettle.state
|
|
||||||
cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
|
||||||
cbpi.emit("KETTLE_CONTROLLER_STARTED", id=id)
|
|
||||||
else:
|
|
||||||
# Stop controller
|
|
||||||
kettle.instance.stop()
|
|
||||||
kettle.state = not kettle.state
|
|
||||||
cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
|
||||||
cbpi.emit("KETTLE_CONTROLLER_STOPPED", id=id)
|
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
#@cbpi.event("SET_TARGET_TEMP")
|
|
||||||
def set_target_temp(id, temp):
|
|
||||||
'''
|
|
||||||
Change Taget Temp Event
|
|
||||||
:param id: kettle id
|
|
||||||
:param temp: target temp to set
|
|
||||||
:return: None
|
|
||||||
'''
|
|
||||||
KettleView().postTargetTemp(id, temp)
|
|
||||||
|
|
||||||
@cbpi.addon.core.backgroundjob(key="read_target_temps", interval=5)
|
@cbpi.addon.core.backgroundjob(key="read_target_temps", interval=5)
|
||||||
def read_target_temps(api):
|
def read_target_temps(api):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import flask_login
|
||||||
|
from flask import request
|
||||||
|
|
||||||
|
from modules.core.core import cbpi, addon
|
||||||
|
|
||||||
|
class User(flask_login.UserMixin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@addon.core.initializer(order=0)
|
||||||
|
def log(cbpi):
|
||||||
|
|
||||||
|
|
||||||
|
cbpi._login_manager = flask_login.LoginManager()
|
||||||
|
cbpi._login_manager.init_app(cbpi._app)
|
||||||
|
@cbpi._app.route('/login', methods=['POST'])
|
||||||
|
def login():
|
||||||
|
|
||||||
|
data = request.json
|
||||||
|
password = cbpi.get_config_parameter("password", None)
|
||||||
|
|
||||||
|
if password is None:
|
||||||
|
return ('',500)
|
||||||
|
|
||||||
|
if password == data.get("password",""):
|
||||||
|
user = User()
|
||||||
|
user.id = "craftbeerpi"
|
||||||
|
flask_login.login_user(user)
|
||||||
|
return ('',204)
|
||||||
|
else:
|
||||||
|
return ('',401)
|
||||||
|
|
||||||
|
|
||||||
|
@cbpi._app.route('/logout', methods=['POST'])
|
||||||
|
def logout():
|
||||||
|
flask_login.logout_user()
|
||||||
|
return 'Logged out'
|
||||||
|
|
||||||
|
@cbpi._login_manager.user_loader
|
||||||
|
def user_loader(user):
|
||||||
|
|
||||||
|
print cbpi.get_config_parameter("password_security", "NO")
|
||||||
|
print user
|
||||||
|
|
||||||
|
if cbpi.get_config_parameter("password_security", "NO") == "YES":
|
||||||
|
if user != "craftbeerpi":
|
||||||
|
return
|
||||||
|
user = User()
|
||||||
|
user.id = user
|
||||||
|
return user
|
||||||
|
else:
|
||||||
|
user = User()
|
||||||
|
user.id = user
|
||||||
|
return user
|
||||||
|
|
||||||
|
@cbpi._login_manager.unauthorized_handler
|
||||||
|
def unauthorized_handler():
|
||||||
|
return ('Please login',401)
|
||||||
@@ -34,7 +34,7 @@ class SensorView(BaseView):
|
|||||||
200:
|
200:
|
||||||
description: Sensor Action called
|
description: Sensor Action called
|
||||||
"""
|
"""
|
||||||
cbpi.cache.get("sensors").get(id).instance.__getattribute__(method)()
|
cbpi.sensor.action(id, method)
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
def _post_post_callback(self, m):
|
def _post_post_callback(self, m):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import yaml
|
import yaml
|
||||||
from flask import json, url_for, Response
|
from flask import json, url_for, Response
|
||||||
from flask_classy import FlaskView, route
|
from flask_classy import FlaskView, route
|
||||||
|
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.core.core import cbpi
|
||||||
import pprint
|
import pprint
|
||||||
@@ -13,6 +14,7 @@ class SystemView(FlaskView):
|
|||||||
from subprocess import call
|
from subprocess import call
|
||||||
call("halt")
|
call("halt")
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/shutdown', methods=['POST'])
|
@route('/shutdown', methods=['POST'])
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""
|
"""
|
||||||
@@ -33,6 +35,7 @@ class SystemView(FlaskView):
|
|||||||
from subprocess import call
|
from subprocess import call
|
||||||
call("reboot")
|
call("reboot")
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/reboot', methods=['POST'])
|
@route('/reboot', methods=['POST'])
|
||||||
def reboot(self):
|
def reboot(self):
|
||||||
"""
|
"""
|
||||||
@@ -47,6 +50,7 @@ class SystemView(FlaskView):
|
|||||||
self.doReboot()
|
self.doReboot()
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/tags/<name>', methods=['GET'])
|
@route('/tags/<name>', methods=['GET'])
|
||||||
def checkout_tag(self,name):
|
def checkout_tag(self,name):
|
||||||
repo = Repo('./')
|
repo = Repo('./')
|
||||||
@@ -58,6 +62,7 @@ class SystemView(FlaskView):
|
|||||||
cbpi.notify("Checkout successful", "Please restart the system")
|
cbpi.notify("Checkout successful", "Please restart the system")
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/git/status', methods=['GET'])
|
@route('/git/status', methods=['GET'])
|
||||||
def git_status(self):
|
def git_status(self):
|
||||||
"""
|
"""
|
||||||
@@ -92,6 +97,7 @@ class SystemView(FlaskView):
|
|||||||
return json.dumps({"tags": tags, "headcommit": str(repo.head.commit), "branchname": branch_name,
|
return json.dumps({"tags": tags, "headcommit": str(repo.head.commit), "branchname": branch_name,
|
||||||
"master": {"changes": changes}})
|
"master": {"changes": changes}})
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/check_update', methods=['GET'])
|
@route('/check_update', methods=['GET'])
|
||||||
def check_update(self):
|
def check_update(self):
|
||||||
"""
|
"""
|
||||||
@@ -114,6 +120,7 @@ class SystemView(FlaskView):
|
|||||||
|
|
||||||
return json.dumps(changes)
|
return json.dumps(changes)
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/git/pull', methods=['POST'])
|
@route('/git/pull', methods=['POST'])
|
||||||
def update(self):
|
def update(self):
|
||||||
"""
|
"""
|
||||||
@@ -131,6 +138,24 @@ class SystemView(FlaskView):
|
|||||||
cbpi.notify("Pull successful", "The lasted updated was downloaded. Please restart the system")
|
cbpi.notify("Pull successful", "The lasted updated was downloaded. Please restart the system")
|
||||||
return ('', 204)
|
return ('', 204)
|
||||||
|
|
||||||
|
@route('/connect', methods=['GET'])
|
||||||
|
def connect(self):
|
||||||
|
"""
|
||||||
|
Connect
|
||||||
|
---
|
||||||
|
tags:
|
||||||
|
- system
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: CraftBeerPi System Cache
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.api.get_config_parameter("setup", "YES") == "YES":
|
||||||
|
return json.dumps(dict(setup=True, loggedin= current_user.is_authenticated ))
|
||||||
|
else:
|
||||||
|
return json.dumps(dict(setup=False, loggedin= current_user.is_authenticated))
|
||||||
|
|
||||||
|
@login_required
|
||||||
@route('/dump', methods=['GET'])
|
@route('/dump', methods=['GET'])
|
||||||
def dump(self):
|
def dump(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+15
-6
@@ -1,4 +1,4 @@
|
|||||||
from flask import Blueprint
|
from flask import Blueprint,render_template
|
||||||
|
|
||||||
from modules.core.core import cbpi
|
from modules.core.core import cbpi
|
||||||
|
|
||||||
@@ -11,11 +11,20 @@ def init(cbpi):
|
|||||||
|
|
||||||
@react.route('/', methods=["GET"])
|
@react.route('/', methods=["GET"])
|
||||||
def index():
|
def index():
|
||||||
return react.send_static_file("index.html")
|
#return react.send_static_file("index.html")
|
||||||
|
|
||||||
|
js_files = []
|
||||||
|
for key, value in cbpi.cache["js"].iteritems():
|
||||||
|
js_files.append(value)
|
||||||
|
|
||||||
|
print js_files
|
||||||
|
return render_template('index.html', js_files=js_files)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@cbpi._app.errorhandler(404)
|
||||||
|
def page_not_found(e):
|
||||||
|
return render_template('404.html'), 404
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container-fluid {
|
.container-fluid {
|
||||||
padding-right: 5px;
|
|
||||||
padding-left: 5px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-48
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/ui/static/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/ui/static/css/font-awesome.min.css">
|
||||||
|
<link rel="stylesheet" href="/ui/static/bootstrap.dark.css">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Dosis:200,500" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
body, h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: 'Dosis', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<title>CraftBeerPi 3.1</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>CraftBeerPi - Page not Found!</h1>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="static/bootstrap.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>
|
||||||
|
|
||||||
|
body, h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: 'Dosis', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<title>CraftBeerPi 3.1</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root" ></div>
|
||||||
|
{% for file in js_files %}
|
||||||
|
|
||||||
|
<script src="{{ file }}" type="text/javascript"></script>
|
||||||
|
{% endfor %}
|
||||||
|
<script src="static/bundle.js" type="text/javascript"></script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -6,9 +6,11 @@ cbpi = CraftBeerPI()
|
|||||||
|
|
||||||
addon = cbpi.addon
|
addon = cbpi.addon
|
||||||
|
|
||||||
|
|
||||||
|
from modules.core.db_migrate import *
|
||||||
from modules.buzzer import *
|
from modules.buzzer import *
|
||||||
from modules.config import *
|
from modules.config import *
|
||||||
from modules.core.login import *
|
from modules.login import *
|
||||||
from modules.system import *
|
from modules.system import *
|
||||||
from modules.ui import *
|
from modules.ui import *
|
||||||
from modules.step import *
|
from modules.step import *
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
INSERT OR IGNORE INTO config VALUES ('password', 'beer', 'text', 'LoginPassword', NULL );
|
||||||
Reference in New Issue
Block a user