refactoring job controller

This commit is contained in:
manuel83 2019-01-01 15:35:35 +01:00
parent ce2d942771
commit e0bec43960
28 changed files with 636 additions and 688 deletions

File diff suppressed because it is too large Load diff

View file

@ -8,21 +8,20 @@ from typing import Iterable, Callable
from cbpi_api import *
class WebSocket:
class CBPiWebSocket:
def __init__(self, cbpi) -> None:
self.cbpi = cbpi
self._callbacks = defaultdict(set)
self._clients = weakref.WeakSet()
self.logger = logging.getLogger(__name__)
self.cbpi.app.add_routes([web.get('/ws', self.websocket_handler)])
self.cbpi.bus.register_object(self)
@on_event(topic="#")
async def listen(self, topic, **kwargs):
from core.utils.encoder import ComplexEncoder
data = json.dumps(dict(topic=topic, data=dict(**kwargs)),skipkeys=True, check_circular=True, cls=ComplexEncoder)
self.logger.info("PUSH %s " % data)
self.send(data)
def send(self, data):
@ -33,10 +32,13 @@ class WebSocket:
await ws.send_str(data)
self.cbpi.app.loop.create_task(send_data(ws, data))
def add_callback(self, func: Callable, event: str) -> None:
self._callbacks[event].add(func)
def register_object(self, obj):
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "ws")]:
self.add_callback(method, method.__getattribute__("key"))
async def emit(self, event: str, *args, **kwargs) -> None:
for func in self._event_funcs(event):
await func(*args, **kwargs)

View file

@ -83,7 +83,9 @@ class ActorController(ActorHttp, CRUDController):
await self._init_actor(value)
async def _init_actor(self, actor):
print("INIT ACXTOR")
if actor.type in self.types:
print("INIT ONE ACTOT")
cfg = actor.config.copy()
cfg.update(dict(cbpi=self.cbpi, id=id, name=actor.name))
clazz = self.types[actor.type]["class"];
@ -91,7 +93,7 @@ class ActorController(ActorHttp, CRUDController):
self.cache[actor.id].instance.init()
await self.cbpi.bus.fire(topic="actor/%s/initialized" % actor.id, id=actor.id)
else:
print("NOT FOUND")
self.logger.error("Actor type '%s' not found (Available Actor Types: %s)" % (actor.type, ', '.join(self.types.keys())))

View file

@ -0,0 +1,42 @@
import asyncio
import logging
from job.aiohttp import setup, get_scheduler_from_app
logger = logging.getLogger(__name__)
class JobController(object):
def __init__(self, cbpi):
self.cbpi = cbpi
async def init(self):
await setup(self.cbpi.app, self.cbpi)
def register_background_task(self, obj):
'''
This method parses all method for the @background_task decorator and registers the background job
which will be launched during start up of the server
:param obj: the object to parse
:return:
'''
async def job_loop(app, name, interval, method):
logger.info("Start Background Task %s Interval %s Method %s" % (name, interval, method))
while True:
logger.debug("Execute Task %s - interval(%s second(s)" % (name, interval))
await asyncio.sleep(interval)
await method()
async def spawn_job(app):
scheduler = get_scheduler_from_app(self.cbpi.app)
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "background_task")]:
name = method.__getattribute__("name")
interval = method.__getattribute__("interval")
job = await scheduler.spawn(job_loop(self.app, name, interval, method), name, "background")
self.cbpi.app.on_startup.append(spawn_job)
async def start_job(self, method, name, type):
scheduler = get_scheduler_from_app(self.cbpi.app)
return await scheduler.spawn(method, name, type)

View file

@ -35,7 +35,7 @@ class KettleHttp(HttpAPI):
else:
return web.Response(status=404, text=result[1])
class KettleController(CRUDController):
class KettleController(CRUDController, KettleHttp):
'''
The main kettle controller
'''
@ -45,9 +45,8 @@ class KettleController(CRUDController):
super(KettleController, self).__init__(cbpi)
self.cbpi = cbpi
self.types = {}
self.cbpi.register(self, None)
self.http = KettleHttp(cbpi)
self.cbpi.register(self.http, "/kettle")
self.cbpi.register(self, "/kettle")
@ -113,7 +112,7 @@ class KettleController(CRUDController):
cfg.update(dict(cbpi=self.cbpi))
kettle.instance = clazz(**cfg)
await self.cbpi.start_job(kettle.instance.run(), "Kettle_logic_%s" % kettle.id, "kettle_logic%s"%id)
await self.cbpi.job.start_job(kettle.instance.run(), "Kettle_logic_%s" % kettle.id, "kettle_logic%s"%id)
else:
kettle.instance.running = False
kettle.instance = None

View file

@ -1,13 +1,11 @@
import json
import logging
import os
from logging.handlers import TimedRotatingFileHandler
from core.utils.encoder import ComplexEncoder
from core.job.aiohttp import get_scheduler_from_app
from cbpi_api import *
from core.controller.crud_controller import CRUDController
from core.database.model import SensorModel
from core.http_endpoints.http_api import HttpAPI
from core.job.aiohttp import get_scheduler_from_app
from core.utils.encoder import ComplexEncoder
class SensorController(CRUDController, HttpAPI):
@ -19,7 +17,7 @@ class SensorController(CRUDController, HttpAPI):
self.cbpi.register(self, "/sensor")
self.service = self
self.types = {}
self.logger = logging.getLogger(__name__)
self.sensors = {}
def info(self):
@ -34,8 +32,7 @@ class SensorController(CRUDController, HttpAPI):
'''
await super(SensorController, self).init()
for name, clazz in self.types.items():
pass
for id, value in self.cache.items():
if value.type in self.types:
@ -45,7 +42,8 @@ class SensorController(CRUDController, HttpAPI):
self.cache[id].instance = clazz(**cfg)
scheduler = get_scheduler_from_app(self.cbpi.app)
self.cache[id].instance.job = await scheduler.spawn(self.cache[id].instance.run(self.cbpi), value.name, "sensor")
else:
self.logger.error("Sensor type '%s' not found (Available Sensor Types: %s)" % (value.type, ', '.join(self.types.keys())))
async def get_value(self, id):
return self.cache[id].instance.value

View file

@ -62,7 +62,7 @@ class StepController(HttpAPI, CRUDController):
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.start_job(self.current_step.run(), step.name, "step")
self.current_job = await self.cbpi.job.start_job(self.current_step.run(), step.name, "step")
@request_mapping(path="/action", auth_required=False)
async def http_action(self, request):
@ -255,7 +255,7 @@ class StepController(HttpAPI, CRUDController):
inactive.stepstate = inactive.config
inactive.start = int(time.time())
await self.model.update(**inactive.__dict__)
self.current_job = await self.cbpi.start_job(self.current_step.run(), inactive.name, "step")
self.current_job = await self.cbpi.job.start_job(self.current_step.run(), inactive.name, "step")
else:
await self.cbpi.bus.fire("step/berwing/finished")

View file

@ -1,142 +1,74 @@
import asyncio
import logging
from os import urandom
import os
from os import urandom
import yaml
from aiohttp import web
from aiohttp_auth import auth
from aiohttp_session import session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_swagger import setup_swagger
from controller.job_controller import JobController
from core.cbpiwebsocket import CBPiWebSocket
from core.controller.actor_controller import ActorController
from core.controller.config_controller import ConfigController
from core.controller.kettle_controller import KettleController
from core.controller.step_controller import StepController
from core.extension.comp import MyComp
from core.job.aiohttp import setup, get_scheduler_from_app
from core.controller.actor_controller import ActorController
from core.controller.notification_controller import NotificationController
from core.controller.plugin_controller import PluginController
from core.controller.sensor_controller import SensorController
from core.controller.step_controller import StepController
from core.controller.system_controller import SystemController
from core.database.model import DBModel
from core.eventbus import CBPiEventBus
from core.http_endpoints.http_login import Login
from core.utils import *
from core.websocket import WebSocket
from core.utils.encoder import ComplexEncoder
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
"""
This is a module docstring
"""
class CraftBeerPi():
"""
This is a Hello class docstring
"""
def __init__(self):
this_directory = os.path.dirname(__file__)
self.config = load_config(os.path.join(this_directory, '../config/config.yaml'))
self.static_config = load_config(os.path.join(os.path.dirname(__file__), '../config/config.yaml'))
logger.info("Init CraftBeerPI")
policy = auth.SessionTktAuthentication(urandom(32), 60, include_ip=True)
middlewares = [web.normalize_path_middleware(), session_middleware(EncryptedCookieStorage(urandom(32))), auth.auth_middleware(policy)]
self.app = web.Application(middlewares=middlewares)
self._setup_shutdownhook()
self.initializer = []
self.shutdown = False
async def on_cleanup(app):
self.shutdown = True
self.app.on_cleanup.append(on_cleanup)
setup(self.app, self)
self.bus = CBPiEventBus(self.app.loop, self)
self.ws = WebSocket(self)
self.ws = CBPiWebSocket(self)
self.job = JobController(self)
self.actor = ActorController(self)
self.sensor = SensorController(self)
self.plugin = PluginController(self)
self.system = SystemController(self)
self.config2 = ConfigController(self)
self.config = ConfigController(self)
self.kettle = KettleController(self)
self.step = StepController(self)
self.notification = NotificationController(self)
self.login = Login(self)
self.register_events(self.ws)
def _setup_shutdownhook(self):
self.shutdown = False
async def on_cleanup(app):
self.shutdown = True
def register_events(self, obj):
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "eventbus")]:
doc = None
if method.__doc__ is not None:
try:
doc = yaml.load(method.__doc__)
doc["topic"] = method.__getattribute__("topic")
except:
pass
self.bus.register(method.__getattribute__("topic"), method)
def register_background_task(self, obj):
'''
This method parses all method for the @background_task decorator and registers the background job
which will be launched during start up of the server
:param obj: the object to parse
:return:
'''
async def job_loop(app, name, interval, method):
logger.info("Start Background Task %s Interval %s Method %s" % (name, interval, method))
while True:
logger.debug("Execute Task %s - interval(%s second(s)" % (name, interval))
await asyncio.sleep(interval)
await method()
async def spawn_job(app):
scheduler = get_scheduler_from_app(self.app)
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "background_task")]:
name = method.__getattribute__("name")
interval = method.__getattribute__("interval")
job = await scheduler.spawn(job_loop(self.app, name, interval, method),name, "background")
self.app.on_startup.append(spawn_job)
self.app.on_cleanup.append(on_cleanup)
def register_on_startup(self, obj):
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "on_startup")]:
name = method.__getattribute__("name")
order = method.__getattribute__("order")
self.initializer.append(dict(name=name, method=method, order=order))
def register_ws(self, obj):
if self.ws is None:
return
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "ws")]:
self.ws.add_callback(method, method.__getattribute__("key"))
def register(self, obj, url_prefix=None, static=None):
'''
@ -147,19 +79,13 @@ class CraftBeerPi():
:return: None
'''
self.register_http_endpoints(obj, url_prefix, static)
self.register_events(obj)
self.register_ws(obj)
self.register_background_task(obj)
self.bus.register_object(obj)
self.ws.register_object(obj)
self.job.register_background_task(obj)
self.register_on_startup(obj)
def register_http_endpoints(self, obj, url_prefix=None, static=None):
'''
This method parses the provided object for @request_mapping decorator
:param obj: the object which will be analyzed
:param url_prefix: the prefix which will be used for the all http endpoints of the object
:return:
'''
routes = []
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "route")]:
http_method = method.__getattribute__("method")
@ -185,11 +111,8 @@ class CraftBeerPi():
"DELETE": add_delete,
"PUT": add_put
}
switcher[http_method]()
if url_prefix is not None:
logger.debug("URL Prefix: %s " % (url_prefix,))
sub = web.Application()
@ -198,15 +121,8 @@ class CraftBeerPi():
sub.add_routes([web.static('/static', static, show_index=False)])
self.app.add_subapp(url_prefix, sub)
else:
self.app.add_routes(routes)
async def start_job(self, method, name, type):
scheduler = get_scheduler_from_app(self.app)
return await scheduler.spawn(method, name, type)
def _swagger_setup(self):
'''
Internatl method to expose REST API documentation by swagger
@ -219,8 +135,8 @@ class CraftBeerPi():
setup_swagger(self.app,
description=long_description,
title=self.config.get("name", "CraftBeerPi"),
api_version=self.config.get("version", ""),
title=self.static_config.get("name", "CraftBeerPi"),
api_version=self.static_config.get("version", ""),
contact="info@craftbeerpi.com")
def notify(self, key, message, type="info"):
@ -234,23 +150,6 @@ class CraftBeerPi():
'''
self.bus.sync_fire(topic="notification/%s" % key, key=key, message=message, type=type)
def setup(self):
'''
This method will start the server
:return:
'''
#async def init_database(app):
#self.app.on_startup.append(call_initializer)
async def call_initializer(self, app):
self.initializer = sorted(self.initializer, key=lambda k: k['order'])
for i in self.initializer:
@ -260,13 +159,15 @@ class CraftBeerPi():
def _print_logo(self):
from pyfiglet import Figlet
f = Figlet(font='big')
logger.info("\n%s" % f.renderText("%s %s" % (self.config.get("name"), self.config.get("version"))))
logger.info("\n%s" % f.renderText("%s %s" % (self.static_config.get("name"), self.static_config.get("version"))))
async def init_serivces(self):
self._print_logo()
await DBModel.test_connection()
await self.config2.init()
await self.job.init()
await DBModel.setup()
await self.config.init()
self.plugin.load_plugins()
self.plugin.load_plugins_from_evn()
await self.sensor.init()
@ -274,13 +175,10 @@ class CraftBeerPi():
await self.actor.init()
await self.kettle.init()
await self.call_initializer(self.app)
logger.info(self.sensor.info())
logger.info(self.actor.info())
self._swagger_setup()
return self.app
def start(self):
web.run_app(self.init_serivces(), port=self.config.get("port", 8080))
web.run_app(self.init_serivces(), port=self.static_config.get("port", 8080))

View file

@ -12,9 +12,6 @@ class DBModel(object):
__json_fields__ = []
def __init__(self, args):
self.__setattr__(self.__priamry_key__, args[self.__priamry_key__])
for f in self.__fields__:
@ -32,7 +29,7 @@ class DBModel(object):
self.__setattr__(f, args.get(f))
@classmethod
async def test_connection(self):
async def setup(self):
async with aiosqlite.connect(DATABASE_FILE) as db:
assert isinstance(db, aiosqlite.Connection)

View file

@ -185,3 +185,15 @@ class CBPiEventBus(object):
yield content
return rec(self._root)
def register_object(self, obj):
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "eventbus")]:
doc = None
if method.__doc__ is not None:
try:
doc = yaml.load(method.__doc__)
doc["topic"] = method.__getattribute__("topic")
except:
pass
self.register(method.__getattribute__("topic"), method)

View file

@ -11,7 +11,7 @@ class Login():
self.cbpi.register(self)
self.db = {cbpi.config.get("username", "cbpi"): cbpi.config.get("password", "cbpi")}
self.db = {cbpi.static_config.get("username", "cbpi"): cbpi.static_config.get("password", "cbpi")}
@request_mapping(path="/logout", name="Logout", method="GET", auth_required=True)
async def logout_view(self, request):

View file

@ -40,12 +40,14 @@ def atomic(coro):
return wrapper
def setup(app, cbpi, **kwargs):
async def on_startup(app):
async def setup(app, cbpi, **kwargs):
app['AIOJOBS_SCHEDULER'] = await create_scheduler(cbpi, **kwargs)
async def on_cleanup(app):
await app['AIOJOBS_SCHEDULER'].close()
app.on_startup.append(on_startup)
app.on_cleanup.append(on_cleanup)

Binary file not shown.

View file

@ -53,16 +53,16 @@ Typically you perform just some basing parameter validation and fire an event so
.. note::
The Events are process in an async way. Results will be pushed to the client via WebSocket Event.
The Events are process in an async way. Results will be pushed to the client via CBPiWebSocket Event.
WebSocket
CBPiWebSocket
---------
The WebSocket is listening on `http://<IP_ADDRESS>:<PORT>/ws`
The CBPiWebSocket is listening on `http://<IP_ADDRESS>:<PORT>/ws`
All events are forwarded to all connected web socket clients.
The WebSocket Event is having the following structure.
The CBPiWebSocket Event is having the following structure.
* topic -> is the bus topic
* data -> the event data

View file

@ -237,7 +237,7 @@ var Documentation = {
},
/**
* init the domain index toggle buttons
* setup the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {

View file

@ -93,8 +93,8 @@ var
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
// The jQuery object is actually just the setup constructor 'enhanced'
// Need setup if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
@ -2965,7 +2965,7 @@ var rootjQuery,
return this;
}
// Method init() accepts an alternate rootjQuery
// Method setup() accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery;
@ -3056,7 +3056,7 @@ var rootjQuery,
return jQuery.makeArray( selector, this );
};
// Give the init function the jQuery prototype for later instantiation
// Give the setup function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;
// Initialize central reference

View file

@ -171,7 +171,7 @@
<p>The main actor controller</p>
<dl class="method">
<dt id="core.controller.actor_controller.ActorController.init">
<code class="descname">init</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.actor_controller.ActorController.init" title="Permalink to this definition"></a></dt>
<code class="descname">setup</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.actor_controller.ActorController.init" title="Permalink to this definition"></a></dt>
<dd><p>This method initializes all actors during startup. It creates actor instances</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />

View file

@ -258,7 +258,7 @@
<h2 id="I">I</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="kettle_controller.html#core.api.kettle_logic.CBPiKettleLogic.init">init() (core.api.kettle_logic.CBPiKettleLogic method)</a>
<li><a href="kettle_controller.html#core.api.kettle_logic.CBPiKettleLogic.init">setup() (core.api.kettle_logic.CBPiKettleLogic method)</a>
<ul>
<li><a href="actor.html#core.controller.actor_controller.ActorController.init">(core.controller.actor_controller.ActorController method)</a>

View file

@ -189,7 +189,7 @@
<li class="toctree-l2"><a class="reference internal" href="standards.html#python">Python</a><ul>
<li class="toctree-l3"><a class="reference internal" href="standards.html#eventbus">CBPiEventBus</a></li>
<li class="toctree-l3"><a class="reference internal" href="standards.html#http-endpoints">HTTP Endpoints</a></li>
<li class="toctree-l3"><a class="reference internal" href="standards.html#websocket">WebSocket</a></li>
<li class="toctree-l3"><a class="reference internal" href="standards.html#websocket">CBPiWebSocket</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="standards.html#web-user-interface">Web User Interface</a></li>

View file

@ -244,7 +244,7 @@
<dl class="method">
<dt id="core.controller.kettle_controller.KettleController.init">
<code class="descname">init</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.kettle_controller.KettleController.init" title="Permalink to this definition"></a></dt>
<code class="descname">setup</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.kettle_controller.KettleController.init" title="Permalink to this definition"></a></dt>
<dd><p>This method initializes all actors during startup. It creates actor instances</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
@ -295,7 +295,7 @@
<p>Base Class for a Kettle logic.</p>
<dl class="method">
<dt id="core.api.kettle_logic.CBPiKettleLogic.init">
<code class="descname">init</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.api.kettle_logic.CBPiKettleLogic.init" title="Permalink to this definition"></a></dt>
<code class="descname">setup</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.api.kettle_logic.CBPiKettleLogic.init" title="Permalink to this definition"></a></dt>
<dd><p>Code which will be executed when the logic is initialised. Needs to be overwritten by the implementing logic</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />

View file

@ -170,7 +170,7 @@
<dl class="method">
<dt id="core.controller.sensor_controller.SensorController.init">
<code class="descname">init</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.sensor_controller.SensorController.init" title="Permalink to this definition"></a></dt>
<code class="descname">setup</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.sensor_controller.SensorController.init" title="Permalink to this definition"></a></dt>
<dd><p>This method initializes all actors during startup. It creates actor instances</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />

View file

@ -89,7 +89,7 @@
<li class="toctree-l2"><a class="reference internal" href="#python">Python</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#eventbus">CBPiEventBus</a></li>
<li class="toctree-l3"><a class="reference internal" href="#http-endpoints">HTTP Endpoints</a></li>
<li class="toctree-l3"><a class="reference internal" href="#websocket">WebSocket</a></li>
<li class="toctree-l3"><a class="reference internal" href="#websocket">CBPiWebSocket</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#web-user-interface">Web User Interface</a></li>
@ -202,14 +202,14 @@ Typically you perform just some basing parameter validation and fire an event so
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The Events are process in an async way. Results will be pushed to the client via WebSocket Event.</p>
<p class="last">The Events are process in an async way. Results will be pushed to the client via CBPiWebSocket Event.</p>
</div>
</div>
<div class="section" id="websocket">
<h3>WebSocket<a class="headerlink" href="#websocket" title="Permalink to this headline"></a></h3>
<p>The WebSocket is listening on <cite>http://&lt;IP_ADDRESS&gt;:&lt;PORT&gt;/ws</cite>
<h3>CBPiWebSocket<a class="headerlink" href="#websocket" title="Permalink to this headline"></a></h3>
<p>The CBPiWebSocket is listening on <cite>http://&lt;IP_ADDRESS&gt;:&lt;PORT&gt;/ws</cite>
All events are forwarded to all connected web socket clients.</p>
<p>The WebSocket Event is having the following structure.</p>
<p>The CBPiWebSocket Event is having the following structure.</p>
<ul class="simple">
<li>topic -&gt; is the bus topic</li>
<li>data -&gt; the event data</li>

View file

@ -352,7 +352,7 @@ Stops the current step</p>
<dl class="method">
<dt id="core.controller.step_controller.StepController.init">
<code class="descname">init</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.step_controller.StepController.init" title="Permalink to this definition"></a></dt>
<code class="descname">setup</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.step_controller.StepController.init" title="Permalink to this definition"></a></dt>
<dd><p>Initializer of the the Step Controller.
:return:</p>
</dd></dl>

View file

@ -55,16 +55,16 @@ Typically you perform just some basing parameter validation and fire an event so
.. note::
The Events are process in an async way. Results will be pushed to the client via WebSocket Event.
The Events are process in an async way. Results will be pushed to the client via CBPiWebSocket Event.
WebSocket
CBPiWebSocket
---------
The WebSocket is listening on `http://<IP_ADDRESS>:<PORT>/ws`
The CBPiWebSocket is listening on `http://<IP_ADDRESS>:<PORT>/ws`
All events are forwarded to all connected web socket clients.
The WebSocket Event is having the following structure.
The CBPiWebSocket Event is having the following structure.
* topic -> is the bus topic
* data -> the event data

View file

@ -7,7 +7,7 @@ from hbmqtt.broker import Broker
from hbmqtt.client import MQTTClient
from hbmqtt.mqtt.constants import QOS_1
from core.websocket import websocket_handler
from core.cbpiwebsocket import websocket_handler
TEST_DB = "test.db"
c = MQTTClient()

View file

@ -11,8 +11,6 @@ class MyAppTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
self.cbpi.setup()
await self.cbpi.init_serivces()
return self.cbpi.app
@ -21,11 +19,9 @@ class MyAppTestCase(AioHTTPTestCase):
async def test_example(self):
resp = await self.client.post(path="/login", data={"username": "cbpi", "password": "123"})
print("resp.status",resp.status)
assert resp.status == 200
resp = await self.client.request("GET", "/actor/1/on")
print("resp.status", resp.status)
assert resp.status == 204
i = await self.cbpi.actor.get_one(1)
assert i.instance.state is True
@ -46,33 +42,5 @@ class MyAppTestCase(AioHTTPTestCase):
i = await self.cbpi.actor.get_one(1)
assert i.instance.state is False
i = await self.cbpi.actor.get_all()
assert len(i) == 2
#ws = await self.client.ws_connect("/ws");
#await ws.send_str(json.dumps({"key": "test"}))
'''
@unittest_run_loop
async def test_example2(self):
print("TEST2222")
print("CLIENT ###### ", self.client)
ws = await self.client.ws_connect("/ws");
await ws.send_str(json.dumps({"topic": "test"}))
#resp = await ws.receive()
#print("##### REPSONE", resp)
assert "Manuel" in await self.cbpi.actor.get_name(), "OH NOW"
await self.client.close()
'''

View file

@ -1,32 +1,33 @@
import asyncio
import time
import aiosqlite
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi
from cbpi_api.config import ConfigType
from core.craftbeerpi import CraftBeerPi
class ConfigTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
self.cbpi.setup()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_get(self):
assert await self.cbpi.config2.get("CBPI_TEST_1", 1) == "22"
assert self.cbpi.config.get("CBPI_TEST_1", 1) == "22"
@unittest_run_loop
async def test_set_get(self):
value = str(time.time())
await self.cbpi.config2.set("CBPI_TEST_2", value)
await self.cbpi.config.set("CBPI_TEST_2", value)
assert await self.cbpi.config2.get("CBPI_TEST_2", 1) == value
assert self.cbpi.config.get("CBPI_TEST_2", 1) == value
@unittest_run_loop
async def test_add(self):
@ -36,18 +37,18 @@ class ConfigTestCase(AioHTTPTestCase):
await db.execute("DELETE FROM config WHERE name = ? ", (key,))
await db.commit()
await self.cbpi.config2.add(key, value, type=ConfigType.STRING, description="test")
await self.cbpi.config.add(key, value, type=ConfigType.STRING, description="test")
@unittest_run_loop
async def test_http_set(self):
value = str(time.time())
key = "CBPI_TEST_3"
await self.cbpi.config2.set(key, value)
assert await self.cbpi.config2.get(key, 1) == value
await self.cbpi.config.set(key, value)
assert self.cbpi.config.get(key, 1) == value
resp = await self.client.request("POST", "/config/%s/" % key, json={'value': '1'})
assert resp.status == 204
assert await self.cbpi.config2.get(key, -1) == "1"
assert self.cbpi.config.get(key, -1) == "1"
@unittest_run_loop
async def test_http_get(self):

View file

@ -8,19 +8,33 @@ class KettleTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
self.cbpi.setup()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_get(self):
resp = await self.client.request("GET", "/kettle")
assert resp.status == 200
print(await resp.json())
@unittest_run_loop
async def test_example(self):
await asyncio.sleep(10)
for i in range(100):
resp = await self.client.request("GET", "/actor/")
print(resp)
resp = await self.client.post(path="/actor/", json={ "name": "Test", "type": "CustomActor", "config": {"gpio": 22 }})
print(resp)
async def test_add(self):
data = {
"name": "Test",
"sensor": None,
"heater": "1",
"automatic": None,
"logic": "CustomKettleLogic",
"config": {
"test": "WOOHO"
},
"agitator": None,
"target_temp": None
}
resp = await self.client.post(path="/kettle/", json=data)
assert resp.status == 200
'''
result = await self.cbpi.kettle.toggle_automtic(1)