diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 56b176b..17a4feb 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -3,29 +3,39 @@
-
+
+
+
+
+
+
+
+
-
+
-
+
+
-
+
+
-
-
-
+
+
+
+
@@ -33,25 +43,31 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -78,6 +94,12 @@
+
+
+
+
+
+
@@ -87,105 +109,36 @@
-
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -197,36 +150,36 @@
- CustomSensor
- Errr
- ws
- tog
- w
- togll
- INI
- SENSOR
- self.cache
- SEND
- REGISTER
- ###### LAD
- log
- #######
- get_all
- step/brewing/stopped
- ADDD
- Nit ACTOR
- delete_a
- notifi
- exte
- "Not Found"
- toggle
- job
print
- automatic
- delete
- not found
- DELE
- dirty
+ setup_swagger
+ Helo World
+ index_url
+ MY EXT
+ plugin_list
+ Hello
+ config.yaml
+ cbpi-actor
+ StepModel
+ ----------- END
+ NORMAL START
+ super
+ _get_manged_fields_as_array
+ _step_done
+ job/step/done
+ step_done
+ STOP CURRENT STEP BEFORE NEXT
+ fire
+ RUNNING
+ update
+ GOON
+ GO
+ TYPE CFG
+ OK
+ JOB DONE
+ get_ste
+ print(
+ notif
+ sensor111
@@ -247,67 +200,70 @@
+
+
+
-
+
-
-
+
+
@@ -327,27 +283,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -358,119 +293,22 @@
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -499,41 +337,16 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
@@ -575,6 +388,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -609,37 +457,32 @@
-
+
+
-
-
+
+
+
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
@@ -658,6 +501,13 @@
+
+
+
+
+
+
+
@@ -665,13 +515,32 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -686,28 +555,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -752,28 +599,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -852,7 +677,55 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -864,28 +737,33 @@
-
+
-
-
-
+
+
+
+
-
+
+
+
+
-
-
+
+
+
@@ -916,7 +794,15 @@
-
+
+
+
+
+
+
+
+
+
1541288846149
@@ -936,39 +822,39 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -980,35 +866,35 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
-
+
+
+
@@ -1035,9 +921,14 @@
- file://$PROJECT_DIR$/cbpi/utils/encoder.py
- 13
-
+ file://$PROJECT_DIR$/cbpi/controller/crud_controller.py
+ 100
+
+
+
+ file://$PROJECT_DIR$/cbpi/craftbeerpi.py
+ 41
+
@@ -1055,181 +946,183 @@
-
+
-
-
-
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1240,102 +1133,93 @@
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
+
+
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1346,78 +1230,76 @@
-
-
-
-
-
-
-
+
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/cbpi/api/actor.py b/cbpi/api/actor.py
index b2e6fac..a5443fc 100644
--- a/cbpi/api/actor.py
+++ b/cbpi/api/actor.py
@@ -45,5 +45,3 @@ class CBPiActor(CBPiExtension, metaclass=ABCMeta):
pass
- def reprJSON(self):
- return dict(state=True)
\ No newline at end of file
diff --git a/cbpi/api/extension.py b/cbpi/api/extension.py
index 23f0c77..e5f00c2 100644
--- a/cbpi/api/extension.py
+++ b/cbpi/api/extension.py
@@ -50,5 +50,3 @@ class CBPiExtension():
except:
logger.warning("Faild to load config %s/config.yaml" % path)
-
-
diff --git a/cbpi/api/step.py b/cbpi/api/step.py
index a46a36f..2b4e2dc 100644
--- a/cbpi/api/step.py
+++ b/cbpi/api/step.py
@@ -1,3 +1,4 @@
+import json
import time
import asyncio
import logging
@@ -6,22 +7,39 @@ from abc import abstractmethod,ABCMeta
class CBPiSimpleStep(metaclass=ABCMeta):
- __dirty = False
managed_fields = []
- _interval = 1
- _max_exceptions = 2
- _exception_count = 0
- def __init__(self, *args, **kwargs):
+ def __init__(self, cbpi="", managed_fields=[], id="", name="", *args, **kwargs):
self.logger = logging.getLogger(__name__)
- print(kwargs)
- for a in kwargs:
- super(CBPiSimpleStep, self).__setattr__(a, kwargs.get(a))
- self.id = kwargs.get("id")
+ 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:
+ self.managed_fields = managed_fields
+ for a in managed_fields:
+ super(CBPiSimpleStep, self).__setattr__(a, kwargs.get(a, None))
+
self.is_stopped = False
self.is_next = False
self.start = time.time()
+ self.logger.info(self.__repr__())
+
+ def __repr__(self) -> str:
+ mf = {}
+ 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):
+ pass
+
def running(self):
'''
Method checks if the step should continue running.
@@ -39,6 +57,9 @@ class CBPiSimpleStep(metaclass=ABCMeta):
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
@@ -61,7 +82,6 @@ class CBPiSimpleStep(metaclass=ABCMeta):
await asyncio.sleep(self._interval)
if self.is_dirty():
- print("DIRTY")
# Now we have to store the managed props
state = {}
for field in self.managed_fields:
@@ -72,6 +92,7 @@ class CBPiSimpleStep(metaclass=ABCMeta):
await self.cbpi.bus.fire("step/update")
self.reset_dirty()
+
@abstractmethod
async def run_cycle(self):
'''
@@ -134,4 +155,4 @@ class CBPiSimpleStep(metaclass=ABCMeta):
self.__dirty = True
super(CBPiSimpleStep, self).__setattr__(name, value)
else:
- super(CBPiSimpleStep, self).__setattr__(name, value)
\ No newline at end of file
+ super(CBPiSimpleStep, self).__setattr__(name, value)
diff --git a/cbpi/cli.py b/cbpi/cli.py
index e1e3059..8d913de 100644
--- a/cbpi/cli.py
+++ b/cbpi/cli.py
@@ -1,5 +1,7 @@
import argparse
import logging
+import requests
+import yaml
from cbpi.craftbeerpi import CraftBeerPi
import os
@@ -13,6 +15,7 @@ def create_plugin_file():
srcfile = os.path.join(os.path.dirname(__file__), "config", "plugin_list.txt")
destfile = os.path.join(".", 'config')
shutil.copy(srcfile, destfile)
+ print("Plugin Folder created")
def create_config_file():
import os.path
@@ -20,19 +23,49 @@ def create_config_file():
srcfile = os.path.join(os.path.dirname(__file__), "config", "config.yaml")
destfile = os.path.join(".", 'config')
shutil.copy(srcfile, destfile)
+ print("Config Folder created")
def create_home_folder_structure():
pathlib.Path(os.path.join(".", 'logs/sensors')).mkdir(parents=True, exist_ok=True)
pathlib.Path(os.path.join(".", 'config')).mkdir(parents=True, exist_ok=True)
+ print("Log Folder created")
def copy_splash():
srcfile = os.path.join(os.path.dirname(__file__), "config", "splash.png")
destfile = os.path.join(".", 'config')
shutil.copy(srcfile, destfile)
+ print("Splash Srceen created")
+
+
+def check_for_setup():
+
+ if os.path.exists(os.path.join(".", "config", "config.yaml")) is False:
+ print("***************************************************")
+ print("CraftBeerPi Config File not found: %s" % os.path.join(".", "config", "config.yaml"))
+ print("Please run 'cbpi setup' before starting the server ")
+ print("***************************************************")
+ return False
+ else:
+ return True
+
+
+def list_plugins():
+ print("***************************************************")
+ print("CraftBeerPi 4.x Plugin List")
+ print("***************************************************")
+ plugins_yaml = "https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins_v4.yaml"
+ r = requests.get(plugins_yaml)
+
+ data = yaml.load(r.content, Loader=yaml.FullLoader)
+
+
+ for name, value in data.items():
+ print(name)
+
def main():
parser = argparse.ArgumentParser(description='Welcome to CraftBeerPi 4')
- parser.add_argument("action", type=str, help="start,stop,restart,setup")
+ parser.add_argument("action", type=str, help="start,stop,restart,setup,plugins")
args = parser.parse_args()
@@ -40,15 +73,24 @@ def main():
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
if args.action == "setup":
+ print("Setting up CBPi")
create_home_folder_structure()
create_plugin_file()
create_config_file()
copy_splash()
+ return
+
+ if args.action == "plugins":
+ list_plugins()
+ return
if args.action == "start":
+ if check_for_setup() is False:
+ return
cbpi = CraftBeerPi()
cbpi.start()
+ return
parser.print_help()
diff --git a/cbpi/config/config.yaml b/cbpi/config/config.yaml
index f05f964..ec4a2ec 100644
--- a/cbpi/config/config.yaml
+++ b/cbpi/config/config.yaml
@@ -1,8 +1,8 @@
name: CraftBeerPi
-version: 4.1
+version: 4.0.1_alpha
-#index_url: /myext
+#: /myext
port: 8080
diff --git a/cbpi/controller/actor_controller.py b/cbpi/controller/actor_controller.py
index eb153c8..6d7d95d 100644
--- a/cbpi/controller/actor_controller.py
+++ b/cbpi/controller/actor_controller.py
@@ -1,8 +1,9 @@
import asyncio
import logging
-from asyncio import Future
-from cbpi.api import *
+
from voluptuous import Schema
+
+from cbpi.api import *
from cbpi.controller.crud_controller import CRUDController
from cbpi.database.model import ActorModel
@@ -46,6 +47,7 @@ class ActorController(CRUDController):
self.cache[actor.id].instance = clazz(**cfg)
self.cache[actor.id].instance.init()
+
await self.cbpi.bus.fire(topic="actor/%s/initialized" % actor.id, id=actor.id)
else:
@@ -73,6 +75,7 @@ class ActorController(CRUDController):
actor_id = int(actor_id)
if actor_id in self.cache:
+
self.logger.debug("ON %s" % actor_id)
actor = self.cache[actor_id].instance
actor.on(power)
@@ -141,7 +144,7 @@ class ActorController(CRUDController):
:param m:
:return:
'''
- print("INIT ACTION")
+
await self._init_actor(m)
pass
diff --git a/cbpi/controller/config_controller.py b/cbpi/controller/config_controller.py
index 6fc0d3d..42e1997 100644
--- a/cbpi/controller/config_controller.py
+++ b/cbpi/controller/config_controller.py
@@ -6,7 +6,7 @@ from cbpi.database.model import ConfigModel
from cbpi.utils import load_config
-class ConfigController():
+class ConfigController:
'''
The main actor controller
'''
@@ -24,14 +24,13 @@ class ConfigController():
async def init(self):
this_directory = os.path.dirname(__file__)
-
self.static = load_config("./config/config.yaml")
items = await self.model.get_all()
for key, value in items.items():
self.cache[value.name] = value
def get(self, name, default=None):
- self.logger.info("GET CONFIG VALUE %s (default %s)" % (name, default))
+ self.logger.debug("GET CONFIG VALUE %s (default %s)" % (name, default))
if name in self.cache and self.cache[name].value is not None:
return self.cache[name].value
else:
diff --git a/cbpi/controller/crud_controller.py b/cbpi/controller/crud_controller.py
index 5d41e7e..276add4 100644
--- a/cbpi/controller/crud_controller.py
+++ b/cbpi/controller/crud_controller.py
@@ -70,7 +70,7 @@ class CRUDController(metaclass=ABCMeta):
await self._pre_add_callback(data)
- print("INSSERT ADD", data)
+
m = await self.model.insert(**data)
@@ -96,10 +96,12 @@ class CRUDController(metaclass=ABCMeta):
'''
self.logger.debug("Update Sensor %s - %s " % (id, data))
+
id = int(id)
- if id not in self.cache:
- self.logger.debug("Sensor %s Not in Cache" % (id,))
+ if self.caching is True and id not in self.cache:
+
+ self.logger.debug("%s %s Not in Cache" % (self.name, id))
raise CBPiException("%s with id %s not found" % (self.name,id))
data["id"] = id
@@ -115,14 +117,10 @@ class CRUDController(metaclass=ABCMeta):
self.cache[id].__dict__.update(**data)
m = self.cache[id] = await self.model.update(**self.cache[id].__dict__)
await self._post_update_callback(self.cache[id])
-
else:
-
m = await self.model.update(**data)
return m
-
-
async def _pre_delete_callback(self, m):
'''
diff --git a/cbpi/controller/dashboard_controller.py b/cbpi/controller/dashboard_controller.py
index e7952d9..7daff7b 100644
--- a/cbpi/controller/dashboard_controller.py
+++ b/cbpi/controller/dashboard_controller.py
@@ -1,7 +1,5 @@
import logging
-from voluptuous import Schema, MultipleInvalid
-
from cbpi.controller.crud_controller import CRUDController
from cbpi.database.model import DashboardModel, DashboardContentModel
diff --git a/cbpi/controller/job_controller.py b/cbpi/controller/job_controller.py
index 9e58fb8..a5797b4 100644
--- a/cbpi/controller/job_controller.py
+++ b/cbpi/controller/job_controller.py
@@ -4,6 +4,7 @@ import logging
from cbpi.job.aiohttp import setup, get_scheduler_from_app
logger = logging.getLogger(__name__)
+
class JobController(object):
def __init__(self, cbpi):
diff --git a/cbpi/controller/kettle_controller.py b/cbpi/controller/kettle_controller.py
index 89ea966..4923f73 100644
--- a/cbpi/controller/kettle_controller.py
+++ b/cbpi/controller/kettle_controller.py
@@ -3,7 +3,7 @@ from cbpi.api import *
from cbpi.controller.crud_controller import CRUDController
from cbpi.database.model import KettleModel
from cbpi.job.aiohttp import get_scheduler_from_app
-
+import logging
class KettleController(CRUDController):
'''
@@ -15,6 +15,7 @@ class KettleController(CRUDController):
super(KettleController, self).__init__(cbpi)
self.cbpi = cbpi
self.types = {}
+ self.logger = logging.getLogger(__name__)
self.cbpi.register(self)
async def init(self):
@@ -58,7 +59,7 @@ class KettleController(CRUDController):
kettle = self.cache[int(kid)]
kettle.instance = None
kettle.state = False
- print("FIRE")
+
await self.cbpi.bus.fire(topic="kettle/%s/logic/stop" % kid)
@on_event(topic="kettle/+/automatic")
@@ -73,7 +74,7 @@ class KettleController(CRUDController):
'''
id = int(id)
- print("K", id)
+
if id in self.cache:
kettle = self.cache[id]
@@ -84,7 +85,7 @@ class KettleController(CRUDController):
if kettle.instance is None:
- print("start")
+
if kettle.logic in self.types:
clazz = self.types.get("CustomKettleLogic")["class"]
cfg = kettle.config.copy()
@@ -104,13 +105,9 @@ class KettleController(CRUDController):
def _is_logic_running(self, kettle_id):
scheduler = get_scheduler_from_app(self.cbpi.app)
-
-
async def heater_on(self, id):
'''
Convenience Method to switch the heater of a kettle on
-
-
:param id: the kettle id
:return: (boolean, string)
'''
diff --git a/cbpi/controller/plugin_controller.py b/cbpi/controller/plugin_controller.py
index b0ac232..6a45e2b 100644
--- a/cbpi/controller/plugin_controller.py
+++ b/cbpi/controller/plugin_controller.py
@@ -1,3 +1,4 @@
+import asyncio
import logging
import os
from importlib import import_module
@@ -5,15 +6,16 @@ from importlib import import_module
import aiohttp
import yaml
from aiohttp import web
-from cbpi.api import *
+from cbpi.api import *
from cbpi.utils.utils import load_config, json_dumps
logger = logging.getLogger(__name__)
+import subprocess
+import sys
class PluginController():
-
modules = {}
types = {}
@@ -25,9 +27,7 @@ class PluginController():
async def load_plugin_list(self):
async with aiohttp.ClientSession() as session:
async with session.get('https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins_v4.yaml') as resp:
-
- if(resp.status == 200):
-
+ if (resp.status == 200):
data = yaml.load(await resp.text())
return data
@@ -44,7 +44,7 @@ class PluginController():
data = load_config(os.path.join(this_directory, "../extension/%s/config.yaml" % filename))
- if(data.get("version") == 4):
+ if (data.get("version") == 4):
self.modules[filename] = import_module("cbpi.extension.%s" % (filename))
self.modules[filename].setup(self.cbpi)
@@ -55,6 +55,7 @@ class PluginController():
except Exception as e:
+ print(e)
logger.error(e)
def load_plugins_from_evn(self):
@@ -63,7 +64,6 @@ class PluginController():
this_directory = os.path.dirname(__file__)
with open("./config/plugin_list.txt") as f:
-
plugins = f.read().splitlines()
plugins = list(set(plugins))
@@ -74,15 +74,42 @@ class PluginController():
self.modules[p] = import_module(p)
self.modules[p].setup(self.cbpi)
-
-
- logger.info("Plugin %s loaded successfully" % p)
+ logger.info("Plugin %s loaded successfully" % p)
except Exception as e:
logger.error("FAILED to load plugin %s " % p)
logger.error(e)
+ @on_event("job/plugins_install/done")
+ async def done(self, **kwargs):
+ self.cbpi.notify(key="p", message="Plugin installed ", type="success")
+ print("DONE INSTALL PLUGIN", kwargs)
- @request_mapping(path="/plugins", method="GET", auth_required=False)
+ @request_mapping(path="/install", method="GET", auth_required=False)
+ async def install_plugin(self, request):
+ """
+ ---
+ description: Install Plugin
+ tags:
+ - Plugin
+ produces:
+ - application/json
+ responses:
+ "204":
+ description: successful operation. Return "pong" text
+ "405":
+ description: invalid HTTP Method
+ """
+
+ async def install(name):
+ await asyncio.sleep(5)
+ subprocess.call([sys.executable, "-m", "pip", "install", name])
+
+ print("OK")
+
+ await self.cbpi.job.start_job(install('requests'), "requests", "plugins_install")
+ return web.Response(status=204)
+
+ @request_mapping(path="/list", method="GET", auth_required=False)
async def get_plugins(self, request):
"""
---
@@ -99,8 +126,6 @@ class PluginController():
"""
return web.json_response(await self.load_plugin_list(), dumps=json_dumps)
-
-
def register(self, name, clazz) -> None:
'''
Register a new actor type
@@ -110,7 +135,7 @@ class PluginController():
'''
logger.info("Register %s Class %s" % (name, clazz.__name__))
if issubclass(clazz, CBPiActor):
- #self.cbpi.actor.types[name] = {"class": clazz, "config": self._parse_props(clazz)}
+ # self.cbpi.actor.types[name] = {"class": clazz, "config": self._parse_props(clazz)}
self.cbpi.actor.types[name] = self._parse_props(clazz)
if issubclass(clazz, CBPiSensor):
@@ -123,7 +148,7 @@ class PluginController():
self.cbpi.step.types[name] = self._parse_props(clazz)
if issubclass(clazz, CBPiExtension):
- self.c = clazz(self.cbpi)
+ self.c = clazz(self.cbpi)
def _parse_props(self, cls):
@@ -131,7 +156,7 @@ class PluginController():
result = {"name": name, "class": cls, "properties": [], "actions": []}
- tmpObj = cls()
+ tmpObj = cls(cbpi=None, managed_fields=None)
members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")]
for m in members:
if isinstance(tmpObj.__getattribute__(m), Property.Number):
@@ -162,4 +187,4 @@ class PluginController():
parameters = method.__getattribute__("parameters")
result["actions"].append({"method": method_name, "label": key, "parameters": parameters})
- return result
\ No newline at end of file
+ return result
diff --git a/cbpi/controller/sensor_controller.py b/cbpi/controller/sensor_controller.py
index ea42e18..af10044 100644
--- a/cbpi/controller/sensor_controller.py
+++ b/cbpi/controller/sensor_controller.py
@@ -41,7 +41,9 @@ class SensorController(CRUDController):
self.cache[sensor.id].instance = clazz(**cfg)
self.cache[sensor.id].instance.init()
scheduler = get_scheduler_from_app(self.cbpi.app)
- self.cache[sensor.id].instance.job = await scheduler.spawn(self.cache[sensor.id].instance.run(self.cbpi), sensor.name, "sensor")
+
+ self.cache[sensor.id].instance.job = await self.cbpi.job.start_job(self.cache[sensor.id].instance.run(self.cbpi), sensor.name, "sensor")
+
await self.cbpi.bus.fire(topic="sensor/%s/initialized" % sensor.id, id=sensor.id)
else:
self.logger.error("Sensor type '%s' not found (Available Sensor Types: %s)" % (sensor.type, ', '.join(self.types.keys())))
diff --git a/cbpi/controller/step_controller.py b/cbpi/controller/step_controller.py
index ec01b05..c072c05 100644
--- a/cbpi/controller/step_controller.py
+++ b/cbpi/controller/step_controller.py
@@ -7,16 +7,13 @@ from cbpi.database.model import StepModel
class StepController(CRUDController):
- '''
- The Step Controller. This controller is responsible to start and stop the brewing steps.
-
- '''
- model = StepModel
+
def __init__(self, cbpi):
- super(StepController, self).__init__(cbpi)
- self.caching = False
+ self.model = StepModel
+
+ self.caching = True
self.is_stopping = False
self.cbpi = cbpi
self.current_task = None
@@ -28,36 +25,11 @@ class StepController(CRUDController):
self.logger = logging.getLogger(__name__)
self.starttime = None
- async def init(self):
- '''
- Initializer of the the Step Controller.
- :return:
- '''
- await super(StepController, self).init()
-
- step = await self.model.get_by_state('A')
- # We have an active step
- if step is not None:
-
- # get the type
- step_type = self.types.get(step.type)
-
- if step_type is None:
- # step type not found. cant restart step
- return
-
- if step.stepstate is not None:
- cfg = step.stepstate.copy()
- else:
- cfg = {}
- cfg.update(dict(cbpi=self.cbpi, id=step.id, managed_fields=self._get_manged_fields_as_array(step_type)))
-
- self.current_step = step_type["class"](**cfg)
- self.current_job = await self.cbpi.job.start_job(self.current_step.run(), step.name, "step")
-
-
- async def get_state(self):
- return dict(items=await self.get_all(),types=self.types,is_running=self.is_running(),current_step=self.current_step)
+ def is_running(self):
+ if self.current_step is not None:
+ return True
+ else:
+ return False
@on_event("step/action")
async def handle_action(self, action, **kwargs):
@@ -65,171 +37,163 @@ class StepController(CRUDController):
'''
Event Handler for "step/action".
It invokes the provided method name on the current step
-
-
+
+
:param action: the method name which will be invoked
- :param kwargs:
+ :param kwargs:
:return: None
'''
if self.current_step is not None:
self.current_step.__getattribute__(action)()
-
- @on_event("step/next")
- async def next(self, **kwargs):
- '''
- Event Handler for "step/next".
- It start the next step
-
- :param kwargs:
- :return: None
- '''
-
- self.starttime = time.time()
- if self.current_step is not None and self.is_next is False:
- self.logger.info("Request Next Step to start. Stopping current step")
- self.is_next = True
- self.current_step.stop()
- else:
- self.logger.info("Can Start Next")
-
-
-
-
- @on_event("job/step/done")
- async def _step_done(self, topic, **kwargs):
-
- '''
- Event Handler for "step/+/done".
- Starts the next step
-
- :param topic:
- :param kwargs:
- :return:
- '''
-
- # SHUTDONW DO NOTHING
- self.logger.info("HANDLE DONE IS SHUTDONW %s IS STOPPING %s IS NEXT %s" % ( self.cbpi.shutdown, self.is_stopping, self.is_next))
-
-
- if self.cbpi.shutdown:
- return
-
- if self.is_stopping:
- self.is_stopping = False
- return
- self.is_next = False
- if self.current_step is not None:
- await self.model.update_state(self.current_step.id, "D", int(time.time()))
- self.current_step = None
- await self.start()
-
-
-
def _get_manged_fields_as_array(self, type_cfg):
result = []
+
for f in type_cfg.get("properties"):
+
result.append(f.get("name"))
return result
- def is_running(self):
- if self.current_step is not None:
- return True
- else:
- return False
+ async def init(self):
+
+ # load all steps into cache
+ self.cache = await self.model.get_all()
+
+
+ for key, value in self.cache.items():
+
+ # get step type as string
+ step_type = self.types.get(value.type)
+
+ # if step has state
+ if value.stepstate is not None:
+ cfg = value.stepstate.copy()
+ else:
+ cfg = {}
+
+ # set managed fields
+ cfg.update(dict(cbpi=self.cbpi, id=value.id, managed_fields=self._get_manged_fields_as_array(step_type)))
+
+ if value.config is not None:
+ # set config values
+ cfg.update(**value.config)
+ # create step instance
+ value.instance = step_type["class"](**cfg)
+
+ async def get_all(self, force_db_update: bool = True):
+ return self.cache
+
+ def find_next_step(self):
+ # filter
+ inactive_steps = {k: v for k, v in self.cache.items() if v.state == 'I'}
+ if len(inactive_steps) == 0:
+ return None
+ return min(inactive_steps, key=lambda x: inactive_steps[x].order)
@on_event("step/start")
async def start(self, **kwargs):
- '''
- Start the first step
-
- :return:None
- '''
-
if self.is_running() is False:
- next_step = await self.model.get_by_state("I")
-
- if next_step is not None:
- step_type = self.types[next_step.type]
- print(step_type)
- managed_fields = self._get_manged_fields_as_array(step_type)
- config = dict(cbpi=self.cbpi, id=next_step.id, name=next_step.name, managed_fields=managed_fields)
- config.update(**next_step.config)
- self._set_default(step_type, config, managed_fields)
-
- self.current_step = step_type["class"](**config)
-
+ next_step_id = self.find_next_step()
+ if next_step_id:
+ next_step = self.cache[next_step_id]
next_step.state = 'A'
next_step.stepstate = next_step.config
next_step.start = int(time.time())
await self.model.update(**next_step.__dict__)
- if self.starttime is not None:
- end = time.time()
- d = end - self.starttime
- print("DURATION", d)
- else:
- print("NORMAL START")
- self.current_job = await self.cbpi.job.start_job(self.current_step.run(), next_step.name, "step")
+ self.current_step = next_step
+ # start the step job
+ self.current_job = await self.cbpi.job.start_job(self.current_step.instance.run(), next_step.name, "step")
await self.cbpi.bus.fire("step/%s/started" % self.current_step.id)
else:
await self.cbpi.bus.fire("step/brewing/finished")
else:
self.logger.error("Process Already Running")
- print("----------- END")
- def _set_default(self, step_type, config, managed_fields):
- for key in managed_fields:
- if key not in config:
- config[key] = None
+ async def next(self, **kwargs):
+ if self.current_step is not None:
+
+ self.is_next = True
+ self.current_step.instance.stop()
+
+ @on_event("job/step/done")
+ async def step_done(self, **kwargs):
+
+ if self.cbpi.shutdown:
+ return
+ if self.is_stopping:
+ self.is_stopping = False
+ return
+
+ if self.current_step is not None:
+
+ self.current_step.state = "D"
+ await self.model.update_state(self.current_step.id, "D", int(time.time()))
+ self.current_step = None
+
+ # start the next step
+ await self.start()
@on_event("step/stop")
- async def stop(self, **kwargs):
-
- if self.current_step is not None:
- self.current_step.stop()
- self.is_stopping = True
- self.current_step = None
-
+ async def stop_all(self, **kwargs):
+ # RESET DB
await self.model.reset_all_steps()
+ # RELOAD all Steps from DB into cache and initialize Instances
+ await self.init()
await self.cbpi.bus.fire("step/brewing/stopped")
- @on_event("step/reset")
- async def handle_reset(self, **kwargs):
- '''
- Event Handler for "step/reset".
- Resets the current step
-
- :param kwargs:
- :return: None
- '''
- if self.current_step is not None:
-
- await self.stop()
- self.current_step = None
- self.is_stopping = True
-
- await self.model.reset_all_steps()
-
@on_event("step/clear")
async def clear_all(self, **kwargs):
await self.model.delete_all()
self.cbpi.notify(key="Steps Cleared", message="Steps cleared successfully", type="success")
- @on_event("step/sort")
- async def sort(self, topic, data, **kwargs):
- await self.model.sort(data)
-
async def _pre_add_callback(self, data):
+
order = await self.model.get_max_order()
data["order"] = 1 if order is None else order + 1
data["state"] = "I"
+ data["stepstate"] = {}
return await super()._pre_add_callback(data)
+ async def init_step(self, value: StepModel):
+ step_type = self.types.get(value.type)
+ # if step has state
+ if value.stepstate is not None:
+ cfg = value.stepstate.copy()
+ else:
+ cfg = {}
+ # set managed fields
+ cfg.update(dict(cbpi=self.cbpi, id=value.id, managed_fields=self._get_manged_fields_as_array(step_type)))
+ # set config values
+ cfg.update(**value.config)
+ # create step instance
+ value.instance = step_type["class"](**cfg)
+ return value
+ async def _post_add_callback(self, m: StepModel) -> None:
+ self.cache[m.id] = await self.init_step(m)
+ async def _post_update_callback(self, m: StepModel) -> None:
+ '''
+ :param m: step model
+ :return: None
+ '''
+ self.cache[m.id] = await self.init_step(m)
+
+ @on_event("step/sort")
+ async def sort(self, topic: 'str', data: 'dict', **kwargs):
+
+ # update order in cache
+ for id, order in data.items():
+ self.cache[int(id)].order = order
+
+ # update oder in database
+ await self.model.sort(data)
+
+ async def get_state(self):
+ return dict(items=await self.get_all(),types=self.types,is_running=self.is_running(),current_step=self.current_step)
diff --git a/cbpi/craftbeerpi.py b/cbpi/craftbeerpi.py
index eff0ba9..fb8c5b2 100644
--- a/cbpi/craftbeerpi.py
+++ b/cbpi/craftbeerpi.py
@@ -52,6 +52,9 @@ async def error_middleware(request, handler):
return web.json_response(status=500, data={'error': message})
except MultipleInvalid as ex:
return web.json_response(status=500, data={'error': str(ex)})
+ except Exception as ex:
+ return web.json_response(status=500, data={'error': str(ex)})
+
return web.json_response(status=500, data={'error': message})
class CraftBeerPi():
@@ -187,7 +190,7 @@ class CraftBeerPi():
api_version=self.static_config.get("version", ""),
contact="info@craftbeerpi.com")
- def notify(self, key, message, type="info"):
+ def notify(self, key: str, message: str, type: str = "info") -> None:
'''
This is a convinience method to send notification to the client
@@ -216,7 +219,7 @@ class CraftBeerPi():
if url is not None:
raise web.HTTPFound(url)
else:
- return web.Response(text="Hello, world")
+ return web.Response(text="Hello from CraftbeerPi!")
self.app.add_routes([web.get('/', http_index)])
diff --git a/cbpi/database/model.py b/cbpi/database/model.py
index 057514a..e7a62cc 100644
--- a/cbpi/database/model.py
+++ b/cbpi/database/model.py
@@ -20,6 +20,13 @@ class ActorModel(DBModel):
'config': dict
}
+ def to_json(self):
+ data = dict(**self.__dict__)
+ if hasattr(self,"instance"):
+ data["state"] = self.instance.get_state()
+ del data["instance"]
+ return data
+
class SensorModel(DBModel):
__fields__ = ["name", "type", "config"]
@@ -32,6 +39,15 @@ class SensorModel(DBModel):
'config': dict
}
+ def to_json(self):
+ data = dict(**self.__dict__)
+ if hasattr(self,"instance"):
+ data["value"] = self.instance.get_value()
+ data["unit"] = self.instance.get_unit()
+ data["state"] = self.instance.get_state()
+ del data["instance"]
+ return data
+
class ConfigModel(DBModel):
__fields__ = ["type", "value", "description", "options"]
@@ -54,7 +70,7 @@ class StepModel(DBModel):
@classmethod
async def update_step_state(cls, step_id, state):
- print("NOW UPDATE", state)
+
async with aiosqlite.connect(DATABASE_FILE) as db:
cursor = await db.execute("UPDATE %s SET stepstate = ? WHERE id = ?" % cls.__table_name__, (json.dumps(state), step_id))
await db.commit()
@@ -93,7 +109,7 @@ class StepModel(DBModel):
async with aiosqlite.connect(DATABASE_FILE) as db:
for key, value in new_order.items():
- print("ORDER", key, value)
+
await db.execute("UPDATE %s SET '%s' = ? WHERE id = ?" % (cls.__table_name__, "order"), (value, key))
await db.commit()
@@ -111,6 +127,19 @@ class StepModel(DBModel):
else:
return 0
+ def to_json(self):
+ data = dict(**self.__dict__)
+ if hasattr(self,"instance"):
+ data["state_msg"] = self.instance.get_status()
+ del data["instance"]
+ return data
+
+ def __str__(self):
+ return "%s, %s, %s, %s, %s" % (self.name, self.start, self.end, self.state, self.order)
+
+ def __repr__(self) -> str:
+ return "Steps(%s, %s, %s, %s, %s)" % (self.name, self.start, self.end, self.state, self.order)
+
class DashboardModel(DBModel):
__fields__ = ["name"]
diff --git a/cbpi/database/orm_framework.py b/cbpi/database/orm_framework.py
index e38a358..ea65acf 100644
--- a/cbpi/database/orm_framework.py
+++ b/cbpi/database/orm_framework.py
@@ -167,3 +167,7 @@ class DBModel(object):
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
+
+ def to_json(self):
+
+ return self.__dict__
diff --git a/cbpi/extension/dummyactor/__init__.py b/cbpi/extension/dummyactor/__init__.py
index bc38333..cac2f60 100644
--- a/cbpi/extension/dummyactor/__init__.py
+++ b/cbpi/extension/dummyactor/__init__.py
@@ -24,7 +24,7 @@ class CustomActor(CBPiActor):
# Custom property which can be configured by the user
@action("test", parameters={})
def action1(self):
- print("EOOOHOOO")
+
pass
diff --git a/cbpi/extension/dummysensor/__init__.py b/cbpi/extension/dummysensor/__init__.py
index 3baaaa9..5dfd20a 100644
--- a/cbpi/extension/dummysensor/__init__.py
+++ b/cbpi/extension/dummysensor/__init__.py
@@ -3,6 +3,7 @@ import asyncio
from aiohttp import web
from cbpi.api import *
+import re
class CustomSensor(CBPiSensor):
@@ -61,6 +62,7 @@ class HTTPSensor(CBPiSensor):
def init(self):
super().init()
+
self.state = True
def get_state(self):
@@ -80,10 +82,12 @@ class HTTPSensor(CBPiSensor):
try:
value = cache.pop(self.key, None)
+ print("HTTP SENSOR READ", value)
if value is not None:
self.log_data(value)
- await cbpi.bus.fire("sensor/%s" % self.id, value=value)
- except:
+ await cbpi.bus.fire("sensor/%s/data" % self.id, value=value)
+ except Exception as e:
+ print(e)
pass
class HTTPSensorEndpoint(CBPiExtension):
@@ -95,6 +99,7 @@ class HTTPSensorEndpoint(CBPiExtension):
:param cbpi:
'''
+ self.pattern_check = re.compile("^[a-zA-Z0-9,.]{0,10}$")
self.cbpi = cbpi
# register component for http, events
@@ -125,10 +130,17 @@ class HTTPSensorEndpoint(CBPiExtension):
"204":
description: successful operation
"""
- print("HALLO")
+
global cache
key = request.match_info['key']
value = request.match_info['value']
+ if self.pattern_check.match(key) is None:
+ return web.json_response(status=422, data={'error': "Key not matching pattern ^[a-zA-Z0-9,.]{0,10}$"})
+
+ if self.pattern_check.match(value) is None:
+ return web.json_response(status=422, data={'error': "Data not matching pattern ^[a-zA-Z0-9,.]{0,10}$"})
+
+ print("HTTP SENSOR ", key, value)
cache[key] = value
return web.Response(status=204)
diff --git a/cbpi/extension/dummystep/__init__.py b/cbpi/extension/dummystep/__init__.py
index 0753bc9..1162936 100644
--- a/cbpi/extension/dummystep/__init__.py
+++ b/cbpi/extension/dummystep/__init__.py
@@ -9,15 +9,23 @@ class CustomStepCBPi(CBPiSimpleStep):
name1 = Property.Number(label="Test", configurable=True)
timer_end = Property.Number(label="Test", default_value=None)
temp = Property.Number(label="Temperature", default_value=50, configurable=True)
+
+
+
i = 0
@action(key="name", parameters=None)
def test(self, **kwargs):
self.name="WOOHOO"
-
+ def get_status(self):
+ return "Status: %s Temp" % self.temp
async def run_cycle(self):
+
+ self.next()
+
+ '''
print("RUN", self.name1, self.managed_fields, self.timer_end)
self.i = self.i + 1
@@ -26,7 +34,7 @@ class CustomStepCBPi(CBPiSimpleStep):
if self.i == 10:
self.next()
-
+ '''
#self.cbpi.notify(key="step", message="HELLO FROM STEP")
diff --git a/cbpi/http_endpoints/http_config.py b/cbpi/http_endpoints/http_config.py
index c9a2850..acf1fdb 100644
--- a/cbpi/http_endpoints/http_config.py
+++ b/cbpi/http_endpoints/http_config.py
@@ -30,7 +30,7 @@ class ConfigHttpEndpoints(HttpCrudEndpoints):
"204":
description: successful operation
"""
- print("HALLO PARA")
+
name = request.match_info['name']
data = await request.json()
await self.controller.set(name=name, value=data.get("value"))
diff --git a/cbpi/http_endpoints/http_curd_endpoints.py b/cbpi/http_endpoints/http_curd_endpoints.py
index fe0a55b..b7fb5d0 100644
--- a/cbpi/http_endpoints/http_curd_endpoints.py
+++ b/cbpi/http_endpoints/http_curd_endpoints.py
@@ -22,7 +22,7 @@ class HttpCrudEndpoints():
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
- return web.json_response(await self.controller.get_all(force_db_update=True), dumps=json_dumps)
+ return web.json_response(await self.controller.get_all(), dumps=json_dumps)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
@@ -39,6 +39,8 @@ class HttpCrudEndpoints():
async def http_update(self, request):
id = int(request.match_info['id'])
data = await request.json()
+
+
obj = await self.controller.update(id, data)
return web.json_response(obj, dumps=json_dumps)
diff --git a/cbpi/http_endpoints/http_dashboard.py b/cbpi/http_endpoints/http_dashboard.py
index 612e9b9..03a2aca 100644
--- a/cbpi/http_endpoints/http_dashboard.py
+++ b/cbpi/http_endpoints/http_dashboard.py
@@ -257,6 +257,6 @@ class DashBoardHttpEndpoints(HttpCrudEndpoints):
schema = Schema({"id": int, "x": int, "y": int})
schema(data)
content_id = int(request.match_info['content_id'])
- print("MOVE",content_id)
+
return web.json_response(await self.cbpi.dashboard.move_content(content_id,data["x"], data["y"]), dumps=json_dumps)
diff --git a/cbpi/http_endpoints/http_step.py b/cbpi/http_endpoints/http_step.py
index e2aa310..194aa9d 100644
--- a/cbpi/http_endpoints/http_step.py
+++ b/cbpi/http_endpoints/http_step.py
@@ -28,24 +28,16 @@ class StepHttpEndpoints(HttpCrudEndpoints):
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
+
"""
---
- description: Switch step on
+ description: Get all steps
tags:
- Step
- parameters:
- - name: "id"
- in: "path"
- description: "step ID"
- required: true
- type: "integer"
- format: "int64"
responses:
"204":
description: successful operation
- "405":
- description: invalid HTTP Met
"""
return await super().http_get_all(request)
diff --git a/cbpi/job/_job.py b/cbpi/job/_job.py
index 3e96c4d..e4b2606 100644
--- a/cbpi/job/_job.py
+++ b/cbpi/job/_job.py
@@ -114,6 +114,7 @@ class Job:
self._started.set_result(None)
def _done_callback(self, task):
+
scheduler = self._scheduler
scheduler._done(self)
try:
diff --git a/cbpi/utils/encoder.py b/cbpi/utils/encoder.py
index b676206..575577d 100644
--- a/cbpi/utils/encoder.py
+++ b/cbpi/utils/encoder.py
@@ -1,38 +1,13 @@
from json import JSONEncoder
-from cbpi.database.model import ActorModel, SensorModel
-
class ComplexEncoder(JSONEncoder):
def default(self, obj):
-
- from cbpi.database.orm_framework import DBModel
-
try:
- if isinstance(obj, ActorModel):
-
-
- data = dict(**obj.__dict__)
- data["state"] = obj.instance.get_state()
- del data["instance"]
-
- return data
-
- elif isinstance(obj, SensorModel):
- data = dict(**obj.__dict__)
- data["value"] = value=obj.instance.get_value()
- data["unit"] = value = obj.instance.get_unit()
- data["state"] = obj.instance.get_state()
- del data["instance"]
- return data
- #elif callable(getattr(obj, "reprJSON")):
- # return obj.reprJSON()
- elif isinstance(obj, DBModel):
- return obj.__dict__
- #elif hasattr(obj, "callback"):
- # return obj()
+ if hasattr(obj, "to_json") and callable(getattr(obj, "to_json")):
+ return obj.to_json()
else:
raise TypeError()
except Exception as e:
diff --git a/cheat_sheet.txt b/cheat_sheet.txt
new file mode 100644
index 0000000..0be4da2
--- /dev/null
+++ b/cheat_sheet.txt
@@ -0,0 +1,11 @@
+#clean
+python3.7 setup.py clean --all
+
+#build
+python setup.py sdist
+
+#Upload
+twine upload dist/*
+
+
+
diff --git a/craftbeerpi.db b/craftbeerpi.db
index d4ae9a2..e5d0de5 100644
Binary files a/craftbeerpi.db and b/craftbeerpi.db differ
diff --git a/sample.py b/sample.py
index 1af9215..b000ad6 100644
--- a/sample.py
+++ b/sample.py
@@ -1,13 +1,8 @@
-import re
-
-pattern = "(actor)\/([\d])\/(on|toggle|off)$"
-
-p = re.compile(pattern)
-result = p.match("actor/1/toggle")
-
-print(result, result.group(3))
-
+def test123(name: str) -> str:
+
+ print(name)
+test123("HALLO")
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 86a6de5..792f731 100644
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,8 @@
from setuptools import setup, find_packages
setup(name='cbpi',
- version='4.0.0.1',
- description='CraftBeerPi API',
+ version='4.0.0.4',
+ description='CraftBeerPi',
author='Manuel Fritsch',
author_email='manuel@craftbeerpi.com',
url='http://web.craftbeerpi.com',
@@ -23,6 +23,7 @@ setup(name='cbpi',
"aiojobs==0.2.2",
"aiosqlite==0.7.0",
"cryptography==2.3.1",
+ "requests==2.22.0",
"voluptuous==0.11.5",
"pyfiglet==0.7.6"
],
diff --git a/tests/test_kettle.py b/tests/test_kettle.py
index e93e576..402af9e 100644
--- a/tests/test_kettle.py
+++ b/tests/test_kettle.py
@@ -68,9 +68,9 @@ class KettleTestCase(AioHTTPTestCase):
assert resp.status == 200
m = await resp.json()
- print(m)
- sensor_id = m["id"]
+ sensor_id = m["id"]
+ print("KETTLE", m["id"], m)
# Get sensor
resp = await self.client.get(path="/kettle/%s" % sensor_id)
assert resp.status == 200
diff --git a/tests/test_step.py b/tests/test_step.py
index 77d4811..6e73825 100644
--- a/tests/test_step.py
+++ b/tests/test_step.py
@@ -17,9 +17,11 @@ class StepTestCase(AioHTTPTestCase):
async def test_get(self):
resp = await self.client.request("GET", "/step")
+ print(resp)
assert resp.status == 200
resp = await self.client.request("GET", "/step/types")
+ print(resp)
assert resp.status == 200
@@ -28,14 +30,15 @@ class StepTestCase(AioHTTPTestCase):
data = {
"name": "Test",
"type": "CustomStepCBPi",
+ "config": {}
}
- # Add new sensor
+ # Add new step
resp = await self.client.post(path="/step/", json=data)
assert resp.status == 200
m = await resp.json()
- print(m)
+ print("Step", m)
sensor_id = m["id"]
# Get sensor
@@ -68,31 +71,37 @@ class StepTestCase(AioHTTPTestCase):
if future in done:
pass
+
+
@unittest_run_loop
async def test_process(self):
- await self.cbpi.step.stop()
- with mock.patch.object(self.cbpi.step, 'start', wraps=self.cbpi.step.start) as mock_obj:
+ step_ctlr = self.cbpi.step
+
+ await step_ctlr.clear_all()
+ await step_ctlr.add(**{"name": "Kettle1", "type": "CustomStepCBPi", "config": {"name1": "1", "temp": 99}})
+ await step_ctlr.add(**{"name": "Kettle1", "type": "CustomStepCBPi", "config": {"name1": "1", "temp": 99}})
+ await step_ctlr.add(**{"name": "Kettle1", "type": "CustomStepCBPi", "config": {"name1": "1", "temp": 99}})
+
+ await step_ctlr.stop_all()
+
+ future = self.create_wait_callback("step/+/started")
+ await step_ctlr.start()
+ await self.wait(future)
+
+ for i in range(len(step_ctlr.cache)-1):
future = self.create_wait_callback("step/+/started")
- await self.cbpi.step.start()
+ await step_ctlr.next()
await self.wait(future)
- future = self.create_wait_callback("step/+/started")
- await self.cbpi.step.next()
- await self.wait(future)
+ await self.print_steps()
- future = self.create_wait_callback("step/+/started")
- await self.cbpi.step.next()
- await self.wait(future)
- future = self.create_wait_callback("step/+/started")
- await self.cbpi.step.next()
- await self.wait(future)
- future = self.create_wait_callback("job/step/done")
- await self.cbpi.step.stop()
- await self.wait(future)
- print("COUNT", mock_obj.call_count)
- print("ARGS", mock_obj.call_args_list)
+ async def print_steps(self):
+ s = await self.cbpi.step.get_all()
+ print(s)
+ for k, v in s.items():
+ print(k, v.to_json())
\ No newline at end of file