mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-25 16:38:36 +01:00
"mash profiles added"
This commit is contained in:
parent
ab14111787
commit
bd311edccd
19 changed files with 422 additions and 157 deletions
|
@ -1 +1 @@
|
||||||
__version__ = "4.0.0.17"
|
__version__ = "4.0.0.18"
|
|
@ -14,7 +14,8 @@ __all__ = ["CBPiActor",
|
||||||
"SensorException",
|
"SensorException",
|
||||||
"ActorException",
|
"ActorException",
|
||||||
"CBPiSensor",
|
"CBPiSensor",
|
||||||
"CBPiStep"]
|
"CBPiStep",
|
||||||
|
"Stop_Reason"]
|
||||||
|
|
||||||
from cbpi.api.actor import *
|
from cbpi.api.actor import *
|
||||||
from cbpi.api.sensor import *
|
from cbpi.api.sensor import *
|
||||||
|
|
64
cbpi/api/base.py
Normal file
64
cbpi/api/base.py
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
from abc import abstractmethod, ABCMeta
|
||||||
|
import asyncio
|
||||||
|
from cbpi.api.config import ConfigType
|
||||||
|
import time
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CBPiBase(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
def get_static_config_value(self,name,default):
|
||||||
|
return self.cbpi.static_config.get(name, default)
|
||||||
|
|
||||||
|
def get_config_value(self,name,default):
|
||||||
|
return self.cbpi.config.get(name, default=default)
|
||||||
|
|
||||||
|
async def set_config_value(self,name,value):
|
||||||
|
return await self.cbpi.config.set(name,value)
|
||||||
|
|
||||||
|
async def add_config_value(self, name, value, type: ConfigType, description, options=None):
|
||||||
|
await self.cbpi.add(name, value, type, description, options=None)
|
||||||
|
|
||||||
|
def get_kettle(self,id):
|
||||||
|
return self.cbpi.kettle.find_by_id(id)
|
||||||
|
|
||||||
|
async def set_target_temp(self,id, temp):
|
||||||
|
await self.cbpi.kettle.set_target_temp(id, temp)
|
||||||
|
|
||||||
|
def get_sensor(self,id):
|
||||||
|
return self.cbpi.sensor.find_by_id(id)
|
||||||
|
|
||||||
|
def get_sensor_value(self,id):
|
||||||
|
return self.cbpi.sensor.get_sensor_value(id)
|
||||||
|
|
||||||
|
def get_actor(self,id):
|
||||||
|
return self.cbpi.actor.find_by_id(id)
|
||||||
|
|
||||||
|
def get_actor_state(self,id):
|
||||||
|
try:
|
||||||
|
actor = self.cbpi.actor.find_by_id(id)
|
||||||
|
return actor.get("instance").get_state()
|
||||||
|
except:
|
||||||
|
logging.error("Faild to read actor state in step - actor {}".format(id))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def actor_on(self,id):
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("\n\n ON\n\n\n\n" )
|
||||||
|
await self.cbpi.actor.on(id)
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def actor_off(self,id):
|
||||||
|
try:
|
||||||
|
print("\n\n OFF\n\n\n\n" )
|
||||||
|
await self.cbpi.actor.off(id)
|
||||||
|
except Exception as e:
|
||||||
|
print("E", e)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
|
@ -50,3 +50,5 @@ class CBPiExtension():
|
||||||
except:
|
except:
|
||||||
logger.warning("Faild to load config %s/config.yaml" % path)
|
logger.warning("Faild to load config %s/config.yaml" % path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ from abc import abstractmethod, ABCMeta
|
||||||
from cbpi.api.extension import CBPiExtension
|
from cbpi.api.extension import CBPiExtension
|
||||||
|
|
||||||
from cbpi.api.config import ConfigType
|
from cbpi.api.config import ConfigType
|
||||||
|
from cbpi.api.base import CBPiBase
|
||||||
|
|
||||||
|
class CBPiSensor(CBPiBase, metaclass=ABCMeta):
|
||||||
class CBPiSensor(metaclass=ABCMeta):
|
|
||||||
|
|
||||||
def __init__(self, cbpi, id, props):
|
def __init__(self, cbpi, id, props):
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
|
@ -35,18 +35,6 @@ class CBPiSensor(metaclass=ABCMeta):
|
||||||
def get_unit(self):
|
def get_unit(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_static_config_value(self,name,default):
|
|
||||||
return self.cbpi.static_config.get(name, default)
|
|
||||||
|
|
||||||
def get_config_value(self,name,default):
|
|
||||||
return self.cbpi.config.get(name, default=default)
|
|
||||||
|
|
||||||
async def set_config_value(self,name,value):
|
|
||||||
return await self.cbpi.config.set(name,value)
|
|
||||||
|
|
||||||
async def add_config_value(self, name, value, type: ConfigType, description, options=None):
|
|
||||||
await self.cbpi.add(name, value, type, description, options=None)
|
|
||||||
|
|
||||||
def push_update(self, value):
|
def push_update(self, value):
|
||||||
try:
|
try:
|
||||||
self.cbpi.ws.send(dict(topic="sensorstate", id=self.id, value=value))
|
self.cbpi.ws.send(dict(topic="sensorstate", id=self.id, value=value))
|
||||||
|
@ -57,5 +45,4 @@ class CBPiSensor(metaclass=ABCMeta):
|
||||||
self.running = True
|
self.running = True
|
||||||
|
|
||||||
async def stop(self):
|
async def stop(self):
|
||||||
|
|
||||||
self.running = False
|
self.running = False
|
107
cbpi/api/step.py
107
cbpi/api/step.py
|
@ -5,8 +5,15 @@ import logging
|
||||||
from abc import abstractmethod, ABCMeta
|
from abc import abstractmethod, ABCMeta
|
||||||
import logging
|
import logging
|
||||||
from cbpi.api.config import ConfigType
|
from cbpi.api.config import ConfigType
|
||||||
|
from cbpi.api.base import CBPiBase
|
||||||
|
from enum import Enum
|
||||||
|
__all__ = ["Stop_Reason", "CBPiStep"]
|
||||||
|
class Stop_Reason(Enum):
|
||||||
|
STOP = 1
|
||||||
|
NEXT = 2
|
||||||
|
|
||||||
class CBPiStep(metaclass=ABCMeta):
|
|
||||||
|
class CBPiStep(CBPiBase, metaclass=ABCMeta):
|
||||||
def __init__(self, cbpi, id, name, props) :
|
def __init__(self, cbpi, id, name, props) :
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
self.props = {**props}
|
self.props = {**props}
|
||||||
|
@ -17,91 +24,61 @@ class CBPiStep(metaclass=ABCMeta):
|
||||||
self.stop_reason = None
|
self.stop_reason = None
|
||||||
self.pause = False
|
self.pause = False
|
||||||
self.task = None
|
self.task = None
|
||||||
|
self._task = None
|
||||||
self._exception_count = 0
|
self._exception_count = 0
|
||||||
self._max_exceptions = 2
|
self._max_exceptions = 2
|
||||||
self.state_msg = "No state"
|
self.state_msg = ""
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
return self.state_msg
|
return self.state_msg
|
||||||
|
|
||||||
def stop(self):
|
def push_update(self):
|
||||||
self.stop_reason = "STOP"
|
self.cbpi.step.push_udpate()
|
||||||
self.running = False
|
|
||||||
|
|
||||||
def start(self):
|
async def stop(self):
|
||||||
self.running = True
|
self.stop_reason = Stop_Reason.STOP
|
||||||
|
self._task.cancel()
|
||||||
|
await self._task
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
self.stop_reason = None
|
self.stop_reason = None
|
||||||
|
self._task = asyncio.create_task(self.run())
|
||||||
|
self._task.add_done_callback(self.cbpi.step.done)
|
||||||
|
|
||||||
def next(self):
|
async def next(self):
|
||||||
self.stop_reason = "NEXT"
|
self.stop_reason = Stop_Reason.NEXT
|
||||||
self.running = False
|
self._task.cancel()
|
||||||
|
|
||||||
async def reset(self):
|
async def reset(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def on_props_update(self, props):
|
||||||
|
self.props = props
|
||||||
|
|
||||||
async def update(self, props):
|
async def update(self, props):
|
||||||
await self.cbpi.step.update_props(self.id, props)
|
await self.cbpi.step.update_props(self.id, props)
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
while self.running:
|
try:
|
||||||
try:
|
while True:
|
||||||
await self.execute()
|
try:
|
||||||
except Exception as e:
|
await self.execute()
|
||||||
self._exception_count += 1
|
except asyncio.CancelledError as e:
|
||||||
logging.error("Step has thrown exception")
|
raise e
|
||||||
if self._exception_count >= self._max_exceptions:
|
except Exception as e:
|
||||||
self.stop_reason = "MAX_EXCEPTIONS"
|
self._exception_count += 1
|
||||||
return (self.id, self.stop_reason)
|
logging.error("Step has thrown exception")
|
||||||
await asyncio.sleep(1)
|
if self._exception_count >= self._max_exceptions:
|
||||||
|
self.stop_reason = "MAX_EXCEPTIONS"
|
||||||
return (self.id, self.stop_reason)
|
return (self.id, self.stop_reason)
|
||||||
|
except asyncio.CancelledError as e:
|
||||||
|
return self.id, self.stop_reason
|
||||||
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def execute(self):
|
async def execute(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_static_config_value(self,name,default):
|
|
||||||
return self.cbpi.static_config.get(name, default)
|
|
||||||
|
|
||||||
def get_config_value(self,name,default):
|
|
||||||
return self.cbpi.config.get(name, default=default)
|
|
||||||
|
|
||||||
async def set_config_value(self,name,value):
|
|
||||||
return await self.cbpi.config.set(name,value)
|
|
||||||
|
|
||||||
async def add_config_value(self, name, value, type: ConfigType, description, options=None):
|
|
||||||
await self.cbpi.add(name, value, type, description, options=None)
|
|
||||||
|
|
||||||
def get_kettle(self,id):
|
|
||||||
return self.cbpi.kettle.find_by_id(id)
|
|
||||||
|
|
||||||
async def set_target_temp(self,id, temp):
|
|
||||||
await self.cbpi.kettle.set_target_temp(id, temp)
|
|
||||||
|
|
||||||
def get_sensor(self,id):
|
|
||||||
return self.cbpi.sensor.find_by_id(id)
|
|
||||||
|
|
||||||
def get_actor(self,id):
|
|
||||||
return self.cbpi.actor.find_by_id(id)
|
|
||||||
|
|
||||||
def get_actor_state(self,id):
|
|
||||||
try:
|
|
||||||
actor = self.cbpi.actor.find_by_id(id)
|
|
||||||
return actor.get("instance").get_state()
|
|
||||||
except:
|
|
||||||
logging.error("Faild to read actor state in step - actor {}".format(id))
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def actor_on(self,id):
|
|
||||||
|
|
||||||
try:
|
|
||||||
await self.cbpi.actor.on(id)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def actor_off(self,id):
|
|
||||||
try:
|
|
||||||
await self.cbpi.actor.off(id)
|
|
||||||
except:
|
|
||||||
pass
|
|
59
cbpi/api/timer.py
Normal file
59
cbpi/api/timer.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import time
|
||||||
|
import asyncio
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
class Timer(object):
|
||||||
|
|
||||||
|
def __init__(self, timeout, callback, update = None) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.timeout = timeout
|
||||||
|
self._timemout = self.timeout
|
||||||
|
self._task = None
|
||||||
|
self._callback = callback
|
||||||
|
self._update = update
|
||||||
|
self.start_time = None
|
||||||
|
|
||||||
|
async def _job(self):
|
||||||
|
self.start_time = time.time()
|
||||||
|
self.count = int(round(self._timemout, 0))
|
||||||
|
try:
|
||||||
|
for seconds in range(self.count, -1, -1):
|
||||||
|
if self._update is not None:
|
||||||
|
await self._update(seconds, self.format_time(seconds))
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
self._callback()
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
end = time.time()
|
||||||
|
duration = end - self.start_time
|
||||||
|
self._timemout = self._timemout - duration
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self._task = asyncio.create_task(self._job())
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
self._task.cancel()
|
||||||
|
await self._task
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
if self.is_running is True:
|
||||||
|
return
|
||||||
|
self._timemout = self.timeout
|
||||||
|
|
||||||
|
def is_running(self):
|
||||||
|
return not self._task.done()
|
||||||
|
|
||||||
|
def set_time(self,timeout):
|
||||||
|
if self.is_running is True:
|
||||||
|
return
|
||||||
|
self.timeout = timeout
|
||||||
|
|
||||||
|
def get_time(self):
|
||||||
|
return self.format_time(int(round(self._timemout,0)))
|
||||||
|
|
||||||
|
def format_time(self, time):
|
||||||
|
pattern = '{0:02d}:{1:02d}:{2:02d}'
|
||||||
|
seconds = time % 60
|
||||||
|
minutes = math.floor(time / 60) % 60
|
||||||
|
hours = math.floor(time / 3600)
|
||||||
|
return pattern.format(hours, minutes, seconds)
|
|
@ -12,6 +12,7 @@ class ActorController(BasicController):
|
||||||
item = self.find_by_id(id)
|
item = self.find_by_id(id)
|
||||||
instance = item.get("instance")
|
instance = item.get("instance")
|
||||||
await instance.on()
|
await instance.on()
|
||||||
|
await self.push_udpate()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ class ActorController(BasicController):
|
||||||
item = self.find_by_id(id)
|
item = self.find_by_id(id)
|
||||||
instance = item.get("instance")
|
instance = item.get("instance")
|
||||||
await instance.off()
|
await instance.off()
|
||||||
|
await self.push_udpate()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,16 @@ class SensorController(BasicController):
|
||||||
def create_dict(self, data):
|
def create_dict(self, data):
|
||||||
try:
|
try:
|
||||||
instance = data.get("instance")
|
instance = data.get("instance")
|
||||||
state = state=instance.get_state()
|
state =instance.get_state()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Faild to create sensor dict {} ".format(e))
|
logging.error("Faild to create sensor dict {} ".format(e))
|
||||||
state = dict()
|
state = dict()
|
||||||
|
|
||||||
return dict(name=data.get("name"), id=data.get("id"), type=data.get("type"), state=state,props=data.get("props", []))
|
return dict(name=data.get("name"), id=data.get("id"), type=data.get("type"), state=state,props=data.get("props", []))
|
||||||
|
|
||||||
|
def get_sensor_value(self, id):
|
||||||
|
try:
|
||||||
|
return self.find_by_id(id).get("instance").get_state()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Faild read sensor value {} {} ".format(id, e))
|
||||||
|
return None
|
|
@ -7,7 +7,7 @@ import shortuuid
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from ..api.step import CBPiStep
|
from ..api.step import CBPiStep, Stop_Reason
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,8 +59,15 @@ class StepController:
|
||||||
|
|
||||||
async def update(self, id, data):
|
async def update(self, id, data):
|
||||||
logging.info("update step")
|
logging.info("update step")
|
||||||
|
def merge_data(id, old, data):
|
||||||
|
step = {**old, **data}
|
||||||
|
try:
|
||||||
|
step["instance"] = self.create_step(id,data["type"], data["name"], data["props"])
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Faild create step instance during update props")
|
||||||
|
return step
|
||||||
|
|
||||||
self.profile = list(map(lambda old: {**old, **data} if old["id"] == id else old, self.profile))
|
self.profile = list(map(lambda old: {**merge_data(id, old, data)} if old["id"] == id else old, self.profile))
|
||||||
await self.save()
|
await self.save()
|
||||||
return self.find_by_id(id)
|
return self.find_by_id(id)
|
||||||
|
|
||||||
|
@ -69,7 +76,7 @@ class StepController:
|
||||||
data = dict(basic=self.basic_data, profile=list(map(lambda x: dict(name=x["name"], type=x.get("type"), id=x["id"], status=x["status"],props=x["props"]), self.profile)))
|
data = dict(basic=self.basic_data, profile=list(map(lambda x: dict(name=x["name"], type=x.get("type"), id=x["id"], status=x["status"],props=x["props"]), self.profile)))
|
||||||
with open(self.path, "w") as file:
|
with open(self.path, "w") as file:
|
||||||
json.dump(data, file, indent=4, sort_keys=True)
|
json.dump(data, file, indent=4, sort_keys=True)
|
||||||
await self.push_udpate()
|
self.push_udpate()
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
# already running
|
# already running
|
||||||
|
@ -88,7 +95,7 @@ class StepController:
|
||||||
|
|
||||||
step = self.find_by_status("I")
|
step = self.find_by_status("I")
|
||||||
if step is not None:
|
if step is not None:
|
||||||
logging.info("Start Step")
|
logging.info("####### Start Step")
|
||||||
|
|
||||||
await self.start_step(step)
|
await self.start_step(step)
|
||||||
await self.save()
|
await self.save()
|
||||||
|
@ -102,9 +109,14 @@ class StepController:
|
||||||
if step is not None:
|
if step is not None:
|
||||||
instance = step.get("instance")
|
instance = step.get("instance")
|
||||||
if instance is not None:
|
if instance is not None:
|
||||||
logging.info("Next")
|
await instance.next()
|
||||||
instance.next()
|
step = self.find_by_status("P")
|
||||||
await instance.task
|
if step is not None:
|
||||||
|
instance = step.get("instance")
|
||||||
|
if instance is not None:
|
||||||
|
step["status"] = "D"
|
||||||
|
await self.save()
|
||||||
|
await self.start()
|
||||||
else:
|
else:
|
||||||
logging.info("No Step is running")
|
logging.info("No Step is running")
|
||||||
|
|
||||||
|
@ -123,9 +135,7 @@ class StepController:
|
||||||
if step != None and step.get("instance") is not None:
|
if step != None and step.get("instance") is not None:
|
||||||
logging.info("CALLING STOP STEP")
|
logging.info("CALLING STOP STEP")
|
||||||
instance = step.get("instance")
|
instance = step.get("instance")
|
||||||
instance.stop()
|
await instance.stop()
|
||||||
# wait for task to be finished
|
|
||||||
await instance.task
|
|
||||||
logging.info("STEP STOPPED")
|
logging.info("STEP STOPPED")
|
||||||
step["status"] = "P"
|
step["status"] = "P"
|
||||||
await self.save()
|
await self.save()
|
||||||
|
@ -139,10 +149,10 @@ class StepController:
|
||||||
logging.info("Reset %s" % item.get("name"))
|
logging.info("Reset %s" % item.get("name"))
|
||||||
item["status"] = "I"
|
item["status"] = "I"
|
||||||
await item["instance"].reset()
|
await item["instance"].reset()
|
||||||
await self.push_udpate()
|
self.push_udpate()
|
||||||
|
|
||||||
def create_step(self, id, type, name, props):
|
def create_step(self, id, type, name, props):
|
||||||
|
print(id, type, name, props)
|
||||||
try:
|
try:
|
||||||
type_cfg = self.types.get(type)
|
type_cfg = self.types.get(type)
|
||||||
clazz = type_cfg.get("class")
|
clazz = type_cfg.get("class")
|
||||||
|
@ -169,7 +179,7 @@ class StepController:
|
||||||
return
|
return
|
||||||
self.profile[index], self.profile[index+direction] = self.profile[index+direction], self.profile[index]
|
self.profile[index], self.profile[index+direction] = self.profile[index+direction], self.profile[index]
|
||||||
await self.save()
|
await self.save()
|
||||||
await self.push_udpate()
|
self.push_udpate()
|
||||||
|
|
||||||
async def delete(self, id):
|
async def delete(self, id):
|
||||||
step = self.find_by_id(id)
|
step = self.find_by_id(id)
|
||||||
|
@ -188,22 +198,23 @@ class StepController:
|
||||||
# Stopping all running task
|
# Stopping all running task
|
||||||
if instance.task != None and instance.task.done() is False:
|
if instance.task != None and instance.task.done() is False:
|
||||||
logging.info("Stop Step")
|
logging.info("Stop Step")
|
||||||
instance.stop()
|
await instance.stop()
|
||||||
await instance.task
|
await instance.task
|
||||||
await self.save()
|
await self.save()
|
||||||
|
|
||||||
def done(self, task):
|
def done(self, task):
|
||||||
|
|
||||||
id, reason = task.result()
|
id, reason = task.result()
|
||||||
|
print("DONE", id, reason)
|
||||||
if reason == "MAX_EXCEPTIONS":
|
if reason == "MAX_EXCEPTIONS":
|
||||||
step_current = self.find_by_id(id)
|
step_current = self.find_by_id(id)
|
||||||
step_current["status"] = "E"
|
step_current["status"] = "E"
|
||||||
self._loop.create_task(self.save())
|
self._loop.create_task(self.save())
|
||||||
return
|
return
|
||||||
|
|
||||||
if reason == "NEXT":
|
if reason == Stop_Reason.NEXT:
|
||||||
step_current = self.find_by_status("A")
|
step_current = self.find_by_status("A")
|
||||||
if step_current is not None:
|
if step_current is not None:
|
||||||
|
|
||||||
step_current["status"] = "D"
|
step_current["status"] = "D"
|
||||||
async def wrapper():
|
async def wrapper():
|
||||||
## TODO DONT CALL SAVE
|
## TODO DONT CALL SAVE
|
||||||
|
@ -221,25 +232,27 @@ class StepController:
|
||||||
def get_index_by_id(self, id):
|
def get_index_by_id(self, id):
|
||||||
return next((i for i, item in enumerate(self.profile) if item["id"] == id), None)
|
return next((i for i, item in enumerate(self.profile) if item["id"] == id), None)
|
||||||
|
|
||||||
async def push_udpate(self):
|
def push_udpate(self):
|
||||||
self.cbpi.ws.send(dict(topic="step_update", data=list(map(lambda x: self.create_dict(x), self.profile))))
|
self.cbpi.ws.send(dict(topic="step_update", data=list(map(lambda x: self.create_dict(x), self.profile))))
|
||||||
|
|
||||||
async def start_step(self,step):
|
async def start_step(self,step):
|
||||||
logging.info("Start Step")
|
logging.info("Start Step")
|
||||||
step.get("instance").start()
|
try:
|
||||||
step["instance"].task = self._loop.create_task(step["instance"].run())
|
await step["instance"].start()
|
||||||
step["instance"].task .add_done_callback(self.done)
|
except Exception as e:
|
||||||
|
print(".........",e)
|
||||||
step["status"] = "A"
|
step["status"] = "A"
|
||||||
|
print("STARTED",step)
|
||||||
|
|
||||||
async def update_props(self, id, props):
|
async def update_props(self, id, props):
|
||||||
logging.info("SAVE PROPS")
|
logging.info("SAVE PROPS")
|
||||||
step = self.find_by_id(id)
|
step = self.find_by_id(id)
|
||||||
step["props"] = props
|
step["props"] = props
|
||||||
await self.save()
|
await self.save()
|
||||||
await self.push_udpate()
|
self.push_udpate()
|
||||||
|
|
||||||
async def save_basic(self, data):
|
async def save_basic(self, data):
|
||||||
logging.info("SAVE Basic Data")
|
logging.info("SAVE Basic Data")
|
||||||
self.basic_data = {**self.basic_data, **data,}
|
self.basic_data = {**self.basic_data, **data,}
|
||||||
await self.save()
|
await self.save()
|
||||||
await self.push_udpate()
|
self.push_udpate()
|
||||||
|
|
|
@ -30,11 +30,8 @@ class CustomSensor(CBPiSensor):
|
||||||
async def run(self):
|
async def run(self):
|
||||||
|
|
||||||
while self.running is True:
|
while self.running is True:
|
||||||
print(self.get_config_value("TEMP_UNIT", "NONE"))
|
|
||||||
print(self.get_static_config_value("port", "NONE"))
|
|
||||||
await self.set_config_value("BREWERY_NAME", "WOOHOO HELLO")
|
|
||||||
|
|
||||||
self.value = random.randint(0,50)
|
self.value = random.randint(0,10)
|
||||||
self.push_update(self.value)
|
self.push_update(self.value)
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,167 @@
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
from cbpi.api.timer import Timer
|
||||||
import random
|
|
||||||
from cbpi.api import *
|
from cbpi.api import *
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
@parameters([Property.Number(label="Timer", configurable=True),
|
@parameters([Property.Number(label="Timer", description="Time in Minutes", configurable=True),
|
||||||
Property.Number(label="Temp", configurable=True),
|
Property.Number(label="Temp", configurable=True),
|
||||||
|
Property.Sensor(label="Sensor"),
|
||||||
Property.Kettle(label="Kettle")])
|
Property.Kettle(label="Kettle")])
|
||||||
class MashStep(CBPiStep):
|
class MashStep(CBPiStep):
|
||||||
|
|
||||||
|
def __init__(self, cbpi, id, name, props):
|
||||||
|
super().__init__(cbpi, id, name, props)
|
||||||
|
self.timer = None
|
||||||
|
|
||||||
|
def timer_done(self):
|
||||||
|
self.state_msg = "Done"
|
||||||
|
asyncio.create_task(self.next())
|
||||||
|
|
||||||
|
async def timer_update(self, seconds, time):
|
||||||
|
self.state_msg = "{}".format(time)
|
||||||
|
self.push_update()
|
||||||
|
|
||||||
|
def start_timer(self):
|
||||||
|
if self.timer is None:
|
||||||
|
self.time = int(self.props.get("Timer", 0))
|
||||||
|
self.timer = Timer(self.time, self.timer_done, self.timer_update)
|
||||||
|
self.timer.start()
|
||||||
|
|
||||||
|
async def stop_timer(self):
|
||||||
|
if self.timer is not None:
|
||||||
|
await self.timer.stop()
|
||||||
|
self.state_msg = "{}".format(self.timer.get_time())
|
||||||
|
|
||||||
|
async def next(self):
|
||||||
|
if self.timer is not None:
|
||||||
|
await self.timer.stop()
|
||||||
|
self.state_msg = ""
|
||||||
|
await super().next()
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
await super().stop()
|
||||||
|
await self.stop_timer()
|
||||||
|
|
||||||
|
async def reset(self):
|
||||||
|
self.state_msg = ""
|
||||||
|
self.timer = None
|
||||||
|
await super().reset()
|
||||||
|
|
||||||
async def execute(self):
|
async def execute(self):
|
||||||
try:
|
if self.timer is None:
|
||||||
kid = self.props.get("Kettle", None)
|
self.state_msg = "Waiting for Target Temp"
|
||||||
kettle = self.get_kettle(kid)
|
self.push_update()
|
||||||
actor = self.get_actor(kettle.get("heater"))
|
else:
|
||||||
print(self.get_actor_state(kettle.get("heater")))
|
if self.timer is not None and self.timer.is_running() is False:
|
||||||
await self.cbpi.kettle.set_target_temp(kid, random.randint(0,50))
|
self.start_timer()
|
||||||
if self.v is True:
|
sensor_value = 0
|
||||||
await self.actor_on(kettle.get("heater"))
|
|
||||||
else:
|
|
||||||
await self.actor_off(kettle.get("heater"))
|
|
||||||
self.v = not self.v
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
sensor_value = self.get_sensor_value(self.props.get("Sensor"))
|
||||||
|
if sensor_value.get("value") >= 2 and self.timer == None:
|
||||||
|
self.start_timer()
|
||||||
|
|
||||||
|
@parameters([Property.Number(label="Timer", description="Time in Minutes", configurable=True)])
|
||||||
|
class WaitStep(CBPiStep):
|
||||||
|
|
||||||
|
def __init__(self, cbpi, id, name, props):
|
||||||
|
super().__init__(cbpi, id, name, props)
|
||||||
|
self.timer = None
|
||||||
|
|
||||||
|
def timer_done(self):
|
||||||
|
self.state_msg = "Done"
|
||||||
|
|
||||||
|
asyncio.create_task(self.next())
|
||||||
|
|
||||||
|
async def timer_update(self, seconds, time):
|
||||||
|
self.state_msg = "{}".format(time)
|
||||||
|
self.push_update()
|
||||||
|
|
||||||
|
def start_timer(self):
|
||||||
|
if self.timer is None:
|
||||||
|
self.time = int(self.props.get("Timer", 0))
|
||||||
|
self.timer = Timer(self.time, self.timer_done, self.timer_update)
|
||||||
|
self.timer.start()
|
||||||
|
|
||||||
|
async def stop_timer(self):
|
||||||
|
if self.timer is not None:
|
||||||
|
await self.timer.stop()
|
||||||
|
self.state_msg = "{}".format(self.timer.get_time())
|
||||||
|
|
||||||
|
async def next(self):
|
||||||
|
if self.timer is not None:
|
||||||
|
await self.timer.stop()
|
||||||
|
self.state_msg = ""
|
||||||
|
await super().next()
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
await super().stop()
|
||||||
|
await self.stop_timer()
|
||||||
|
|
||||||
|
async def reset(self):
|
||||||
|
self.state_msg = ""
|
||||||
|
self.timer = None
|
||||||
|
await super().reset()
|
||||||
|
|
||||||
|
async def execute(self):
|
||||||
|
self.start_timer()
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
@parameters([Property.Number(label="Timer", description="Time in Seconds", configurable=True),
|
||||||
|
Property.Actor(label="Actor")])
|
||||||
|
class ActorStep(CBPiStep):
|
||||||
|
|
||||||
|
def __init__(self, cbpi, id, name, props):
|
||||||
|
super().__init__(cbpi, id, name, props)
|
||||||
|
self.timer = None
|
||||||
|
|
||||||
|
def timer_done(self):
|
||||||
|
self.state_msg = "Done"
|
||||||
|
asyncio.create_task(self.actor_off(self.actor_id))
|
||||||
|
asyncio.create_task(self.next())
|
||||||
|
|
||||||
|
async def timer_update(self, seconds, time):
|
||||||
|
self.state_msg = "{}".format(time)
|
||||||
|
self.push_update()
|
||||||
|
|
||||||
|
def start_timer(self):
|
||||||
|
if self.timer is None:
|
||||||
|
self.time = int(self.props.get("Timer", 0))
|
||||||
|
self.timer = Timer(self.time, self.timer_done, self.timer_update)
|
||||||
|
self.timer.start()
|
||||||
|
|
||||||
|
async def stop_timer(self):
|
||||||
|
if self.timer is not None:
|
||||||
|
await self.timer.stop()
|
||||||
|
self.state_msg = "{}".format(self.timer.get_time())
|
||||||
|
|
||||||
|
async def next(self):
|
||||||
|
if self.timer is not None:
|
||||||
|
await self.timer.stop()
|
||||||
|
self.state_msg = ""
|
||||||
|
await super().next()
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
await super().stop()
|
||||||
|
await self.actor_off(self.actor_id)
|
||||||
|
await self.stop_timer()
|
||||||
|
|
||||||
|
async def reset(self):
|
||||||
|
self.state_msg = ""
|
||||||
|
self.timer = None
|
||||||
|
await super().reset()
|
||||||
|
|
||||||
|
async def execute(self):
|
||||||
|
self.start_timer()
|
||||||
|
self.actor_id = self.props.get("Actor")
|
||||||
|
await self.actor_on(self.actor_id)
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
def setup(cbpi):
|
def setup(cbpi):
|
||||||
'''
|
'''
|
||||||
|
@ -34,5 +171,8 @@ def setup(cbpi):
|
||||||
:param cbpi: the cbpi core
|
:param cbpi: the cbpi core
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
cbpi.plugin.register("ActorStep", ActorStep)
|
||||||
|
cbpi.plugin.register("WaitStep", WaitStep)
|
||||||
cbpi.plugin.register("MashStep", MashStep)
|
cbpi.plugin.register("MashStep", MashStep)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"id": "YwGzXvWMpmbLb6XobesL8n",
|
"id": "YwGzXvWMpmbLb6XobesL8n",
|
||||||
"name": "111",
|
"name": "Actor 1",
|
||||||
"props": {
|
"props": {
|
||||||
"GPIO": 4,
|
"GPIO": 4,
|
||||||
"Inverted": "Yes"
|
"Inverted": "Yes"
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "EsmZwWi9Qp3bzmXqq7N3Ly",
|
"id": "EsmZwWi9Qp3bzmXqq7N3Ly",
|
||||||
"name": "HALO",
|
"name": "Actor 2",
|
||||||
"props": {
|
"props": {
|
||||||
"Frequency": "20",
|
"Frequency": "20",
|
||||||
"GPIO": 5
|
"GPIO": 5
|
||||||
|
|
|
@ -102,18 +102,6 @@
|
||||||
365,
|
365,
|
||||||
160
|
160
|
||||||
],
|
],
|
||||||
[
|
|
||||||
285,
|
|
||||||
175
|
|
||||||
],
|
|
||||||
[
|
|
||||||
430,
|
|
||||||
420
|
|
||||||
],
|
|
||||||
[
|
|
||||||
240,
|
|
||||||
350
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
220,
|
220,
|
||||||
160
|
160
|
||||||
|
|
|
@ -3,7 +3,7 @@ version: 4.0
|
||||||
|
|
||||||
index_url: /cbpi_ui/static/index.html
|
index_url: /cbpi_ui/static/index.html
|
||||||
plugins:
|
plugins:
|
||||||
- cbpi4-ui
|
- cbpi4ui
|
||||||
|
|
||||||
port: 8080
|
port: 8080
|
||||||
# login data
|
# login data
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"props": {},
|
"props": {},
|
||||||
"sensor": "8ohkXvFA9UrkHLsxQL38wu",
|
"sensor": "8ohkXvFA9UrkHLsxQL38wu",
|
||||||
"state": {},
|
"state": {},
|
||||||
"target_temp": 25,
|
"target_temp": 45,
|
||||||
"type": "CustomKettleLogic"
|
"type": "CustomKettleLogic"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -11,6 +11,15 @@
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"type": "OneWire"
|
"type": "OneWire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "JUGteK9KrSVPDxboWjBS4N",
|
||||||
|
"name": "Test2",
|
||||||
|
"props": {},
|
||||||
|
"state": {
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"type": "CustomSensor"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -4,15 +4,27 @@
|
||||||
},
|
},
|
||||||
"profile": [
|
"profile": [
|
||||||
{
|
{
|
||||||
"id": "Gkjdsu45XPcfJimz4yHc4w",
|
"id": "SeL6hT9WxvA5yTsTakZuu8",
|
||||||
"name": "Test",
|
"name": "Pump Left",
|
||||||
"props": {
|
"props": {
|
||||||
"Kettle": "oHxKz3z5RjbsxfSz6KUgov",
|
"Actor": "YwGzXvWMpmbLb6XobesL8n",
|
||||||
"Temp": "2",
|
"Timer": "5"
|
||||||
"Timer": "1"
|
|
||||||
},
|
},
|
||||||
"status": "P",
|
"status": "D",
|
||||||
"type": "MashStep"
|
"type": "ActorStep"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "YwyRyzA2ePiiXXnET5gEeH",
|
||||||
|
"name": "Pump Right",
|
||||||
|
"props": {
|
||||||
|
"Actor": "EsmZwWi9Qp3bzmXqq7N3Ly",
|
||||||
|
"Kettle": "oHxKz3z5RjbsxfSz6KUgov",
|
||||||
|
"Sensor": "JUGteK9KrSVPDxboWjBS4N",
|
||||||
|
"Temp": "2",
|
||||||
|
"Timer": "5"
|
||||||
|
},
|
||||||
|
"status": "D",
|
||||||
|
"type": "ActorStep"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
8
sample.py
Normal file
8
sample.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
timerTime = 3661
|
||||||
|
|
||||||
|
|
||||||
|
print(format_time(timerTime))
|
Loading…
Reference in a new issue