Added Fermenters (development)

Added fermenter type
Added fermenter logic (incl. new class)
-> will require cbpi4ui -> >= 0.1.a1

Still under development, but fermentation w/o steps should be working
This commit is contained in:
avollkopf 2022-01-02 11:25:56 +01:00
parent bee645ff96
commit d7c1b64493
17 changed files with 651 additions and 29 deletions

View file

@ -1 +1 @@
__version__ = "4.0.0.59"
__version__ = "4.0.1.a1"

View file

@ -9,6 +9,7 @@ __all__ = ["CBPiActor",
"parameters",
"background_task",
"CBPiKettleLogic",
"CBPiFermenterLogic",
"CBPiException",
"KettleException",
"SensorException",
@ -22,5 +23,6 @@ from cbpi.api.extension import *
from cbpi.api.property import *
from cbpi.api.decorator import *
from cbpi.api.kettle_logic import *
from cbpi.api.fermenter_logic import *
from cbpi.api.step import *
from cbpi.api.exceptions import *

View file

@ -29,6 +29,15 @@ class CBPiBase(metaclass=ABCMeta):
async def set_target_temp(self,id, temp):
await self.cbpi.kettle.set_target_temp(id, temp)
def get_fermenter(self,id):
return self.cbpi.fermenter._find_by_id(id)
def get_fermenter_target_temp(self,id):
return self.cbpi.fermenter._find_by_id(id).target_temp
async def set_fermenter_target_temp(self,id, temp):
await self.cbpi.fermenter.set_target_temp(id, temp)
def get_sensor(self,id):
return self.cbpi.sensor.find_by_id(id)

View file

@ -8,5 +8,6 @@ class ConfigType(Enum):
ACTOR = "actor"
SENSOR = "sensor"
STEP = "step"
FERMENTER = "fermenter"

View file

@ -62,7 +62,7 @@ class Actor:
def __str__(self):
return "name={} props={}, state={}, type={}, power={}".format(self.name, self.props, self.state, self.type, self.power)
def to_dict(self):
return dict(id=self.id, name=self.name, type=self.type, props=self.props.to_dict(), state2="HELLO WORLD", state=self.instance.get_state(), power=self.power)
return dict(id=self.id, name=self.name, type=self.type, props=self.props.to_dict(), state=self.instance.get_state(), power=self.power)
@dataclass
@ -125,15 +125,30 @@ class Step:
class Fermenter:
id: str = None
name: str = None
sensor: Sensor = None
heater: Actor = None
cooler: Actor = None
brewname: str = None
props: Props = Props()
target_temp: int = 0
type: str = None
steps: List[Step]= field(default_factory=list)
instance: str = None
def __str__(self):
return "id={} name={} brewname={} props={} temp={} steps={}".format(self.id, self.name, self.brewname, self.props, self.target_temp, self.steps)
return "id={} name={} sensor={} heater={} cooler={} brewname={} props={} temp={} type={} steps={}".format(self.id, self.name, self.sensor, self.heater, self.cooler, self.brewname, self.props, self.target_temp, self.type, self.steps)
def to_dict(self):
if self.instance is not None:
state = self.instance.state
else:
state = False
steps = list(map(lambda item: item.to_dict(), self.steps))
return dict(id=self.id, name=self.name, target_temp=self.target_temp, steps=steps, props=self.props.to_dict() if self.props is not None else None)
return dict(id=self.id, name=self.name, state=state, sensor=self.sensor, heater=self.heater, cooler=self.cooler, brewname=self.brewname, props=self.props.to_dict() if self.props is not None else None, target_temp=self.target_temp, type=self.type, steps=steps)
@dataclass
@ -162,6 +177,7 @@ class ConfigType(Enum):
NUMBER="number"
SELECT="select"
STEP="step"
FERMENTER="fermenter"
@dataclass
class Config:

View file

@ -0,0 +1,51 @@
from cbpi.api.base import CBPiBase
from cbpi.api.extension import CBPiExtension
from abc import ABCMeta
import logging
import asyncio
class CBPiFermenterLogic(CBPiBase, metaclass=ABCMeta):
def __init__(self, cbpi, id, props):
self.cbpi = cbpi
self.id = id
self.props = props
self.state = False
self.running = False
def init(self):
pass
async def on_start(self):
pass
async def on_stop(self):
pass
async def run(self):
pass
async def _run(self):
try:
await self.on_start()
self.cancel_reason = await self.run()
except asyncio.CancelledError as e:
pass
finally:
await self.on_stop()
def get_state(self):
return dict(running=self.state)
async def start(self):
self.state = True
async def stop(self):
self.task.cancel()
await self.task
self.state = False

View file

@ -98,6 +98,23 @@ class Property(object):
The user select a kettle which is available in the system. The value of this variable will be the kettle id
'''
def __init__(self, label, description=""):
'''
:param label:
:param description:
'''
PropertyType.__init__(self)
self.label = label
self.configurable = True
self.description = description
class Fermenter(PropertyType):
'''
The user select a fermenter which is available in the system. The value of this variable will be the fermenter id
'''
def __init__(self, label, description=""):
'''

View file

@ -42,6 +42,11 @@ def create_config_file():
destfile = os.path.join(".", 'config')
shutil.copy(srcfile, destfile)
if os.path.exists(os.path.join(".", 'config', "fermenter_data.json")) is False:
srcfile = os.path.join(os.path.dirname(__file__), "config", "fermenter_data.json")
destfile = os.path.join(".", 'config')
shutil.copy(srcfile, destfile)
if os.path.exists(os.path.join(".", 'config', "step_data.json")) is False:
srcfile = os.path.join(os.path.dirname(__file__), "config", "step_data.json")
destfile = os.path.join(".", 'config')

View file

@ -0,0 +1,5 @@
{
"data": [
]
}

View file

@ -1,4 +1,3 @@
import asyncio
import cbpi
import copy
@ -9,19 +8,15 @@ from os import listdir
from os.path import isfile, join
import shortuuid
from cbpi.api.dataclasses import Fermenter, FermenterStep, Props, Step
from cbpi.controller.basic_controller2 import BasicController
from tabulate import tabulate
import sys, os
from ..api.step import CBPiStep, StepMove, StepResult, StepState
logging.basicConfig(format='%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
datefmt='%Y-%m-%d:%H:%M:%S',
level=logging.INFO)
class FermentStep:
def __init__(self, cbpi, step, on_done) -> None:
self.cbpi = cbpi
self.logger = logging.getLogger(__name__)
@ -85,9 +80,10 @@ class FermentStep:
async def on_stop(self):
pass
class FermenationController:
class FermentationController:
def __init__(self, cbpi):
self.update_key = "fermenterupdate"
self.cbpi = cbpi
self.logger = logging.getLogger(__name__)
self.path = os.path.join(".", 'config', "fermenter_data.json")
@ -96,6 +92,27 @@ class FermenationController:
self.types = {}
self.cbpi.app.on_cleanup.append(self.shutdown)
async def init(self):
logging.info("INIT Fermentation Controller")
self.check_fermenter_file()
await self.load()
pass
def check_fermenter_file(self):
if os.path.exists(os.path.join(".", 'config', "fermenter_data.json")) is False:
logging.info("INIT fermenter_data.json file")
data = {
"data": [
]
}
destfile = os.path.join(".", 'config', "fermenter_data.json")
json.dump(data,open(destfile,'w'),indent=4, sort_keys=True)
def push_update(self):
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
pass
async def shutdown(self, app=None):
self.save()
for fermenter in self.data:
@ -114,7 +131,11 @@ class FermenationController:
with open(self.path) as json_file:
d = json.load(json_file)
self.data = list(map(lambda item: self._create(item), d))
#for item in self.data:
# logging.info("{} Starting ".format(item.name))
# await self.start(item.id)
def _create_step(self, fermenter, item):
id = item.get("id")
name = item.get("name")
@ -140,20 +161,37 @@ class FermenationController:
def _create(self, data):
id = data.get("id")
name = data.get("name")
sensor = data.get("sensor")
heater = data.get("heater")
cooler = data.get("cooler")
logictype = data.get("type")
temp = data.get("target_temp")
brewname = data.get("brewname")
props = Props(data.get("props", {}))
fermenter = Fermenter(id, name, brewname, props, 0)
fermenter = Fermenter(id, name, sensor, heater, cooler, brewname, props, temp, logictype)
fermenter.steps = list(map(lambda item: self._create_step(fermenter, item), data.get("steps", [])))
self.push_update()
#self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
#self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
return fermenter
def _find_by_id(self, id):
return next((item for item in self.data if item.id == id), None)
async def init(self):
pass
async def get_all(self):
return self.data
return list(map(lambda x: x.to_dict(), self.data))
def get_types(self):
# logging.info("{} Get Types".format(self.name))
result = {}
for key, value in self.types.items():
result[key] = dict(name=value.get("name"), properties=value.get("properties"), actions=value.get("actions"))
return result
def get_state(self):
# logging.info("{} Get State".format(self.name))
return {"data": list(map(lambda x: x.to_dict(), self.data)), "types":self.get_types()}
async def get(self, id: str ):
return self._find_by_id(id)
@ -162,12 +200,21 @@ class FermenationController:
data.id = shortuuid.uuid()
self.data.append(data)
self.save()
self.push_update()
#self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
#self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
return data
async def update(self, item: Fermenter ):
logging.info(item)
def _update(old_item: Fermenter, item: Fermenter):
old_item.name = item.name
old_item.sensor = item.sensor
old_item.heater = item.heater
old_item.cooler = item.cooler
old_item.type = item.type
old_item.brewname = item.brewname
old_item.props = item.props
old_item.target_temp = item.target_temp
@ -175,12 +222,31 @@ class FermenationController:
self.data = list(map(lambda old: _update(old, item) if old.id == item.id else old, self.data))
self.save()
self.push_update()
#self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
#self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
return item
async def set_target_temp(self, id: str, target_temp):
try:
item = self._find_by_id(id)
logging.info(item.target_temp)
if item:
item.target_temp = target_temp
self.save()
self.push_update()
#self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
#self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
except Exception as e:
logging.error("Failed to set Target Temp {} {}".format(id, e))
async def delete(self, id: str ):
item = self._find_by_id(id)
self.data = list(filter(lambda item: item.id != id, self.data))
self.save()
self.push_update()
#self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
#self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
def save(self):
with open(self.path, "w") as file:
@ -191,7 +257,7 @@ class FermenationController:
step.id = shortuuid.uuid()
item = self._find_by_id(id)
step.instance = FermentStep( self.cbpi, step.id, step.name, None, self._done)
step.instance = FermentStep( self.cbpi, step, self._done)
item.steps.append(step)
self.save()
@ -223,10 +289,11 @@ class FermenationController:
if step is None:
self.logger.info("No futher step to start")
else:
await step.instance.start()
step.status = StepState.ACTIVE
self.save()
await step.instance.start()
step.status = StepState.ACTIVE
self.save()
except Exception as e:
self.logger.error(e)
@ -240,6 +307,46 @@ class FermenationController:
except Exception as e:
self.logger.error(e)
async def start_logic(self, id):
try:
item = self._find_by_id(id)
logging.info("{} Start Id {} ".format(item.name, id))
if item.instance is not None and item.instance.running is True:
logging.warning("{} already running {}".format(item.name, id))
return
if item.type is None:
logging.warning("{} No Type {}".format(item.name, id))
return
clazz = self.types[item.type]["class"]
item.instance = clazz(self.cbpi, item.id, item.props)
await item.instance.start()
item.instance.running = True
item.instance.task = self._loop.create_task(item.instance._run())
logging.info("{} started {}".format(item.name, id))
# await self.push_udpate()
except Exception as e:
logging.error("{} Cant start {} - {}".format(item.name, id, e))
async def toggle(self, id):
try:
item = self._find_by_id(id)
#logging.info(item)
if item.instance is None or item.instance.state == False:
await self.start_logic(id)
else:
await item.instance.stop()
self.push_update()
#self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
#self.cbpi.push_update("cbpi/{}/update".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
except Exception as e:
logging.error("Failed to switch on FermenterLogic {} {}".format(id, e))
async def next(self, id):
self.logger.info("Next {} ".format(id))
@ -283,5 +390,4 @@ class FermenationController:
except Exception as e:
self.logger.error(e)

View file

@ -31,8 +31,7 @@ class PluginController():
try:
logger.info("Trying to load plugin %s" % filename)
data = load_config(os.path.join(
this_directory, "../extension/%s/config.yaml" % filename))
this_directory, "../extension/%s/config.yaml" % filename))
if (data.get("active") is True and data.get("version") == 4):
self.modules[filename] = import_module(
"cbpi.extension.%s" % (filename))
@ -75,6 +74,9 @@ class PluginController():
if issubclass(clazz, CBPiKettleLogic):
self.cbpi.kettle.types[name] = self._parse_step_props(clazz, name)
if issubclass(clazz, CBPiFermenterLogic):
self.cbpi.fermenter.types[name] = self._parse_step_props(clazz, name)
if issubclass(clazz, CBPiSensor):
self.cbpi.sensor.types[name] = self._parse_step_props(clazz, name)

View file

@ -26,6 +26,7 @@ from cbpi.controller.sensor_controller import SensorController
from cbpi.controller.step_controller import StepController
from cbpi.controller.recipe_controller import RecipeController
from cbpi.controller.upload_controller import UploadController
from cbpi.controller.fermentation_controller import FermentationController
from cbpi.controller.system_controller import SystemController
from cbpi.controller.satellite_controller import SatelliteController
@ -49,6 +50,7 @@ from cbpi.http_endpoints.http_system import SystemHttpEndpoints
from cbpi.http_endpoints.http_log import LogHttpEndpoints
from cbpi.http_endpoints.http_notification import NotificationHttpEndpoints
from cbpi.http_endpoints.http_upload import UploadHttpEndpoints
from cbpi.http_endpoints.http_fermentation import FermentationHttpEndpoints
import shortuuid
logger = logging.getLogger(__name__)
@ -115,8 +117,9 @@ class CraftBeerPi:
self.satellite = None
if str(self.static_config.get("mqtt", False)).lower() == "true":
self.satellite: SatelliteController = SatelliteController(self)
self.dashboard = DashboardController(self)
self.fermenter : FermentationController = FermentationController(self)
self.http_step = StepHttpEndpoints(self)
self.http_recipe = RecipeHttpEndpoints(self)
self.http_sensor = SensorHttpEndpoints(self)
@ -129,7 +132,7 @@ class CraftBeerPi:
self.http_log = LogHttpEndpoints(self)
self.http_notification = NotificationHttpEndpoints(self)
self.http_upload = UploadHttpEndpoints(self)
self.http_fermenter = FermentationHttpEndpoints(self)
self.login = Login(self)
@ -279,7 +282,7 @@ class CraftBeerPi:
await self.kettle.init()
await self.call_initializer(self.app)
await self.dashboard.init()
await self.fermenter.init()
self._swagger_setup()

View file

@ -1,9 +1,10 @@
import os, threading, time
import os, threading, time, shutil
from aiohttp import web
import logging
from unittest.mock import MagicMock, patch
import asyncio
import random
import json
from cbpi.api import *
from cbpi.api.config import ConfigType
from cbpi.api.base import CBPiBase

View file

@ -0,0 +1,115 @@
import asyncio
from asyncio import tasks
import logging
from cbpi.api import *
import aiohttp
from aiohttp import web
from cbpi.controller.fermentation_controller import FermentationController
from cbpi.api.dataclasses import Fermenter, Props, Step
from cbpi.api.base import CBPiBase
from cbpi.api.config import ConfigType
import json
import webbrowser
class FermenterAutostart(CBPiExtension):
def __init__(self,cbpi):
self.cbpi = cbpi
self._task = asyncio.create_task(self.run())
self.controller : FermentationController = cbpi.fermenter
async def run(self):
logging.info("Starting Fermenter Autorun")
#get all kettles
self.fermenter = self.controller.get_state()
for id in self.fermenter['data']:
try:
self.autostart=(id['props']['AutoStart'])
if self.autostart == "Yes":
fermenter_id=(id['id'])
logging.info("Enabling Autostart for Fermenter {}".format(fermenter_id))
self.fermenter=self.cbpi.fermenter._find_by_id(fermenter_id)
try:
if (self.fermenter.instance is None or self.fermenter.instance.state == False):
await self.cbpi.fermenter.toggle(self.fermenter.id)
logging.info("Successfully switched on Ferenterlogic for Fermenter {}".format(self.fermenter.id))
except Exception as e:
logging.error("Failed to switch on FermenterLogic {} {}".format(self.fermenter.id, e))
except:
pass
@parameters([Property.Number(label="HeaterOffsetOn", configurable=True, description="Offset as decimal number when the heater is switched on. Should be greater then 'HeaterOffsetOff'. For example a value of 2 switches on the heater if the current temperature is 2 degrees below the target temperature"),
Property.Number(label="HeaterOffsetOff", configurable=True, description="Offset as decimal number when the heater is switched off. Should be smaller then 'HeaterOffsetOn'. For example a value of 1 switches off the heater if the current temperature is 1 degree below the target temperature"),
Property.Number(label="CoolerOffsetOn", configurable=True, description="Offset as decimal number when the cooler is switched on. Should be greater then 'CoolerOffsetOff'. For example a value of 2 switches on the cooler if the current temperature is 2 degrees below the target temperature"),
Property.Number(label="CoolerOffsetOff", configurable=True, description="Offset as decimal number when the cooler is switched off. Should be smaller then 'CoolerOffsetOn'. For example a value of 1 switches off the cooler if the current temperature is 1 degree below the target temperature"),
Property.Select(label="AutoStart", options=["Yes","No"],description="Autostart Fermenter on cbpi start")])
class FermenterHysteresis(CBPiFermenterLogic):
async def run(self):
try:
self.heater_offset_min = float(self.props.get("HeaterOffsetOn", 0))
self.heater_offset_max = float(self.props.get("HeaterOffsetOff", 0))
self.cooler_offset_min = float(self.props.get("CoolerOffsetOn", 0))
self.cooler_offset_max = float(self.props.get("CoolerOffsetOff", 0))
self.fermenter = self.get_fermenter(self.id)
self.heater = self.fermenter.heater
self.cooler = self.fermenter.cooler
target_temp = self.get_fermenter_target_temp(self.id)
if target_temp == 0:
await self.set_fermenter_target_temp(self.id,int(self.props.get("TargetTemp", 0)))
while self.running == True:
sensor_value = self.get_sensor_value(self.fermenter.sensor).get("value")
target_temp = self.get_fermenter_target_temp(self.id)
if sensor_value + self.heater_offset_min <= target_temp:
if self.heater:
await self.actor_on(self.heater)
if sensor_value + self.heater_offset_max >= target_temp:
if self.heater:
await self.actor_off(self.heater)
if sensor_value >= self.cooler_offset_min + target_temp:
if self.cooler:
await self.actor_on(self.cooler)
if sensor_value <= self.cooler_offset_max + target_temp:
if self.cooler:
await self.actor_off(self.cooler)
await asyncio.sleep(1)
except asyncio.CancelledError as e:
pass
except Exception as e:
logging.error("CustomLogic Error {}".format(e))
finally:
self.running = False
if self.heater:
await self.actor_off(self.heater)
if self.cooler:
await self.actor_off(self.cooler)
def setup(cbpi):
'''
This method is called by the server during startup
Here you need to register your plugins at the server
:param cbpi: the cbpi core
:return:
'''
cbpi.plugin.register("Fermenter Hysteresis", FermenterHysteresis)
cbpi.plugin.register("Fermenter Autostart", FermenterAutostart)

