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:
avollkopf 2021-05-30 11:58:18 +02:00
parent 40020ba64d
commit b3d87bc027
7 changed files with 169 additions and 7 deletions

View file

@ -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",

View file

@ -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)

View file

@ -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

View file

@ -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"))

View file

@ -286,7 +286,6 @@ class StepHttpEndpoints():
await self.controller.savetobook() await self.controller.savetobook()
return web.Response(status=204) return web.Response(status=204)

View 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())

View file

@ -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"'
], ],
@ -46,4 +47,4 @@ setup(name='cbpi',
"cbpi=cbpi.cli:main", "cbpi=cbpi.cli:main",
] ]
} }
) )