mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-25 16:38:36 +01:00
Added api path for recipe creation
- Added path parameter in config.json for settings - If empty, 'upload' will be used per default as api path - If something is entered, a different api path will be used for the creation of recipes. -> this allows the standard usage of the recipe upload and selection via cbpi4, but adds the possibility that custom plugins can be written to create cbpi recipe flows from the uploaded files ********************* + some prep work to create the http endpoints
This commit is contained in:
parent
40020ba64d
commit
b3d87bc027
7 changed files with 169 additions and 7 deletions
|
@ -20,6 +20,13 @@
|
||||||
"type": "kettle",
|
"type": "kettle",
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
|
"RECIPE_CREATION_PATH": {
|
||||||
|
"description": "API path to creation plugin. Default: empty",
|
||||||
|
"name": "RECIPE_CREATION_PATH",
|
||||||
|
"options": null,
|
||||||
|
"type": "string",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
"TEMP_UNIT": {
|
"TEMP_UNIT": {
|
||||||
"description": "Temperature Unit",
|
"description": "Temperature Unit",
|
||||||
"name": "TEMP_UNIT",
|
"name": "TEMP_UNIT",
|
||||||
|
|
|
@ -46,6 +46,7 @@ from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_system import SystemHttpEndpoints
|
from cbpi.http_endpoints.http_system import SystemHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_log import LogHttpEndpoints
|
from cbpi.http_endpoints.http_log import LogHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_notification import NotificationHttpEndpoints
|
from cbpi.http_endpoints.http_notification import NotificationHttpEndpoints
|
||||||
|
from cbpi.http_endpoints.http_upload import UploadHttpEndpoints
|
||||||
|
|
||||||
import shortuuid
|
import shortuuid
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -123,6 +124,8 @@ class CraftBeerPi:
|
||||||
self.http_system = SystemHttpEndpoints(self)
|
self.http_system = SystemHttpEndpoints(self)
|
||||||
self.http_log = LogHttpEndpoints(self)
|
self.http_log = LogHttpEndpoints(self)
|
||||||
self.http_notification = NotificationHttpEndpoints(self)
|
self.http_notification = NotificationHttpEndpoints(self)
|
||||||
|
self.http_upload = UploadHttpEndpoints(self)
|
||||||
|
|
||||||
|
|
||||||
self.login = Login(self)
|
self.login = Login(self)
|
||||||
|
|
||||||
|
@ -219,7 +222,6 @@ class CraftBeerPi:
|
||||||
contact="info@craftbeerpi.com")
|
contact="info@craftbeerpi.com")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def notify(self, title: str, message: str, type: NotificationType = NotificationType.INFO, action=[]) -> None:
|
def notify(self, title: str, message: str, type: NotificationType = NotificationType.INFO, action=[]) -> None:
|
||||||
self.notification.notify(title, message, type, action)
|
self.notification.notify(title, message, type, action)
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,12 @@ class RecipeUpload(CBPiExtension):
|
||||||
def allowed_file(self, filename, extension):
|
def allowed_file(self, filename, extension):
|
||||||
return '.' in filename and filename.rsplit('.', 1)[1] in set([extension])
|
return '.' in filename and filename.rsplit('.', 1)[1] in set([extension])
|
||||||
|
|
||||||
|
def get_creation_path(self):
|
||||||
|
creation_path = self.cbpi.config.get("RECIPE_CREATION_PATH", "upload")
|
||||||
|
path = {'path': 'upload'} if creation_path == '' else {'path': creation_path}
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path='/', method="POST", auth_required=False)
|
@request_mapping(path='/', method="POST", auth_required=False)
|
||||||
async def RecipeUpload(self, request):
|
async def RecipeUpload(self, request):
|
||||||
data = await request.post()
|
data = await request.post()
|
||||||
|
@ -123,6 +129,21 @@ class RecipeUpload(CBPiExtension):
|
||||||
await self.xml_recipe_creation(xml_id['id'])
|
await self.xml_recipe_creation(xml_id['id'])
|
||||||
return web.Response(status=200)
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
@request_mapping(path="/getpath", auth_required=False)
|
||||||
|
async def http_getpath(self, request):
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: get path for recipe creation
|
||||||
|
tags:
|
||||||
|
- Upload
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
return web.json_response(data=self.get_creation_path())
|
||||||
|
|
||||||
async def kbh_recipe_creation(self, Recipe_ID):
|
async def kbh_recipe_creation(self, Recipe_ID):
|
||||||
self.kettle = None
|
self.kettle = None
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,11 @@ from typing import KeysView
|
||||||
from cbpi.api.config import ConfigType
|
from cbpi.api.config import ConfigType
|
||||||
from cbpi.api.base import CBPiBase
|
from cbpi.api.base import CBPiBase
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
#import scipy.optimize
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@parameters([Property.Text(label="Notification",configurable = True, description = "Text for notification"),
|
@parameters([Property.Text(label="Notification",configurable = True, description = "Text for notification"),
|
||||||
Property.Select(label="AutoNext",options=["Yes","No"], description="Automatically move to next step (Yes) or pause after Notification (No)")])
|
Property.Select(label="AutoNext",options=["Yes","No"], description="Automatically move to next step (Yes) or pause after Notification (No)")])
|
||||||
class NotificationStep(CBPiStep):
|
class NotificationStep(CBPiStep):
|
||||||
|
@ -412,7 +414,7 @@ class CooldownStep(CBPiStep):
|
||||||
self.kettle = self.get_kettle(self.props.get("Kettle", None))
|
self.kettle = self.get_kettle(self.props.get("Kettle", None))
|
||||||
self.actor = self.props.get("Actor", None)
|
self.actor = self.props.get("Actor", None)
|
||||||
self.target_temp = int(self.props.get("Temp",0))
|
self.target_temp = int(self.props.get("Temp",0))
|
||||||
self.Interval = 10 # Interval in minutes on how often cooldwon end time is calculated
|
self.Interval = 15 # Interval in minutes on how often cooldwon end time is calculated
|
||||||
|
|
||||||
self.cbpi.notify(self.name, 'Cool down to {}°'.format(self.target_temp), NotificationType.INFO)
|
self.cbpi.notify(self.name, 'Cool down to {}°'.format(self.target_temp), NotificationType.INFO)
|
||||||
if self.timer is None:
|
if self.timer is None:
|
||||||
|
@ -422,6 +424,7 @@ class CooldownStep(CBPiStep):
|
||||||
self.time_array.append(time.time())
|
self.time_array.append(time.time())
|
||||||
self.next_check = self.start_time + self.Interval * 60
|
self.next_check = self.start_time + self.Interval * 60
|
||||||
self.count = 0
|
self.count = 0
|
||||||
|
self.initial_date = None
|
||||||
|
|
||||||
async def on_stop(self):
|
async def on_stop(self):
|
||||||
await self.timer.stop()
|
await self.timer.stop()
|
||||||
|
@ -441,13 +444,17 @@ class CooldownStep(CBPiStep):
|
||||||
await self.push_update()
|
await self.push_update()
|
||||||
while self.running == True:
|
while self.running == True:
|
||||||
current_temp = self.get_sensor_value(self.props.get("Sensor", None)).get("value")
|
current_temp = self.get_sensor_value(self.props.get("Sensor", None)).get("value")
|
||||||
if self.count == 19:
|
if self.count == 10:
|
||||||
self.temp_array.append(current_temp)
|
self.temp_array.append(current_temp)
|
||||||
self.time_array.append(time.time())
|
current_time = time.time()
|
||||||
|
if self.initial_date == None:
|
||||||
|
self.initial_date = current_time
|
||||||
|
self.time_array.append(current_time)
|
||||||
self.count = 0
|
self.count = 0
|
||||||
if time.time() >= self.next_check:
|
if time.time() >= self.next_check:
|
||||||
self.next_check = time.time() + (self.Interval * 60)
|
self.next_check = time.time() + (self.Interval * 60)
|
||||||
cooldown_model = np.poly1d(np.polyfit(self.temp_array, self.time_array, 4))
|
|
||||||
|
cooldown_model = np.poly1d(np.polyfit(self.temp_array, self.time_array, 2))
|
||||||
target_time=cooldown_model(self.target_temp)
|
target_time=cooldown_model(self.target_temp)
|
||||||
target_timestring= datetime.fromtimestamp(target_time)
|
target_timestring= datetime.fromtimestamp(target_time)
|
||||||
self.summary="ECT: {}".format(target_timestring.strftime("%H:%M"))
|
self.summary="ECT: {}".format(target_timestring.strftime("%H:%M"))
|
||||||
|
|
|
@ -289,4 +289,3 @@ class StepHttpEndpoints():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
125
cbpi/http_endpoints/http_upload.py
Normal file
125
cbpi/http_endpoints/http_upload.py
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
#from cbpi.controller.recipe_controller import RecipeController
|
||||||
|
from cbpi.api.dataclasses import Props, Step
|
||||||
|
from aiohttp import web
|
||||||
|
from cbpi.api import *
|
||||||
|
|
||||||
|
class UploadHttpEndpoints():
|
||||||
|
|
||||||
|
def __init__(self, cbpi):
|
||||||
|
self.cbpi = cbpi
|
||||||
|
# self.controller : RecipeController = cbpi.recipe
|
||||||
|
self.cbpi.register(self, "/fileupload")
|
||||||
|
|
||||||
|
|
||||||
|
@request_mapping(path='/', method="POST", auth_required=False)
|
||||||
|
async def RecipeUpload(self, request):
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Upload XML file or database from KBH V2
|
||||||
|
tags:
|
||||||
|
- FileUpload
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
multipart/form-data:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
orderId:
|
||||||
|
type: integer
|
||||||
|
userId:
|
||||||
|
type: integer
|
||||||
|
fileName:
|
||||||
|
type: string
|
||||||
|
format: binary
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = await request.post()
|
||||||
|
fileData = data['File']
|
||||||
|
logging.info(fileData)
|
||||||
|
|
||||||
|
|
||||||
|
@request_mapping(path='/kbh', method="GET", auth_required=False)
|
||||||
|
async def get_kbh_list(self, request):
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Get Recipe list from Kleiner Brauhelfer
|
||||||
|
tags:
|
||||||
|
- FileUpload
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
kbh_list = await get_kbh_recipes()
|
||||||
|
return web.json_response(kbh_list)
|
||||||
|
|
||||||
|
@request_mapping(path='/kbh', method="POST", auth_required=False)
|
||||||
|
async def create_kbh_recipe(self, request):
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Create Recipe from KBH database with selected ID
|
||||||
|
tags:
|
||||||
|
- FileUpload
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
kbh_id = await request.json()
|
||||||
|
await self.kbh_recipe_creation(kbh_id['id'])
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
@request_mapping(path='/xml', method="GET", auth_required=False)
|
||||||
|
async def get_xml_list(self, request):
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Get recipe list from xml file
|
||||||
|
tags:
|
||||||
|
- FileUpload
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
xml_list = await get_xml_recipes()
|
||||||
|
return web.json_response(xml_list)
|
||||||
|
|
||||||
|
@request_mapping(path='/xml', method="POST", auth_required=False)
|
||||||
|
async def create_xml_recipe(self, request):
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Create recipe from xml file with selected id
|
||||||
|
tags:
|
||||||
|
- FileUpload
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
xml_id = await request.json()
|
||||||
|
await self.xml_recipe_creation(xml_id['id'])
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
@request_mapping(path="/getpath", auth_required=False)
|
||||||
|
async def http_getpath(self, request):
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: get path for recipe creation
|
||||||
|
tags:
|
||||||
|
- FileUpload
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
return web.json_response(data=self.get_creation_path())
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -34,6 +34,7 @@ setup(name='cbpi',
|
||||||
'shortuuid==1.0.1',
|
'shortuuid==1.0.1',
|
||||||
'tabulate==0.8.7',
|
'tabulate==0.8.7',
|
||||||
'asyncio-mqtt',
|
'asyncio-mqtt',
|
||||||
|
'scipy',
|
||||||
'cbpi4ui',
|
'cbpi4ui',
|
||||||
'RPi.GPIO; sys_platform == "linux"'
|
'RPi.GPIO; sys_platform == "linux"'
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue