adding description

This commit is contained in:
Manuel Fritsch 2021-02-07 13:08:13 +01:00
parent 9938ce6de1
commit 3a39719957
17 changed files with 120 additions and 278 deletions

View file

@ -1 +1 @@
__version__ = "4.0.0.15" __version__ = "4.0.0.16"

View file

@ -9,7 +9,6 @@ __all__ = ["CBPiActor",
"parameters", "parameters",
"background_task", "background_task",
"CBPiKettleLogic", "CBPiKettleLogic",
"CBPiSimpleStep",
"CBPiException", "CBPiException",
"KettleException", "KettleException",
"SensorException", "SensorException",

View file

@ -1,6 +1,5 @@
from abc import ABCMeta from abc import ABCMeta
import asyncio import asyncio
from cbpi.api.extension import CBPiExtension
from cbpi.api.config import ConfigType from cbpi.api.config import ConfigType
__all__ = ["CBPiActor"] __all__ = ["CBPiActor"]

View file

@ -4,11 +4,12 @@ import asyncio
import logging import logging
from abc import abstractmethod, ABCMeta from abc import abstractmethod, ABCMeta
import logging import logging
from cbpi.api.config import ConfigType
class CBPiStep(metaclass=ABCMeta): class CBPiStep(metaclass=ABCMeta):
def __init__(self, cbpi, id, name, props) : def __init__(self, cbpi, id, name, props) :
self.cbpi = cbpi self.cbpi = cbpi
self.props = {"wohoo": 0, "count": 5, **props} self.props = {**props}
self.id = id self.id = id
self.name = name self.name = name
self.status = 0 self.status = 0
@ -45,168 +46,62 @@ class CBPiStep(metaclass=ABCMeta):
while self.running: while self.running:
try: try:
await self.execute() await self.execute()
except: except Exception as e:
self._exception_count += 1 self._exception_count += 1
logging.error("Step has thrown exception") logging.error("Step has thrown exception")
if self._exception_count >= self._max_exceptions: if self._exception_count >= self._max_exceptions:
self.stop_reason = "MAX_EXCEPTIONS" self.stop_reason = "MAX_EXCEPTIONS"
return (self.id, self.stop_reason) return (self.id, self.stop_reason)
await asyncio.sleep(1) await asyncio.sleep(1)
return (self.id, self.stop_reason) return (self.id, self.stop_reason)
@abstractmethod @abstractmethod
async def execute(self): async def execute(self):
pass pass
class CBPiSimpleStep(metaclass=ABCMeta): def get_static_config_value(self,name,default):
return self.cbpi.static_config.get(name, default)
managed_fields = [] def get_config_value(self,name,default):
return self.cbpi.config.get(name, default=default)
def __init__(self, cbpi="", managed_fields=[], id="", name="", *args, **kwargs): async def set_config_value(self,name,value):
self.logger = logging.getLogger(__name__) return await self.cbpi.config.set(name,value)
self._exception_count = 0
self._interval = 0.1
self._max_exceptions = 2
self.__dirty = False
self.cbpi = cbpi
self.id = id
self.name = name
if managed_fields: async def add_config_value(self, name, value, type: ConfigType, description, options=None):
self.managed_fields = managed_fields await self.cbpi.add(name, value, type, description, options=None)
for a in managed_fields:
super(CBPiSimpleStep, self).__setattr__(a, kwargs.get(a, None))
self.is_stopped = False def get_kettle(self,id):
self.is_next = False return self.cbpi.kettle.find_by_id(id)
self.start = time.time()
self.logger.info(self.__repr__()) async def set_target_temp(self,id, temp):
await self.cbpi.kettle.set_target_temp(id, temp)
def __repr__(self) -> str: def get_sensor(self,id):
mf = {} return self.cbpi.sensor.find_by_id(id)
has_cbpi = True if self.cbpi is not None else False
for f in self.managed_fields:
mf[f] = super(CBPiSimpleStep, self).__getattribute__(f)
return json.dumps(dict(type=self.__class__.__name__, id=self.id, name=self.name, has_link_to_cbpi=has_cbpi, managed_fields=mf))
def get_status(self): def get_actor(self,id):
pass return self.cbpi.actor.find_by_id(id)
def running(self): def get_actor_state(self,id):
''' try:
Method checks if the step should continue running. actor = self.cbpi.actor.find_by_id(id)
The method will return False if the step is requested to stop or the next step should start 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):
:return: True if the step is running. Otherwise False. try:
''' await self.cbpi.actor.on(id)
if self.is_next is True: except:
return False pass
if self.is_stopped is True: async def actor_off(self,id):
return False try:
await self.cbpi.actor.off(id)
return True except:
pass
async def run(self):
#while self.running():
# print(".... Step %s ...." % self.id)
# await asyncio.sleep(0.1)
'''
This method in running in the background. It invokes the run_cycle method in the configured interval
It checks if a managed variable was modified in the last exection cycle. If yes, the method will persisit the new value of the
managed property
:return: None
'''
while self.running():
try:
await self.run_cycle()
except Exception as e:
logging.exception("CBPiSimpleStep Error")
self._exception_count = self._exception_count + 1
if self._exception_count == self._max_exceptions:
self.logger.error("Step Exception limit exceeded. Stopping Step")
self.stop()
await asyncio.sleep(self._interval)
if self.is_dirty():
# Now we have to store the managed props
state = {}
for field in self.managed_fields:
state[field] = self.__getattribute__(field)
await self.cbpi.step.model.update_step_state(self.id, state)
await self.cbpi.bus.fire("step/update")
self.reset_dirty()
@abstractmethod
async def run_cycle(self):
'''
This method is executed in the defined interval.
That the place to put your step logic.
The method need to be overwritten in the Ccstom step implementaion
:return: None
'''
print("NOTING IMPLEMENTED")
pass
def next(self):
'''
Request to stop the the step
:return: None
'''
self.is_next = True
def stop(self):
'''
Request to stop the step
:return: None
'''
self.is_stopped = True
def reset(self):
'''
Reset the step. This method needs to be overwritten by the custom step implementation
:return: None
'''
pass
def is_dirty(self):
'''
Check if a managed variable has a new value
:return: True if at least one managed variable has a new value assigend. Otherwise False
'''
return self.__dirty
def reset_dirty(self):
'''
Reset the dirty flag
:return:
'''
self.__dirty = False
def __setattr__(self, name, value):
if name != "_Step__dirty" and name in self.managed_fields:
self.__dirty = True
super(CBPiSimpleStep, self).__setattr__(name, value)
else:
super(CBPiSimpleStep, self).__setattr__(name, value)

View file

@ -10,5 +10,5 @@ username: cbpi
password: 123 password: 123
plugins: plugins:
- cbpi4-ui - cbpi4ui

View file

@ -1,20 +1,8 @@
{ {
"basic": { "basic": {
"name": "WOOHOo" "name": ""
}, },
"profile": [ "profile": [
{
"id": "MSXuATqL56EAeCXrg3XLuY",
"name": "Test",
"props": {
"Param1": 123,
"Param2": "HALLO",
"Param3": 1,
"count": 6,
"wohoo": 0
},
"status": "D",
"type": "CustomStep2"
}
] ]
} }

View file

@ -90,7 +90,6 @@ class BasicController:
type = item["type"] type = item["type"]
clazz = self.types[type]["class"] clazz = self.types[type]["class"]
print("#####",item)
item["instance"] = clazz(self.cbpi, item["id"], item["props"]) item["instance"] = clazz(self.cbpi, item["id"], item["props"])
await item["instance"].start() await item["instance"].start()
item["instance"].task = self._loop.create_task(item["instance"].run()) item["instance"].task = self._loop.create_task(item["instance"].run())

View file

@ -227,7 +227,7 @@ class StepController:
async def start_step(self,step): async def start_step(self,step):
logging.info("Start Step") logging.info("Start Step")
step.get("instance").start() step.get("instance").start()
step["instance"].task = self._loop.create_task(step["instance"].run(), name=step["name"]) step["instance"].task = self._loop.create_task(step["instance"].run())
step["instance"].task .add_done_callback(self.done) step["instance"].task .add_done_callback(self.done)
step["status"] = "A" step["status"] = "A"

View file

@ -1,44 +0,0 @@
import asyncio
import time
from cbpi.api import *
@parameters([Property.Number(label="Param1", configurable=True),
Property.Text(label="Param2", configurable=True, default_value="HALLO"),
Property.Select(label="Param3", options=[1,2,4]),
Property.Sensor(label="Param4"),
Property.Actor(label="Param5")])
class Step2(CBPiStep):
@action(key="name2", parameters=[])
async def action2(self, **kwargs):
print("CALL ACTION")
@action(key="name", parameters=[Property.Number(label="Test", configurable=True)])
async def action(self, **kwargs):
print("CALL ACTION")
async def execute(self):
count = self.props.get("count", 0)
self.state_msg = "COUNT %s" % count
self.props["count"] += 1
await self.update(self.props)
if count >= 5:
self.next()
async def reset(self):
self.props["count"] = 0
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("CustomStep2", Step2)

View file

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

View file

@ -20,17 +20,17 @@ except Exception:
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
@parameters([Property.Select(label="GPIO", options=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]), Property.Select(label="Inverted", options=["Yes", "No"])]) @parameters([Property.Select(label="GPIO", description="The GPIO Pin", options=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]), Property.Select(label="Inverted", description="No: Active on high; Yes: Active on low", options=["Yes", "No"])])
class GPIOActor(CBPiActor): class GPIOActor(CBPiActor):
def get_GPIO_state(self, state): def get_GPIO_state(self, state):
# ON # ON
if state == 1: if state == 1:
return 0 if self.inverted == False else 1 return 1 if self.inverted == False else 0
# OFF # OFF
if state == 0: if state == 0:
return 1 if self.inverted == False else 0 return 0 if self.inverted == False else 1
async def start(self): async def start(self):
await super().start() await super().start()

