mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-12-25 06:54:53 +01:00
refactoring job controller
This commit is contained in:
parent
ce2d942771
commit
e0bec43960
28 changed files with 636 additions and 688 deletions
File diff suppressed because it is too large
Load diff
|
@ -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)
|
|
@ -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())))
|
||||
|
||||
|
||||
|
|
42
core/controller/job_controller.py
Normal file
42
core/controller/job_controller.py
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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):
|
||||
|
|
|
@ -40,12 +40,14 @@ def atomic(coro):
|
|||
return wrapper
|
||||
|
||||
|
||||
def setup(app, cbpi, **kwargs):
|
||||
async def on_startup(app):
|
||||
app['AIOJOBS_SCHEDULER'] = await create_scheduler(cbpi, **kwargs)
|
||||
|
||||
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)
|
||||
app.on_cleanup.append(on_cleanup)
|
||||
|
||||
|
||||
|
|
BIN
craftbeerpi.db
BIN
craftbeerpi.db
Binary file not shown.
|
@ -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
|
||||
|
|
2
docs/_static/doctools.js
vendored
2
docs/_static/doctools.js
vendored
|
@ -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() {
|
||||
|
|
8
docs/_static/jquery-3.2.1.js
vendored
8
docs/_static/jquery-3.2.1.js
vendored
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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://<IP_ADDRESS>:<PORT>/ws</cite>
|
||||
<h3>CBPiWebSocket<a class="headerlink" href="#websocket" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The CBPiWebSocket is listening on <cite>http://<IP_ADDRESS>:<PORT>/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 -> is the bus topic</li>
|
||||
<li>data -> the event data</li>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
2
main.py
2
main.py
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
'''
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue