mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-21 14:38:15 +01:00
Merge form dev branch
This commit is contained in:
commit
036e70e4bf
18 changed files with 220 additions and 239 deletions
|
@ -1 +1 @@
|
|||
__version__ = "4.0.2.0.a8"
|
||||
__version__ = "4.0.2.0.a19"
|
||||
|
|
|
@ -131,7 +131,7 @@ class Fermenter:
|
|||
brewname: str = None
|
||||
description : str = None
|
||||
props: Props = Props()
|
||||
target_temp: int = 0
|
||||
target_temp: float = 0
|
||||
type: str = None
|
||||
steps: List[Step]= field(default_factory=list)
|
||||
instance: str = None
|
||||
|
@ -162,7 +162,7 @@ class FermenterStep:
|
|||
props: Props = Props()
|
||||
type: str = None
|
||||
status: StepState = StepState.INITIAL
|
||||
endtime: int = 0 # endtime if step is active and timer is running
|
||||
endtime: int = 0 # endtime if step is active and timer is running
|
||||
instance: str = None
|
||||
step: dict = None
|
||||
|
||||
|
@ -170,7 +170,7 @@ class FermenterStep:
|
|||
return "name={} props={}, type={}, instance={}".format(self.name, self.props, self.type, self.instance)
|
||||
def to_dict(self):
|
||||
msg = self.instance.summary if self.instance is not None else ""
|
||||
return dict(id=self.id, name=self.name, state_text=msg, type=self.type, status=self.status.value, endtime = self.endtime, props=self.props.to_dict())
|
||||
return dict(id=self.id, name=self.name, state_text=msg, type=self.type, status=self.status.value, endtime=self.endtime, props=self.props.to_dict())
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -117,15 +117,6 @@ class CBPiStep(CBPiBase):
|
|||
def __str__(self):
|
||||
return "name={} props={}, type={}".format(self.name, self.props, self.__class__.__name__)
|
||||
|
||||
#class CBPiFermentationStep(CBPiStep):
|
||||
|
||||
# def __init__(self, cbpi, fermenter, step, props, on_done) -> None:
|
||||
# self.fermenter = fermenter
|
||||
# id = step.get("id")
|
||||
# name=step.get("name")
|
||||
# self.step=step
|
||||
# super().__init__(cbpi, id, name, props, on_done)
|
||||
|
||||
class CBPiFermentationStep(CBPiBase):
|
||||
|
||||
def __init__(self, cbpi, fermenter, step, props, on_done) -> None:
|
||||
|
@ -190,9 +181,9 @@ class CBPiFermentationStep(CBPiBase):
|
|||
|
||||
async def update_endtime(self):
|
||||
await self.cbpi.fermenter.update_endtime(self.fermenter.id, self.id, self.endtime)
|
||||
|
||||
|
||||
async def save_props(self):
|
||||
self.cbpi.fermenter.save()
|
||||
self.cbpi.fermenter.save()
|
||||
|
||||
async def push_update(self):
|
||||
self.cbpi.fermenter.push_update(self.update_key)
|
||||
|
|
|
@ -22,7 +22,7 @@ class BasicController:
|
|||
self.logger = logging.getLogger(__name__)
|
||||
self.data = []
|
||||
self.autostart = True
|
||||
self._loop = asyncio.get_event_loop()
|
||||
#self._loop = asyncio.get_event_loop()
|
||||
self.path = os.path.join(".", 'config', file)
|
||||
self.cbpi.app.on_cleanup.append(self.shutdown)
|
||||
|
||||
|
@ -100,7 +100,8 @@ class BasicController:
|
|||
|
||||
await item.instance.start()
|
||||
item.instance.running = True
|
||||
item.instance.task = self._loop.create_task(item.instance._run())
|
||||
item.instance.task = asyncio.get_event_loop().create_task(item.instance._run())
|
||||
#item.instance.task = self._loop.create_task(item.instance._run())
|
||||
|
||||
logging.info("{} started {}".format(self.name, id))
|
||||
|
||||
|
|
|
@ -15,79 +15,7 @@ from cbpi.controller.basic_controller2 import BasicController
|
|||
from tabulate import tabulate
|
||||
import sys, os
|
||||
from ..api.step import CBPiStep, StepMove, StepResult, StepState, CBPiFermentationStep
|
||||
|
||||
|
||||
|
||||
class FermentStep:
|
||||
|
||||
def __init__(self, cbpi, step, on_done) -> None:
|
||||
self.cbpi = cbpi
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.step = step
|
||||
self.props = step.props
|
||||
self._done_callback = on_done
|
||||
self.task = None
|
||||
self.summary = ""
|
||||
|
||||
def _done(self, task):
|
||||
if self._done_callback is not None:
|
||||
try:
|
||||
result = task.result()
|
||||
self._done_callback(self, result)
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
|
||||
@abstractmethod
|
||||
async def run(self):
|
||||
while self.running:
|
||||
logging.info(self.step)
|
||||
await asyncio.sleep(1)
|
||||
pass
|
||||
|
||||
async def _run(self):
|
||||
try:
|
||||
await self.step.instance.on_start()
|
||||
await self.step.instance.run()
|
||||
#await self.on_start()
|
||||
#await self.run()
|
||||
self.cancel_reason = StepResult.DONE
|
||||
except asyncio.CancelledError as e:
|
||||
pass
|
||||
finally:
|
||||
await self.on_stop()
|
||||
|
||||
return self.cancel_reason
|
||||
|
||||
async def start(self):
|
||||
self.logger.info("Start {}".format(self.step.name))
|
||||
self.running = True
|
||||
self.task = asyncio.create_task(self._run())
|
||||
self.task.add_done_callback(self._done)
|
||||
|
||||
async def next(self):
|
||||
self.running = False
|
||||
self.cancel_reason = StepResult.NEXT
|
||||
self.task.cancel()
|
||||
await self.task
|
||||
|
||||
async def stop(self):
|
||||
try:
|
||||
self.running = False
|
||||
if self.task is not None and self.task.done() is False:
|
||||
self.logger.info("Stopping Task")
|
||||
self.cancel_reason = StepResult.STOP
|
||||
self.task.cancel()
|
||||
await self.task
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
|
||||
async def on_start(self):
|
||||
#self.props.hello = "WOOHOo"
|
||||
pass
|
||||
|
||||
async def on_stop(self):
|
||||
pass
|
||||
|
||||
|
||||
class FermentationController:
|
||||
|
||||
def __init__(self, cbpi):
|
||||
|
@ -95,7 +23,6 @@ class FermentationController:
|
|||
self.cbpi = cbpi
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.path = os.path.join(".", 'config', "fermenter_data.json")
|
||||
|
||||
self.data = []
|
||||
self.types = {}
|
||||
self.steptypes = {}
|
||||
|
@ -127,6 +54,10 @@ class FermentationController:
|
|||
for step in fermenter.steps:
|
||||
try:
|
||||
self.logger.info("Stop {}".format(step.name))
|
||||
try:
|
||||
step.instance.shutdown = True
|
||||
except:
|
||||
pass
|
||||
await step.instance.stop()
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
|
@ -136,15 +67,16 @@ class FermentationController:
|
|||
for step in fermenter.steps:
|
||||
try:
|
||||
self.logger.info("Stop {}".format(step.name))
|
||||
try:
|
||||
step.instance.shutdown = True
|
||||
except:
|
||||
pass
|
||||
await step.instance.stop()
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
|
||||
|
||||
async def load(self):
|
||||
# if os.path.exists(self.path) is False:
|
||||
# with open(self.path, "w") as file:
|
||||
# json.dump(dict(basic={}, steps=[]), file, indent=4, sort_keys=True)
|
||||
with open(self.path) as json_file:
|
||||
data = json.load(json_file)
|
||||
|
||||
|
@ -155,12 +87,14 @@ class FermentationController:
|
|||
id = item.get("id")
|
||||
name = item.get("name")
|
||||
props = Props(item.get("props"))
|
||||
try:
|
||||
endtime = int(item.get("endtime", 0))
|
||||
except:
|
||||
endtime=0
|
||||
|
||||
status = StepState(item.get("status", "I"))
|
||||
endtime = int(item.get("endtime", 0))
|
||||
if status == StepState.ACTIVE:
|
||||
status = StepState("S")
|
||||
if status != StepState.STOP:
|
||||
endtime = 0
|
||||
type = item.get("type")
|
||||
|
||||
try:
|
||||
|
@ -221,7 +155,6 @@ class FermentationController:
|
|||
|
||||
def get_state(self):
|
||||
if self.data == []:
|
||||
#logging.info(self.data)
|
||||
pass
|
||||
|
||||
return {"data": list(map(lambda x: x.to_dict(), self.data)), "types":self.get_types(), "steptypes":self.get_steptypes()}
|
||||
|
@ -238,7 +171,6 @@ class FermentationController:
|
|||
|
||||
def get_fermenter_steps(self):
|
||||
if self.data == []:
|
||||
#logging.info(self.data)
|
||||
pass
|
||||
fermentersteps=[]
|
||||
steplist=list(map(lambda x: x.to_dict(), self.data))
|
||||
|
@ -307,16 +239,16 @@ class FermentationController:
|
|||
with open(self.path, "w") as file:
|
||||
json.dump(data, file, indent=4, sort_keys=True)
|
||||
|
||||
async def create_step(self, id, item):
|
||||
def create_step(self, id, item):
|
||||
try:
|
||||
stepid = shortuuid.uuid()
|
||||
props = item.get("props")
|
||||
item['id'] = stepid
|
||||
status = StepState("I")
|
||||
type = item.get("type")
|
||||
name = item.get("name")
|
||||
endtime = item.get("endtime", 0)
|
||||
props = Props(item.get("props"))
|
||||
fermenter = self._find_by_id(id)
|
||||
|
||||
try:
|
||||
type_cfg = self.steptypes.get(type)
|
||||
clazz = type_cfg.get("class")
|
||||
|
@ -324,13 +256,8 @@ class FermentationController:
|
|||
except Exception as e:
|
||||
logging.warning("Failed to create step instance %s - %s" % (id, e))
|
||||
instance = None
|
||||
step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, instance=instance)
|
||||
step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, endtime=endtime, instance=instance)
|
||||
|
||||
|
||||
|
||||
fermenter.steps.append(step)
|
||||
self.save()
|
||||
self.push_update("fermenterstepupdate")
|
||||
return step
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
|
@ -341,30 +268,29 @@ class FermentationController:
|
|||
props = item.get("props")
|
||||
status = StepState("I")
|
||||
type = item.get("type")
|
||||
#logging.info(type)
|
||||
endtime = 0
|
||||
name = item.get("name")
|
||||
props = Props(item.get("props"))
|
||||
|
||||
logging.info("update step")
|
||||
try:
|
||||
type_cfg = self.steptypes.get(type)
|
||||
#logging.info(type_cfg)
|
||||
logging.info(type_cfg)
|
||||
clazz = type_cfg.get("class")
|
||||
#logging.info(clazz)
|
||||
logging.info(clazz)
|
||||
instance = clazz(self.cbpi, fermenter, item, props, self._done)
|
||||
logging.info(instance)
|
||||
except Exception as e:
|
||||
logging.warning("Failed to create step instance %s - %s " % (item.id, e))
|
||||
instance = None
|
||||
step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, instance=instance)
|
||||
#logging.info(step)
|
||||
#logging.info(fermenter.steps)
|
||||
step = FermenterStep(id=stepid, name=name, fermenter=fermenter, props=props, type=type, status=status, endtime=endtime, instance=instance)
|
||||
|
||||
try:
|
||||
fermenter.steps = list(map(lambda old: step if old.id == step.id else old, fermenter.steps))
|
||||
except Exception as e:
|
||||
logging.info(e)
|
||||
#logging.info(fermenter.steps)
|
||||
|
||||
self.save()
|
||||
#logging.info("SAVEUPDATE")
|
||||
|
||||
self.push_update("fermenterstepupdate")
|
||||
|
||||
|
@ -382,6 +308,15 @@ class FermentationController:
|
|||
self.save()
|
||||
self.push_update("fermenterstepupdate")
|
||||
|
||||
async def update_endtime(self, id, stepid, endtime):
|
||||
try:
|
||||
item = self._find_by_id(id)
|
||||
step = self._find_step_by_id(item.steps, stepid)
|
||||
step.endtime = int(endtime)
|
||||
self.save()
|
||||
self.push_update("fermenterstepupdate")
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
|
||||
def _find_by_status(self, data, status):
|
||||
return next((item for item in data if item.status == status), None)
|
||||
|
@ -419,6 +354,7 @@ class FermentationController:
|
|||
logging.info("Need to change timer")
|
||||
step.status = StepState.ACTIVE
|
||||
self.save()
|
||||
self.push_update()
|
||||
self.push_update("fermenterstepupdate")
|
||||
return
|
||||
|
||||
|
@ -432,6 +368,7 @@ class FermentationController:
|
|||
logging.info("Starting step {}".format(step.name))
|
||||
step.status = StepState.ACTIVE
|
||||
self.save()
|
||||
self.push_update()
|
||||
self.push_update("fermenterstepupdate")
|
||||
|
||||
except Exception as e:
|
||||
|
@ -517,7 +454,7 @@ class FermentationController:
|
|||
await self.start(id)
|
||||
else:
|
||||
logging.info("No Step is running")
|
||||
|
||||
self.push_update()
|
||||
self.push_update("fermenterstepupdate")
|
||||
|
||||
except Exception as e:
|
||||
|
@ -531,12 +468,14 @@ class FermentationController:
|
|||
for step in item.steps:
|
||||
self.logger.info("Stopping Step {} {}".format(step.name, step.id))
|
||||
try:
|
||||
await step.instance.stop()
|
||||
await step.instance.reset()
|
||||
await step.instance.stop()
|
||||
step.status = StepState.INITIAL
|
||||
step.endtime = 0
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
self.save()
|
||||
self.push_update()
|
||||
self.push_update("fermenterstepupdate")
|
||||
|
||||
except Exception as e:
|
||||
|
@ -555,6 +494,7 @@ class FermentationController:
|
|||
|
||||
fermenter.steps[index], fermenter.steps[index+direction] = fermenter.steps[index+direction], fermenter.steps[index]
|
||||
self.save()
|
||||
self.push_update()
|
||||
self.push_update("fermenterstepupdate")
|
||||
|
||||
except Exception as e:
|
||||
|
@ -564,15 +504,19 @@ class FermentationController:
|
|||
|
||||
if key == self.update_key:
|
||||
self.cbpi.ws.send(dict(topic=key, data=list(map(lambda item: item.to_dict(), self.data))))
|
||||
#self.cbpi.push_update("cbpi/{}".format(self.update_key), list(map(lambda item: item.to_dict(), self.data)))
|
||||
|
||||
|
||||
for item in self.data:
|
||||
self.cbpi.push_update("cbpi/{}/{}".format(self.update_key,item.id), item.to_dict())
|
||||
pass
|
||||
else:
|
||||
#logging.info("FERMENTERSTEPUPDATE {}".format(key))
|
||||
fermentersteps=self.get_fermenter_steps()
|
||||
self.cbpi.ws.send(dict(topic=key, data=fermentersteps))
|
||||
|
||||
# send mqtt update for active femrentersteps
|
||||
for fermenter in fermentersteps:
|
||||
for step in fermenter['steps']:
|
||||
if step['status'] == 'A':
|
||||
self.cbpi.push_update("cbpi/{}/{}/{}".format(key,fermenter['id'],step['id']), step)
|
||||
|
||||
async def call_action(self, id, action, parameter) -> None:
|
||||
logging.info("FermenterStep Controller - call Action {} {}".format(id, action))
|
||||
|
@ -582,8 +526,7 @@ class FermentationController:
|
|||
await item.instance.__getattribute__(action)(**parameter)
|
||||
except Exception as e:
|
||||
logging.error("FermenterStep Controller - Failed to call action on {} {} {}".format(id, action, e))
|
||||
|
||||
# todo: Sensors may need to be removed when saving the recipe -> need to be replaced when assinging later to Fermenter with 'fermenter.sensor'
|
||||
|
||||
async def savetobook(self, fermenterid):
|
||||
name = shortuuid.uuid()
|
||||
path = os.path.join(".", 'config', "fermenterrecipes", "{}.yaml".format(name))
|
||||
|
@ -591,7 +534,7 @@ class FermentationController:
|
|||
try:
|
||||
brewname = fermenter.brewname
|
||||
description = fermenter.description
|
||||
# todo add escription at later point of time, once description has been added to fermenter dataclass
|
||||
|
||||
except:
|
||||
brewname = ""
|
||||
description = ""
|
||||
|
@ -605,20 +548,38 @@ class FermentationController:
|
|||
with open(path, "w") as file:
|
||||
yaml.dump(data, file)
|
||||
|
||||
async def load_recipe(self, data, fermenterid):
|
||||
async def load_recipe(self, data, fermenterid, name):
|
||||
try:
|
||||
await self.shutdown(None, fermenterid)
|
||||
except:
|
||||
pass
|
||||
fermenter = self._find_by_id(fermenterid)
|
||||
|
||||
def add_runtime_data(item):
|
||||
item["status"] = "I"
|
||||
item["endtime"] = 0
|
||||
item["id"] = shortuuid.uuid()
|
||||
item["props"]["Sensor"] = fermenter.sensor
|
||||
|
||||
list(map(lambda item: add_runtime_data(item), data.get("steps")))
|
||||
fermenter.description = data['basic']['desc']
|
||||
fermenter.brewname = data['basic']['name']
|
||||
fermenter.steps=[]
|
||||
if name is not None:
|
||||
fermenter.brewname = name
|
||||
else:
|
||||
fermenter.brewname = data['basic']['name']
|
||||
await self.update(fermenter)
|
||||
fermenter.steps=[]
|
||||
for item in data.get("steps"):
|
||||
await self.create_step(fermenterid, item)
|
||||
fermenter.steps.append(self.create_step(fermenterid, item))
|
||||
|
||||
self.save()
|
||||
self.push_update("fermenterstepupdate")
|
||||
|
||||
async def add_step(self, fermenterid, newstep):
|
||||
fermenter = self._find_by_id(fermenterid)
|
||||
step = self.create_step(fermenterid, newstep)
|
||||
fermenter.steps.append(step)
|
||||
self.save()
|
||||
self.push_update("fermenterstepupdate")
|
||||
return step
|
||||
|
|
@ -69,13 +69,13 @@ class FermenterRecipeController:
|
|||
os.remove(path)
|
||||
|
||||
|
||||
async def brew(self, name, fermenterid):
|
||||
async def brew(self, recipeid, fermenterid, name):
|
||||
|
||||
recipe_path = os.path.join(".", 'config', "fermenterrecipes", "%s.yaml" % name)
|
||||
recipe_path = os.path.join(".", 'config', "fermenterrecipes", "%s.yaml" % recipeid)
|
||||
logging.info(recipe_path)
|
||||
with open(recipe_path) as file:
|
||||
data = yaml.load(file, Loader=yaml.FullLoader)
|
||||
await self.cbpi.fermenter.load_recipe(data, fermenterid)
|
||||
await self.cbpi.fermenter.load_recipe(data, fermenterid, name)
|
||||
|
||||
async def clone(self, id, new_name):
|
||||
recipe_path = os.path.join(".", 'config', "fermenterrecipes", "%s.yaml" % id)
|
||||
|
|
|
@ -20,7 +20,7 @@ class StepController:
|
|||
self.cbpi = cbpi
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.path = os.path.join(".", 'config', "step_data.json")
|
||||
self._loop = asyncio.get_event_loop()
|
||||
#self._loop = asyncio.get_event_loop()
|
||||
self.basic_data = {}
|
||||
self.step = None
|
||||
self.types = {}
|
||||
|
@ -68,8 +68,9 @@ class StepController:
|
|||
self.profile = list(map(lambda item: self.create(item), self.profile))
|
||||
if startActive is True:
|
||||
active_step = self.find_by_status("A")
|
||||
if active_step is not None:
|
||||
self._loop.create_task(self.start_step(active_step))
|
||||
if active_step is not None:
|
||||
asyncio.get_event_loop().create_task(self.start_step(active_step))
|
||||
#self._loop.create_task(self.start_step(active_step))
|
||||
|
||||
async def add(self, item: Step):
|
||||
logging.debug("Add step")
|
||||
|
|
|
@ -178,6 +178,8 @@ class SystemController:
|
|||
mempercent = 0
|
||||
eth0IP = "N/A"
|
||||
wlan0IP = "N/A"
|
||||
eth0speed = "N/A"
|
||||
wlan0speed = "N/A"
|
||||
|
||||
TEMP_UNIT=self.cbpi.config.get("TEMP_UNIT", "C")
|
||||
FAHRENHEIT = False if TEMP_UNIT == "C" else True
|
||||
|
@ -225,12 +227,31 @@ class SystemController:
|
|||
if str(addr.family) == "AddressFamily.AF_INET":
|
||||
if addr.address:
|
||||
wlan0IP = addr.address
|
||||
info = psutil.net_if_stats()
|
||||
try:
|
||||
for nic in info:
|
||||
if nic == 'eth0':
|
||||
if info[nic].isup == True:
|
||||
if info[nic].speed:
|
||||
eth0speed = info[nic].speed
|
||||
else:
|
||||
eth0speed = "down"
|
||||
if nic == 'wlan0':
|
||||
if info[nic].isup == True:
|
||||
ratestring = os.popen('iwlist wlan0 rate | grep Rate').read()
|
||||
start = ratestring.find("=") + 1
|
||||
end = ratestring.find(" Mb/s")
|
||||
wlan0speed = ratestring[start:end]
|
||||
else:
|
||||
wlan0speed = "down"
|
||||
except Exception as e:
|
||||
logging.info(e)
|
||||
except:
|
||||
pass
|
||||
|
||||
if system == "Windows":
|
||||
try:
|
||||
ethernet = psutil.net_if_addrs()
|
||||
ethernet = psutil.net_if_addrs()
|
||||
for nic, addrs in ethernet.items():
|
||||
if nic == "Ethernet":
|
||||
for addr in addrs:
|
||||
|
@ -242,6 +263,23 @@ class SystemController:
|
|||
if str(addr.family) == "AddressFamily.AF_INET":
|
||||
if addr.address:
|
||||
wlan0IP = addr.address
|
||||
info = psutil.net_if_stats()
|
||||
try:
|
||||
for nic in info:
|
||||
if nic == 'Ethernet':
|
||||
if info[nic].isup == True:
|
||||
if info[nic].speed:
|
||||
eth0speed = info[nic].speed
|
||||
else:
|
||||
eth0speed = "down"
|
||||
if nic == 'WLAN':
|
||||
if info[nic].isup == True:
|
||||
if info[nic].speed:
|
||||
wlan0speed = info[nic].speed
|
||||
else:
|
||||
wlan0speed = "down"
|
||||
except Exception as e:
|
||||
logging.info(e)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -258,7 +296,9 @@ class SystemController:
|
|||
'temp': temp,
|
||||
'temp_unit': TEMP_UNIT,
|
||||
'eth0': eth0IP,
|
||||
'wlan0': wlan0IP}
|
||||
'wlan0': wlan0IP,
|
||||
'eth0speed': eth0speed,
|
||||
'wlan0speed': wlan0speed}
|
||||
return systeminfo
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
|
||||
import asyncio
|
||||
import sys
|
||||
try:
|
||||
from asyncio import set_event_loop_policy, WindowsSelectorEventLoopPolicy
|
||||
except ImportError:
|
||||
pass
|
||||
import json
|
||||
from voluptuous.schema_builder import message
|
||||
from cbpi.api.dataclasses import NotificationType
|
||||
|
@ -82,6 +87,11 @@ async def error_middleware(request, handler):
|
|||
class CraftBeerPi:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
operationsystem= sys.platform
|
||||
if operationsystem.startswith('win'):
|
||||
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
||||
|
||||
self.path = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-1]) # The path to the package dir
|
||||
|
||||
self.version = __version__
|
||||
|
|
|
@ -32,8 +32,9 @@ class FermenterNotificationStep(CBPiFermentationStep):
|
|||
|
||||
if self.AutoNext == True:
|
||||
self.cbpi.notify(self.name, self.props.get("Notification",""), NotificationType.INFO)
|
||||
await self.next(self.fermenter.id)
|
||||
return StepResult.DONE
|
||||
if self.shutdown != True:
|
||||
await self.next(self.fermenter.id)
|
||||
return StepResult.DONE
|
||||
else:
|
||||
self.cbpi.notify(self.name, self.props.get("Notification",""), NotificationType.INFO, action=[NotificationAction("Next Step", self.NextStep)])
|
||||
await self.push_update()
|
||||
|
@ -42,6 +43,7 @@ class FermenterNotificationStep(CBPiFermentationStep):
|
|||
await self.push_update()
|
||||
|
||||
async def on_start(self):
|
||||
self.shutdown = False
|
||||
self.summary=""
|
||||
self.AutoNext = False if self.props.get("AutoNext", "No") == "No" else True
|
||||
if self.timer is None:
|
||||
|
@ -69,13 +71,12 @@ class FermenterNotificationStep(CBPiFermentationStep):
|
|||
class FermenterTargetTempStep(CBPiFermentationStep):
|
||||
|
||||
async def NextStep(self, **kwargs):
|
||||
await self.next(self.fermenter.id)
|
||||
return StepResult.DONE
|
||||
if self.shutdown != True:
|
||||
await self.next(self.fermenter.id)
|
||||
return StepResult.DONE
|
||||
|
||||
|
||||
async def on_timer_done(self,timer):
|
||||
self.summary = ""
|
||||
#self.fermenter.target_temp = 0
|
||||
await self.push_update()
|
||||
if self.AutoMode == True:
|
||||
await self.setAutoMode(False)
|
||||
|
@ -88,10 +89,10 @@ class FermenterTargetTempStep(CBPiFermentationStep):
|
|||
await self.push_update()
|
||||
|
||||
async def on_start(self):
|
||||
self.shutdown = False
|
||||
self.AutoMode = True if self.props.get("AutoMode","No") == "Yes" else False
|
||||
self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value")
|
||||
if self.fermenter is not None:
|
||||
self.fermenter.target_temp = int(self.props.get("Temp", 0))
|
||||
self.fermenter.target_temp = float(self.props.get("Temp", 0))
|
||||
if self.AutoMode == True:
|
||||
await self.setAutoMode(True)
|
||||
self.summary = "Waiting for Target Temp"
|
||||
|
@ -107,6 +108,9 @@ class FermenterTargetTempStep(CBPiFermentationStep):
|
|||
await self.push_update()
|
||||
|
||||
async def run(self):
|
||||
while self.get_sensor_value(self.props.get("Sensor", None)).get("value") > 900:
|
||||
await asyncio.sleep(1)
|
||||
self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value")
|
||||
if self.fermenter.target_temp >= self.starttemp:
|
||||
logging.info("warmup")
|
||||
while self.running == True:
|
||||
|
@ -128,6 +132,7 @@ class FermenterTargetTempStep(CBPiFermentationStep):
|
|||
|
||||
async def reset(self):
|
||||
self.timer = Timer(1 ,on_update=self.on_timer_update, on_done=self.on_timer_done)
|
||||
self.timer.is_running == False
|
||||
|
||||
async def setAutoMode(self, auto_state):
|
||||
try:
|
||||
|
@ -162,13 +167,15 @@ class FermenterStep(CBPiFermentationStep):
|
|||
else:
|
||||
self.cbpi.notify(self.name, 'Timer is already running', NotificationType.WARNING)
|
||||
|
||||
#@action("Add 5 Minutes to Timer", [])
|
||||
#async def add_timer(self):
|
||||
# if self.timer.is_running == True:
|
||||
# self.cbpi.notify(self.name, '5 Minutes added', NotificationType.INFO)
|
||||
# await self.timer.add(300)
|
||||
# else:
|
||||
# self.cbpi.notify(self.name, 'Timer must be running to add time', NotificationType.WARNING)
|
||||
# @action("Add 1 Day to Timer", [])
|
||||
# async def add_timer(self):
|
||||
# if self.timer.is_running == True:
|
||||
# self.cbpi.notify(self.name, '1 Day added', NotificationType.INFO)
|
||||
# await self.timer.add(86400)
|
||||
# self.endtime = self.endtime +86400
|
||||
# await self.update_endtime()
|
||||
# else:
|
||||
# self.cbpi.notify(self.name, 'Timer must be running to add time', NotificationType.WARNING)
|
||||
|
||||
|
||||
async def on_timer_done(self,timer):
|
||||
|
@ -176,8 +183,9 @@ class FermenterStep(CBPiFermentationStep):
|
|||
if self.AutoMode == True:
|
||||
await self.setAutoMode(False)
|
||||
self.cbpi.notify(self.name, 'Step finished', NotificationType.SUCCESS)
|
||||
await self.next(self.fermenter.id)
|
||||
return StepResult.DONE
|
||||
if self.shutdown != True:
|
||||
await self.next(self.fermenter.id)
|
||||
return StepResult.DONE
|
||||
|
||||
|
||||
async def on_timer_update(self,timer, seconds):
|
||||
|
@ -185,7 +193,8 @@ class FermenterStep(CBPiFermentationStep):
|
|||
await self.push_update()
|
||||
|
||||
async def on_start(self):
|
||||
if self.endtime == 0:
|
||||
self.shutdown = False
|
||||
if self.endtime == 0:
|
||||
timeD=int(self.props.get("TimerD", 0))
|
||||
timeH=int(self.props.get("TimerH", 0))
|
||||
timeM=int(self.props.get("TimerM", 0))
|
||||
|
@ -194,9 +203,8 @@ class FermenterStep(CBPiFermentationStep):
|
|||
self.fermentationtime = self.endtime - time.time()
|
||||
|
||||
self.AutoMode = True if self.props.get("AutoMode", "No") == "Yes" else False
|
||||
self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value")
|
||||
if self.fermenter is not None:
|
||||
self.fermenter.target_temp = int(self.props.get("Temp", 0))
|
||||
self.fermenter.target_temp = float(self.props.get("Temp", 0))
|
||||
if self.AutoMode == True:
|
||||
await self.setAutoMode(True)
|
||||
await self.push_update()
|
||||
|
@ -217,6 +225,9 @@ class FermenterStep(CBPiFermentationStep):
|
|||
if self.endtime != 0 and self.timer is not None and self.timer.is_running == False:
|
||||
self.timer.start()
|
||||
self.timer.is_running = True
|
||||
estimated_completion_time = datetime.fromtimestamp(time.time()+ self.fermentationtime)
|
||||
self.cbpi.notify(self.name, 'Timer restarted. Estimated completion: {}'.format(estimated_completion_time.strftime("%d.%m, %H:%M")), NotificationType.INFO)
|
||||
|
||||
|
||||
self.summary = "Waiting for Target Temp"
|
||||
await self.push_update()
|
||||
|
@ -229,17 +240,19 @@ class FermenterStep(CBPiFermentationStep):
|
|||
await self.push_update()
|
||||
|
||||
async def reset(self):
|
||||
await self.timer.stop()
|
||||
timeD=int(self.props.get("TimerD", 0))
|
||||
timeH=int(self.props.get("TimerH", 0))
|
||||
timeM=int(self.props.get("TimerM", 0))
|
||||
self.fermentationtime=(timeM+(60*timeH)+(1440*timeD)) *60
|
||||
|
||||
self.timer = Timer(self.fermentationtime ,on_update=self.on_timer_update, on_done=self.on_timer_done)
|
||||
self.endtime = 0
|
||||
await self.update_endtime()
|
||||
self.timer.is_running == False
|
||||
|
||||
async def run(self):
|
||||
while self.get_sensor_value(self.props.get("Sensor", None)).get("value") > 900:
|
||||
await asyncio.sleep(1)
|
||||
self.starttemp= self.get_sensor_value(self.props.get("Sensor", None)).get("value")
|
||||
|
||||
if self.fermenter.target_temp >= self.starttemp:
|
||||
logging.info("warmup")
|
||||
while self.running == True:
|
||||
|
@ -278,43 +291,6 @@ class FermenterStep(CBPiFermentationStep):
|
|||
except Exception as e:
|
||||
logging.error("Failed to switch on FermenterLogic {} {}".format(self.fermenter.id, e))
|
||||
|
||||
@parameters([Property.Number(label="TimerD", description="Timer Days", configurable=True),
|
||||
Property.Number(label="TimerH", description="Timer Hours", configurable=True),
|
||||
Property.Number(label="TimerM", description="Timer Minutes", configurable=True)
|
||||
])
|
||||
class FermenterWaitStep(CBPiFermentationStep):
|
||||
|
||||
async def on_timer_done(self, timer):
|
||||
self.summary = ""
|
||||
await self.next(self.fermenter.id)
|
||||
return StepResult.DONE
|
||||
|
||||
async def on_timer_update(self, timer, seconds):
|
||||
self.summary = Timer.format_time(seconds)
|
||||
await self.push_update()
|
||||
|
||||
async def on_start(self):
|
||||
timeD=int(self.props.get("TimerD", 0))
|
||||
timeH=int(self.props.get("TimerH", 0))
|
||||
timeM=int(self.props.get("TimerM", 0))
|
||||
self.fermentationtime=(timeM+(60*timeH)+(1440*timeD)) *60
|
||||
|
||||
if self.timer is None:
|
||||
self.timer = Timer(self.fermentationtime, on_update=self.on_timer_update, on_done=self.on_timer_done)
|
||||
self.timer.start()
|
||||
|
||||
async def on_stop(self):
|
||||
await self.timer.stop()
|
||||
self.summary = ""
|
||||
await self.push_update()
|
||||
|
||||
async def reset(self):
|
||||
self.timer = Timer(self.fermentationtime, on_update=self.on_timer_update, on_done=self.on_timer_done)
|
||||
|
||||
async def run(self):
|
||||
while self.running == True:
|
||||
await asyncio.sleep(1)
|
||||
return StepResult.DONE
|
||||
|
||||
def setup(cbpi):
|
||||
'''
|
||||
|
@ -328,4 +304,3 @@ def setup(cbpi):
|
|||
cbpi.plugin.register("FermenterNotificationStep", FermenterNotificationStep)
|
||||
cbpi.plugin.register("FermenterTargetTempStep", FermenterTargetTempStep)
|
||||
cbpi.plugin.register("FermenterStep", FermenterStep)
|
||||
#cbpi.plugin.register("FermenterWaitStep", FermenterWaitStep)
|
|
@ -33,7 +33,7 @@ class FermenterAutostart(CBPiExtension):
|
|||
try:
|
||||
if (self.fermenter.instance is None or self.fermenter.instance.state == False):
|
||||
await self.cbpi.fermenter.start(self.fermenter.id)
|
||||
logging.info("Successfully switched on Fermenterlogic for Fermenter {}".format(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:
|
||||
|
|
|
@ -10,7 +10,7 @@ logger = logging.getLogger(__name__)
|
|||
try:
|
||||
import RPi.GPIO as GPIO
|
||||
except Exception:
|
||||
logger.warning("Failed to load RPi.GPIO. Using Mock")
|
||||
logger.warning("Failed to load RPi.GPIO. Using Mock instead")
|
||||
MockRPi = MagicMock()
|
||||
modules = {
|
||||
"RPi": MockRPi,
|
||||
|
|
|
@ -22,6 +22,8 @@ class MQTTActor(CBPiActor):
|
|||
async def on_start(self):
|
||||
self.topic = self.props.get("Topic", None)
|
||||
self.power = 100
|
||||
await self.off()
|
||||
self.state = False
|
||||
|
||||
async def on(self, power=None):
|
||||
if power is not None:
|
||||
|
|
|
@ -18,7 +18,7 @@ class MQTTSensor(CBPiSensor):
|
|||
if self.payload_text != None:
|
||||
self.payload_text = self.payload_text.split('.')
|
||||
self.mqtt_task = self.cbpi.satellite.subcribe(self.Topic, self.on_message)
|
||||
self.value: int = 0
|
||||
self.value: float = 999
|
||||
|
||||
async def on_message(self, message):
|
||||
val = json.loads(message)
|
||||
|
|
|
@ -313,8 +313,8 @@ class FermentationHttpEndpoints():
|
|||
|
||||
data = await request.json()
|
||||
fermenterid= request.match_info['id']
|
||||
newstep = {"name": data.get("name"), "props": data.get("props", {}), "type": data.get("type")}
|
||||
response_data = await self.controller.create_step(fermenterid,newstep)
|
||||
newstep = {"name": data.get("name"), "props": data.get("props", {}), "endtime": 0, "type": data.get("type")}
|
||||
response_data = await self.controller.add_step(fermenterid,newstep)
|
||||
return web.json_response(data=response_data.to_dict())
|
||||
|
||||
@request_mapping(path="/{fermenterid}/{stepid}", method="PUT", auth_required=False)
|
||||
|
@ -352,7 +352,7 @@ class FermentationHttpEndpoints():
|
|||
data = await request.json()
|
||||
stepid = request.match_info['stepid']
|
||||
fermenterid = request.match_info['fermenterid']
|
||||
updatedstep = {"id": stepid, "name": data.get("name"), "props": data.get("props", {}), "type": data.get("type")}
|
||||
updatedstep = {"id": stepid, "name": data.get("name"), "endtime": 0, "props": data.get("props", {}), "type": data.get("type")}
|
||||
#step = FermenterStep(stepid, data.get("name"), None, Props(data.get("props", {})), data.get("type"))
|
||||
await self.controller.update_step(fermenterid,updatedstep)
|
||||
return web.Response(status=200)
|
||||
|
|
|
@ -117,7 +117,7 @@ class FermenterRecipeHttpEndpoints():
|
|||
await self.controller.remove(name)
|
||||
return web.Response(status=204)
|
||||
|
||||
@request_mapping(path="/{name}/{fermenterid}/brew", method="POST", auth_required=False)
|
||||
@request_mapping(path="/{recipeid}/{fermenterid}/{name}/brew", method="POST", auth_required=False)
|
||||
async def http_brew(self, request):
|
||||
|
||||
"""
|
||||
|
@ -137,9 +137,10 @@ class FermenterRecipeHttpEndpoints():
|
|||
"200":
|
||||
description: successful operation
|
||||
"""
|
||||
recipeid = request.match_info['recipeid']
|
||||
name = request.match_info['name']
|
||||
fermenterid = request.match_info['fermenterid']
|
||||
await self.controller.brew(name,fermenterid)
|
||||
await self.controller.brew(recipeid,fermenterid,name)
|
||||
return web.Response(status=204)
|
||||
|
||||
@request_mapping(path="/{id}/clone", method="POST", auth_required=False)
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
aiohttp==3.7.4
|
||||
aiohttp==3.8.1
|
||||
aiohttp-auth==0.1.1
|
||||
aiohttp-route-decorator==0.1.4
|
||||
aiohttp-security==0.4.0
|
||||
aiohttp-session==2.9.0
|
||||
aiohttp-swagger==1.0.15
|
||||
aiojobs==0.3.0
|
||||
aiosqlite==0.16.0
|
||||
cryptography==3.3.2
|
||||
requests==2.25.1
|
||||
voluptuous==0.12.1
|
||||
aiohttp-session==2.11.0
|
||||
aiohttp-swagger==1.0.16
|
||||
aiojobs==1.0.0
|
||||
aiosqlite==0.17.0
|
||||
cryptography==36.0.1
|
||||
requests==2.27.1
|
||||
voluptuous==0.12.2
|
||||
pyfiglet==0.8.post1
|
||||
pandas==1.4.0
|
||||
shortuuid==1.0.1
|
||||
tabulate==0.8.7
|
||||
numpy==1.22.0
|
||||
pandas==1.4.1
|
||||
shortuuid==1.0.8
|
||||
tabulate==0.8.9
|
||||
numpy==1.22.2
|
||||
cbpi4ui
|
||||
click==7.1.2
|
||||
importlib_metadata==4.8.2
|
||||
click==8.0.4
|
||||
importlib_metadata==4.11.1
|
||||
asyncio-mqtt
|
||||
psutil==5.8.0
|
||||
psutil==5.9.0
|
||||
zipp>=0.5
|
||||
PyInquirer==1.0.3
|
||||
colorama==0.4.4
|
37
setup.py
37
setup.py
|
@ -27,34 +27,33 @@ setup(name='cbpi',
|
|||
'': ['*.txt', '*.rst', '*.yaml'],
|
||||
'cbpi': ['*','*.txt', '*.rst', '*.yaml']},
|
||||
|
||||
python_requires='>=3',
|
||||
python_requires='>=3.9',
|
||||
|
||||
install_requires=[
|
||||
"aiohttp==3.7.4",
|
||||
"aiohttp==3.8.1",
|
||||
"aiohttp-auth==0.1.1",
|
||||
"aiohttp-route-decorator==0.1.4",
|
||||
"aiohttp-security==0.4.0",
|
||||
"aiohttp-session==2.9.0",
|
||||
"aiohttp-swagger==1.0.15",
|
||||
"aiojobs==0.3.0",
|
||||
"aiosqlite==0.16.0",
|
||||
"cryptography==3.3.2",
|
||||
"requests==2.25.1",
|
||||
"voluptuous==0.12.1",
|
||||
"aiohttp-session==2.11.0",
|
||||
"aiohttp-swagger==1.0.16",
|
||||
"aiojobs==1.0.0 ",
|
||||
"aiosqlite==0.17.0",
|
||||
"cryptography==36.0.1",
|
||||
"requests==2.27.1",
|
||||
"voluptuous==0.12.2",
|
||||
"pyfiglet==0.8.post1",
|
||||
'click==7.1.2',
|
||||
'shortuuid==1.0.1',
|
||||
'tabulate==0.8.7',
|
||||
'click==8.0.4',
|
||||
'shortuuid==1.0.8',
|
||||
'tabulate==0.8.9',
|
||||
'asyncio-mqtt',
|
||||
'psutil==5.8.0',
|
||||
'colorama==0.4.4',
|
||||
'PyInquirer==1.0.3',
|
||||
'colorama==0.4.4',
|
||||
'psutil==5.9.0',
|
||||
'cbpi4ui',
|
||||
'importlib_metadata'] + (
|
||||
['RPi.GPIO==0.7.1'] if raspberrypi else [] ) +
|
||||
(['numpy==1.22.0'] if (int(platform.python_version_tuple()[1]) >= 9) and (int(platform.python_version_tuple()[0]) == 3) else ['numpy==1.20.3'] ) +
|
||||
(['pandas==1.4.0'] if (int(platform.python_version_tuple()[1]) >= 9) and (int(platform.python_version_tuple()[0]) == 3) else ['pandas==1.1.5'] ),
|
||||
|
||||
'importlib_metadata',
|
||||
'numpy==1.22.2',
|
||||
'pandas==1.4.1'] + (
|
||||
['RPi.GPIO==0.7.1'] if raspberrypi else [] ),
|
||||
|
||||
dependency_links=[
|
||||
'https://testpypi.python.org/pypi',
|
||||
|
|
Loading…
Reference in a new issue