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

View file

@ -83,7 +83,9 @@ class ActorController(ActorHttp, CRUDController):
await self._init_actor(value) await self._init_actor(value)
async def _init_actor(self, actor): async def _init_actor(self, actor):
print("INIT ACXTOR")
if actor.type in self.types: if actor.type in self.types:
print("INIT ONE ACTOT")
cfg = actor.config.copy() cfg = actor.config.copy()
cfg.update(dict(cbpi=self.cbpi, id=id, name=actor.name)) cfg.update(dict(cbpi=self.cbpi, id=id, name=actor.name))
clazz = self.types[actor.type]["class"]; clazz = self.types[actor.type]["class"];
@ -91,7 +93,7 @@ class ActorController(ActorHttp, CRUDController):
self.cache[actor.id].instance.init() self.cache[actor.id].instance.init()
await self.cbpi.bus.fire(topic="actor/%s/initialized" % actor.id, id=actor.id) await self.cbpi.bus.fire(topic="actor/%s/initialized" % actor.id, id=actor.id)
else: else:
print("NOT FOUND")
self.logger.error("Actor type '%s' not found (Available Actor Types: %s)" % (actor.type, ', '.join(self.types.keys()))) 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: else:
return web.Response(status=404, text=result[1]) return web.Response(status=404, text=result[1])
class KettleController(CRUDController): class KettleController(CRUDController, KettleHttp):
''' '''
The main kettle controller The main kettle controller
''' '''
@ -45,9 +45,8 @@ class KettleController(CRUDController):
super(KettleController, self).__init__(cbpi) super(KettleController, self).__init__(cbpi)
self.cbpi = cbpi self.cbpi = cbpi
self.types = {} self.types = {}
self.cbpi.register(self, None) self.cbpi.register(self, "/kettle")
self.http = KettleHttp(cbpi)
self.cbpi.register(self.http, "/kettle")
@ -113,7 +112,7 @@ class KettleController(CRUDController):
cfg.update(dict(cbpi=self.cbpi)) cfg.update(dict(cbpi=self.cbpi))
kettle.instance = clazz(**cfg) 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: else:
kettle.instance.running = False kettle.instance.running = False
kettle.instance = None kettle.instance = None

View file

@ -1,13 +1,11 @@
import json import json
import logging 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.controller.crud_controller import CRUDController
from core.database.model import SensorModel from core.database.model import SensorModel
from core.http_endpoints.http_api import HttpAPI 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): class SensorController(CRUDController, HttpAPI):
@ -19,7 +17,7 @@ class SensorController(CRUDController, HttpAPI):
self.cbpi.register(self, "/sensor") self.cbpi.register(self, "/sensor")
self.service = self self.service = self
self.types = {} self.types = {}
self.logger = logging.getLogger(__name__)
self.sensors = {} self.sensors = {}
def info(self): def info(self):
@ -34,8 +32,7 @@ class SensorController(CRUDController, HttpAPI):
''' '''
await super(SensorController, self).init() await super(SensorController, self).init()
for name, clazz in self.types.items():
pass
for id, value in self.cache.items(): for id, value in self.cache.items():
if value.type in self.types: if value.type in self.types:
@ -45,7 +42,8 @@ class SensorController(CRUDController, HttpAPI):
self.cache[id].instance = clazz(**cfg) self.cache[id].instance = clazz(**cfg)
scheduler = get_scheduler_from_app(self.cbpi.app) 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") 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): async def get_value(self, id):
return self.cache[id].instance.value 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))) 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_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) @request_mapping(path="/action", auth_required=False)
async def http_action(self, request): async def http_action(self, request):
@ -255,7 +255,7 @@ class StepController(HttpAPI, CRUDController):
inactive.stepstate = inactive.config inactive.stepstate = inactive.config
inactive.start = int(time.time()) inactive.start = int(time.time())
await self.model.update(**inactive.__dict__) 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: else:
await self.cbpi.bus.fire("step/berwing/finished") await self.cbpi.bus.fire("step/berwing/finished")

View file