View file

@ -0,0 +1,3 @@
name: FermenterHysteresis
version: 4
active: true

View file

@ -0,0 +1,285 @@
from cbpi.controller.fermentation_controller import FermentationController
from cbpi.api.dataclasses import Fermenter, Step, Props
from aiohttp import web
from cbpi.api import *
import logging
import json
auth = False
class FermentationHttpEndpoints():
def __init__(self, cbpi):
self.cbpi = cbpi
self.controller : FermentationController = cbpi.fermenter
self.cbpi.register(self, "/fermenter")
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Show all Fermenters
tags:
- Fermenter
responses:
"204":
description: successful operation
"""
data= self.controller.get_state()
return web.json_response(data=data)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: add one Fermenter
tags:
- Fermenter
parameters:
- in: body
name: body
description: Create a Fermenter
required: true
schema:
type: object
properties:
name:
type: string
sensor:
type: "integer"
format: "int64"
heater:
type: "integer"
format: "int64"
cooler:
type: "integer"
format: "int64"
target_temp:
type: "integer"
format: "int64"
type:
type: string
props:
type: object
example:
name: "Fermenter 1"
type: "CustomFermenterLogic"
sensor: "FermenterSensor"
heater: "FermenterHeater"
cooler: "FermenterCooler"
props: {}
responses:
"204":
description: successful operation
"""
data = await request.json()
fermenter = Fermenter(id=id, name=data.get("name"), sensor=data.get("sensor"), heater=data.get("heater"), cooler=data.get("cooler"), brewname=data.get("brewname"), target_temp=data.get("target_temp"), props=Props(data.get("props", {})), type=data.get("type"))
response_data = await self.controller.create(fermenter)
return web.json_response(data=response_data.to_dict())
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update a Fermenter (NOT YET IMPLEMENTED)
tags:
- Fermenter
parameters:
- name: "id"
in: "path"
description: "Fermenter ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update a Fermenter
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
props: object
responses:
"200":
description: successful operation
"""
id = request.match_info['id']
data = await request.json()
fermenter = Fermenter(id=id, name=data.get("name"), sensor=data.get("sensor"), heater=data.get("heater"), cooler=data.get("cooler"), brewname=data.get("brewname"), target_temp=data.get("target_temp"), props=Props(data.get("props", {})), type=data.get("type"))
return web.json_response(data=(await self.controller.update(fermenter)).to_dict())
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete an actor
tags:
- Fermenter
parameters:
- name: "id"
in: "path"
description: "Fermenter ID"
required: true
type: "string"
responses:
"204":
description: successful operation
"""
id = request.match_info['id']
await self.controller.delete(id)
return web.Response(status=204)
# @request_mapping(path="/{id}/on", method="POST", auth_required=False)
# async def http_on(self, request) -> web.Response:
"""
---
description: Switch actor on
tags:
- Fermenter
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "string"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
# id = request.match_info['id']
# await self.controller.start(id)
# return web.Response(status=204)
# @request_mapping(path="/{id}/off", method="POST", auth_required=False)
# async def http_off(self, request) -> web.Response:
"""
---
description: Switch actor on
tags:
- Fermenter
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "string"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
# id = request.match_info['id']
# await self.controller.off(id)
# return web.Response(status=204)
@request_mapping(path="/{id}/toggle", method="POST", auth_required=False)
async def http_toggle(self, request) -> web.Response:
"""
---
description: Switch actor on
tags:
- Fermenter
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "string"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
id = request.match_info['id']
await self.controller.toggle(id)
return web.Response(status=204)
# @request_mapping(path="/{id}/action", method="POST", auth_required=auth)
# async def http_action(self, request) -> web.Response:
"""
---
description: Toogle an actor on or off
tags:
- Fermenter
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update an actor
required: false
schema:
type: object
properties:
name:
type: string
parameter:
type: object
responses:
"204":
description: successful operation
"""
# actor_id = request.match_info['id']
# data = await request.json()
# await self.controller.call_action(actor_id, data.get("name"), data.get("parameter"))
return web.Response(status=204)
@request_mapping(path="/{id}/target_temp", method="POST", auth_required=auth)
async def http_target(self, request) -> web.Response:
"""
---
description: Set Target Temp for Fermenter
tags:
- Fermenter
parameters:
- name: "id"
in: "path"
description: "Fermenter ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update Temp
required: true
schema:
type: object
properties:
temp:
type: integer
responses:
"204":
description: successful operation
"""
id = request.match_info['id']
data = await request.json()
await self.controller.set_target_temp(id,data.get("temp"))
return web.Response(status=204)

View file

@ -29,6 +29,7 @@ class SystemHttpEndpoints:
"""
return web.json_response(data=dict(
actor=self.cbpi.actor.get_state(),
fermenter=self.cbpi.fermenter.get_state(),
sensor=self.cbpi.sensor.get_state(),
kettle=self.cbpi.kettle.get_state(),
step=self.cbpi.step.get_state(),