View file

@ -0,0 +1,38 @@
import asyncio
import time
import random
from cbpi.api import *
@parameters([Property.Number(label="Timer", configurable=True),
Property.Number(label="Temp", configurable=True),
Property.Kettle(label="Kettle")])
class MashStep(CBPiStep):
async def execute(self):
try:
kid = self.props.get("Kettle", None)
kettle = self.get_kettle(kid)
actor = self.get_actor(kettle.get("heater"))
print(self.get_actor_state(kettle.get("heater")))
await self.cbpi.kettle.set_target_temp(kid, random.randint(0,50))
if self.v is True:
await self.actor_on(kettle.get("heater"))
else:
await self.actor_off(kettle.get("heater"))
self.v = not self.v
except:
pass
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("MashStep", MashStep)

View file

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

View file

@ -41,6 +41,29 @@
"type": "ActorButton", "type": "ActorButton",
"x": 505, "x": 505,
"y": 140 "y": 140
},
{
"id": "3cae292a-f12d-4c9e-8e0e-2fd93a9b253e",
"name": "TargetTemp",
"props": {
"color": "#fff",
"kettle": "oHxKz3z5RjbsxfSz6KUgov",
"size": "12",
"unit": "\u00b0"
},
"type": "TargetTemp",
"x": 160,
"y": 75
},
{
"id": "bb90e1ab-7b2d-4623-8df3-3139f91b7087",
"name": "Steps",
"props": {
"width": "200"
},
"type": "Steps",
"x": 595,
"y": 50
} }
], ],
"pathes": [ "pathes": [

View file

@ -2,40 +2,13 @@
"data": [ "data": [
{ {
"agitator": "EsmZwWi9Qp3bzmXqq7N3Ly", "agitator": "EsmZwWi9Qp3bzmXqq7N3Ly",
"heater": "YwGzXvWMpmbLb6XobesL8n", "heater": "EsmZwWi9Qp3bzmXqq7N3Ly",
"id": "oHxKz3z5RjbsxfSz6KUgov", "id": "oHxKz3z5RjbsxfSz6KUgov",
"name": "MashTun", "name": "MashTun",
"props": {}, "props": {},
"sensor": "8ohkXvFA9UrkHLsxQL38wu", "sensor": "8ohkXvFA9UrkHLsxQL38wu",
"state": {}, "state": {},
"target_temp": 52, "target_temp": 25,
"type": "CustomKettleLogic"
},
{
"agitator": "",
"heater": "",
"id": "WxAkesrkqiHH3Gywc4fMci",
"name": "HLT",
"props": {
"Param2": "13",
"Param3": 1,
"Param4": "",
"Param5": "8BLRqagLicCdEBDdc77Sgr"
},
"sensor": "",
"state": {},
"target_temp": null,
"type": ""
},
{
"agitator": "",
"heater": "NjammuygecdvMpoGYc3rXt",
"id": "a7bWex85Z9Td4atwgazpXW",
"name": "Boil",
"props": {},
"sensor": "",
"state": {},
"target_temp": 55,
"type": "CustomKettleLogic" "type": "CustomKettleLogic"
} }
] ]

View file

@ -4,43 +4,15 @@
}, },
"profile": [ "profile": [
{ {
"id": "T2y34Mbex9KjNWXhzfCRby", "id": "Gkjdsu45XPcfJimz4yHc4w",
"name": "MashIn", "name": "Test",
"props": { "props": {
"Param1": 123, "Kettle": "oHxKz3z5RjbsxfSz6KUgov",
"Param2": "HALLO", "Temp": "2",
"Param3": 1, "Timer": "1"
"count": 1,
"wohoo": 0
}, },
"status": "P", "status": "P",
"type": "CustomStep2" "type": "MashStep"
},
{
"id": "RjS8Zb2GGpUtNsqHsES3yF",
"name": "Step2",
"props": {
"Param1": 123,
"Param2": "HALLO",
"Param3": 1,
"count": 0,
"wohoo": 0
},
"status": "I",
"type": "CustomStep2"
},
{
"id": "WkZG4fDNxZdtZ7uoTsSHhR",
"name": "Mash Step 1",
"props": {
"Param1": 123,
"Param2": "HALLO",
"Param3": 1,
"count": 0,
"wohoo": 0
},
"status": "I",
"type": "CustomStep2"
} }
] ]
} }

View file

@ -32,7 +32,7 @@ setup(name='cbpi',
'shortuuid==1.0.1', 'shortuuid==1.0.1',
'tabulate==0.8.7', 'tabulate==0.8.7',
'asyncio-mqtt', 'asyncio-mqtt',
'cbpi4-ui', 'cbpi4ui',
], ],
dependency_links=[ dependency_links=[
'https://testpypi.python.org/pypi', 'https://testpypi.python.org/pypi',