@ -1,142 +1,74 @@
import asyncio
import logging import logging
from os import urandom
import os import os
from os import urandom
import yaml
from aiohttp import web from aiohttp import web
from aiohttp_auth import auth from aiohttp_auth import auth
from aiohttp_session import session_middleware from aiohttp_session import session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_swagger import setup_swagger 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.config_controller import ConfigController
from core.controller.kettle_controller import KettleController 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.notification_controller import NotificationController
from core.controller.plugin_controller import PluginController from core.controller.plugin_controller import PluginController
from core.controller.sensor_controller import SensorController from core.controller.sensor_controller import SensorController
from core.controller.step_controller import StepController
from core.controller.system_controller import SystemController from core.controller.system_controller import SystemController
from core.database.model import DBModel from core.database.model import DBModel
from core.eventbus import CBPiEventBus from core.eventbus import CBPiEventBus
from core.http_endpoints.http_login import Login from core.http_endpoints.http_login import Login
from core.utils import * from core.utils import *
from core.websocket import WebSocket
from core.utils.encoder import ComplexEncoder
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
"""
This is a module docstring
"""
class CraftBeerPi(): class CraftBeerPi():
"""
This is a Hello class docstring
"""
def __init__(self): def __init__(self):
this_directory = os.path.dirname(__file__) self.static_config = load_config(os.path.join(os.path.dirname(__file__), '../config/config.yaml'))
self.config = load_config(os.path.join(this_directory, '../config/config.yaml'))
logger.info("Init CraftBeerPI") logger.info("Init CraftBeerPI")
policy = auth.SessionTktAuthentication(urandom(32), 60, include_ip=True) policy = auth.SessionTktAuthentication(urandom(32), 60, include_ip=True)
middlewares = [web.normalize_path_middleware(), session_middleware(EncryptedCookieStorage(urandom(32))), auth.auth_middleware(policy)] middlewares = [web.normalize_path_middleware(), session_middleware(EncryptedCookieStorage(urandom(32))), auth.auth_middleware(policy)]
self.app = web.Application(middlewares=middlewares) self.app = web.Application(middlewares=middlewares)
self._setup_shutdownhook()
self.initializer = [] 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.bus = CBPiEventBus(self.app.loop, self)
self.ws = WebSocket(self) self.ws = CBPiWebSocket(self)
self.job = JobController(self)
self.actor = ActorController(self) self.actor = ActorController(self)
self.sensor = SensorController(self) self.sensor = SensorController(self)
self.plugin = PluginController(self) self.plugin = PluginController(self)
self.system = SystemController(self) self.system = SystemController(self)
self.config2 = ConfigController(self) self.config = ConfigController(self)
self.kettle = KettleController(self) self.kettle = KettleController(self)
self.step = StepController(self) self.step = StepController(self)
self.notification = NotificationController(self) self.notification = NotificationController(self)
self.login = Login(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): self.app.on_cleanup.append(on_cleanup)
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)
def register_on_startup(self, obj): 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")]: 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") name = method.__getattribute__("name")
order = method.__getattribute__("order") order = method.__getattribute__("order")
self.initializer.append(dict(name=name, method=method, order=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): def register(self, obj, url_prefix=None, static=None):
''' '''
@ -147,19 +79,13 @@ class CraftBeerPi():
:return: None :return: None
''' '''
self.register_http_endpoints(obj, url_prefix, static) self.register_http_endpoints(obj, url_prefix, static)
self.register_events(obj) self.bus.register_object(obj)
self.register_ws(obj) self.ws.register_object(obj)
self.register_background_task(obj) self.job.register_background_task(obj)
self.register_on_startup(obj) self.register_on_startup(obj)
def register_http_endpoints(self, obj, url_prefix=None, static=None): 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 = [] routes = []
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "route")]: 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") http_method = method.__getattribute__("method")
@ -185,11 +111,8 @@ class CraftBeerPi():
"DELETE": add_delete, "DELETE": add_delete,
"PUT": add_put "PUT": add_put
} }
switcher[http_method]() switcher[http_method]()
if url_prefix is not None: if url_prefix is not None:
logger.debug("URL Prefix: %s " % (url_prefix,)) logger.debug("URL Prefix: %s " % (url_prefix,))
sub = web.Application() sub = web.Application()
@ -198,15 +121,8 @@ class CraftBeerPi():
sub.add_routes([web.static('/static', static, show_index=False)]) sub.add_routes([web.static('/static', static, show_index=False)])
self.app.add_subapp(url_prefix, sub) self.app.add_subapp(url_prefix, sub)
else: else:
self.app.add_routes(routes) 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): def _swagger_setup(self):
''' '''
Internatl method to expose REST API documentation by swagger Internatl method to expose REST API documentation by swagger
@ -219,8 +135,8 @@ class CraftBeerPi():
setup_swagger(self.app, setup_swagger(self.app,
description=long_description, description=long_description,
title=self.config.get("name", "CraftBeerPi"), title=self.static_config.get("name", "CraftBeerPi"),
api_version=self.config.get("version", ""), api_version=self.static_config.get("version", ""),
contact="info@craftbeerpi.com") contact="info@craftbeerpi.com")
def notify(self, key, message, type="info"): 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) 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): async def call_initializer(self, app):
self.initializer = sorted(self.initializer, key=lambda k: k['order']) self.initializer = sorted(self.initializer, key=lambda k: k['order'])
for i in self.initializer: for i in self.initializer:
@ -260,13 +159,15 @@ class CraftBeerPi():
def _print_logo(self): def _print_logo(self):
from pyfiglet import Figlet from pyfiglet import Figlet
f = Figlet(font='big') 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): async def init_serivces(self):
self._print_logo() 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()
self.plugin.load_plugins_from_evn() self.plugin.load_plugins_from_evn()
await self.sensor.init() await self.sensor.init()
@ -274,13 +175,10 @@ class CraftBeerPi():
await self.actor.init() await self.actor.init()
await self.kettle.init() await self.kettle.init()
await self.call_initializer(self.app) await self.call_initializer(self.app)
logger.info(self.sensor.info())
logger.info(self.actor.info())
self._swagger_setup() self._swagger_setup()
return self.app return self.app
def start(self): 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__ = [] __json_fields__ = []
def __init__(self, args): def __init__(self, args):
self.__setattr__(self.__priamry_key__, args[self.__priamry_key__]) self.__setattr__(self.__priamry_key__, args[self.__priamry_key__])
for f in self.__fields__: for f in self.__fields__:
@ -32,7 +29,7 @@ class DBModel(object):
self.__setattr__(f, args.get(f)) self.__setattr__(f, args.get(f))
@classmethod @classmethod
async def test_connection(self): async def setup(self):
async with aiosqlite.connect(DATABASE_FILE) as db: async with aiosqlite.connect(DATABASE_FILE) as db:
assert isinstance(db, aiosqlite.Connection) assert isinstance(db, aiosqlite.Connection)

View file

@ -185,3 +185,15 @@ class CBPiEventBus(object):
yield content yield content
return rec(self._root) 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.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) @request_mapping(path="/logout", name="Logout", method="GET", auth_required=True)
async def logout_view(self, request): async def logout_view(self, request):

View file

@ -40,12 +40,14 @@ def atomic(coro):
return wrapper 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) app['AIOJOBS_SCHEDULER'] = await create_scheduler(cbpi, **kwargs)
async def on_cleanup(app): async def on_cleanup(app):
await app['AIOJOBS_SCHEDULER'].close() await app['AIOJOBS_SCHEDULER'].close()
app.on_startup.append(on_startup)
app.on_cleanup.append(on_cleanup) 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:: .. 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. 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 * topic -> is the bus topic
* data -> the event data * 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() { initIndexTable : function() {
var togglers = $('img.toggler').click(function() { var togglers = $('img.toggler').click(function() {

View file

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

View file

@ -171,7 +171,7 @@
<p>The main actor controller</p> <p>The main actor controller</p>
<dl class="method"> <dl class="method">
<dt id="core.controller.actor_controller.ActorController.init"> <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> <dd><p>This method initializes all actors during startup. It creates actor instances</p>
<table class="docutils field-list" frame="void" rules="none"> <table class="docutils field-list" frame="void" rules="none">
<col class="field-name" /> <col class="field-name" />

View file

@ -258,7 +258,7 @@
<h2 id="I">I</h2> <h2 id="I">I</h2>
<table style="width: 100%" class="indextable genindextable"><tr> <table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul> <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> <ul>
<li><a href="actor.html#core.controller.actor_controller.ActorController.init">(core.controller.actor_controller.ActorController method)</a> <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-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#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#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> </ul>
</li> </li>
<li class="toctree-l2"><a class="reference internal" href="standards.html#web-user-interface">Web User Interface</a></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"> <dl class="method">
<dt id="core.controller.kettle_controller.KettleController.init"> <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> <dd><p>This method initializes all actors during startup. It creates actor instances</p>
<table class="docutils field-list" frame="void" rules="none"> <table class="docutils field-list" frame="void" rules="none">
<col class="field-name" /> <col class="field-name" />
@ -295,7 +295,7 @@
<p>Base Class for a Kettle logic.</p> <p>Base Class for a Kettle logic.</p>
<dl class="method"> <dl class="method">
<dt id="core.api.kettle_logic.CBPiKettleLogic.init"> <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> <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"> <table class="docutils field-list" frame="void" rules="none">
<col class="field-name" /> <col class="field-name" />

View file

@ -170,7 +170,7 @@
<dl class="method"> <dl class="method">
<dt id="core.controller.sensor_controller.SensorController.init"> <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> <dd><p>This method initializes all actors during startup. It creates actor instances</p>
<table class="docutils field-list" frame="void" rules="none"> <table class="docutils field-list" frame="void" rules="none">
<col class="field-name" /> <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-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="#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="#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> </ul>
</li> </li>
<li class="toctree-l2"><a class="reference internal" href="#web-user-interface">Web User Interface</a></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>
<div class="admonition note"> <div class="admonition note">
<p class="first admonition-title">Note</p> <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> </div>
<div class="section" id="websocket"> <div class="section" id="websocket">
<h3>WebSocket<a class="headerlink" href="#websocket" title="Permalink to this headline"></a></h3> <h3>CBPiWebSocket<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> <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> 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"> <ul class="simple">
<li>topic -&gt; is the bus topic</li> <li>topic -&gt; is the bus topic</li>
<li>data -&gt; the event data</li> <li>data -&gt; the event data</li>

View file

@ -352,7 +352,7 @@ Stops the current step</p>
<dl class="method"> <dl class="method">
<dt id="core.controller.step_controller.StepController.init"> <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. <dd><p>Initializer of the the Step Controller.
:return:</p> :return:</p>
</dd></dl> </dd></dl>

View file

@ -55,16 +55,16 @@ Typically you perform just some basing parameter validation and fire an event so
.. note:: .. 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. 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 * topic -> is the bus topic
* data -> the event data * data -> the event data

View file

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

View file

@ -11,8 +11,6 @@ class MyAppTestCase(AioHTTPTestCase):
async def get_application(self): async def get_application(self):
self.cbpi = CraftBeerPi() self.cbpi = CraftBeerPi()
self.cbpi.setup()
await self.cbpi.init_serivces() await self.cbpi.init_serivces()
return self.cbpi.app return self.cbpi.app
@ -21,11 +19,9 @@ class MyAppTestCase(AioHTTPTestCase):
async def test_example(self): async def test_example(self):
resp = await self.client.post(path="/login", data={"username": "cbpi", "password": "123"}) resp = await self.client.post(path="/login", data={"username": "cbpi", "password": "123"})
print("resp.status",resp.status)
assert resp.status == 200 assert resp.status == 200
resp = await self.client.request("GET", "/actor/1/on") resp = await self.client.request("GET", "/actor/1/on")
print("resp.status", resp.status)
assert resp.status == 204 assert resp.status == 204
i = await self.cbpi.actor.get_one(1) i = await self.cbpi.actor.get_one(1)
assert i.instance.state is True assert i.instance.state is True
@ -46,33 +42,5 @@ class MyAppTestCase(AioHTTPTestCase):
i = await self.cbpi.actor.get_one(1) i = await self.cbpi.actor.get_one(1)
assert i.instance.state is False 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 time
import aiosqlite import aiosqlite
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi
from cbpi_api.config import ConfigType from cbpi_api.config import ConfigType
from core.craftbeerpi import CraftBeerPi
class ConfigTestCase(AioHTTPTestCase): class ConfigTestCase(AioHTTPTestCase):
async def get_application(self): async def get_application(self):
self.cbpi = CraftBeerPi() self.cbpi = CraftBeerPi()
self.cbpi.setup() await self.cbpi.init_serivces()
return self.cbpi.app return self.cbpi.app
@unittest_run_loop @unittest_run_loop
async def test_get(self): 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 @unittest_run_loop
async def test_set_get(self): async def test_set_get(self):
value = str(time.time()) 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 @unittest_run_loop
async def test_add(self): async def test_add(self):
@ -36,18 +37,18 @@ class ConfigTestCase(AioHTTPTestCase):
await db.execute("DELETE FROM config WHERE name = ? ", (key,)) await db.execute("DELETE FROM config WHERE name = ? ", (key,))
await db.commit() 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 @unittest_run_loop
async def test_http_set(self): async def test_http_set(self):
value = str(time.time()) value = str(time.time())
key = "CBPI_TEST_3" key = "CBPI_TEST_3"
await self.cbpi.config2.set(key, value) await self.cbpi.config.set(key, value)
assert await self.cbpi.config2.get(key, 1) == value assert self.cbpi.config.get(key, 1) == value
resp = await self.client.request("POST", "/config/%s/" % key, json={'value': '1'}) resp = await self.client.request("POST", "/config/%s/" % key, json={'value': '1'})
assert resp.status == 204 assert resp.status == 204
assert await self.cbpi.config2.get(key, -1) == "1" assert self.cbpi.config.get(key, -1) == "1"
@unittest_run_loop @unittest_run_loop
async def test_http_get(self): async def test_http_get(self):

View file

@ -8,19 +8,33 @@ class KettleTestCase(AioHTTPTestCase):
async def get_application(self): async def get_application(self):
self.cbpi = CraftBeerPi() self.cbpi = CraftBeerPi()
self.cbpi.setup() await self.cbpi.init_serivces()
return self.cbpi.app 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 @unittest_run_loop
async def test_example(self): async def test_add(self):
await asyncio.sleep(10) data = {
for i in range(100): "name": "Test",
resp = await self.client.request("GET", "/actor/") "sensor": None,
print(resp) "heater": "1",
resp = await self.client.post(path="/actor/", json={ "name": "Test", "type": "CustomActor", "config": {"gpio": 22 }}) "automatic": None,
print(resp) "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) result = await self.cbpi.kettle.toggle_automtic(1)