From: Benjamin Braatz Date: Wed, 24 Feb 2021 05:16:00 +0000 (+0100) Subject: Initial commit X-Git-Tag: v0.3.0~95 X-Git-Url: http://git.graph-it.com/?a=commitdiff_plain;h=bfcc5d7c3b967da05b976883a63d2946cece7af1;p=graphit%2Fcontrolpi.git Initial commit --- bfcc5d7c3b967da05b976883a63d2946cece7af1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6dcc565 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +controlpi.egg-info/ +venv/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ebb8ac1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2021 Graph-IT GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..003e3d2 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Control-Pi-Infrastruktur + diff --git a/conf.json b/conf.json new file mode 100644 index 0000000..18eeee5 --- /dev/null +++ b/conf.json @@ -0,0 +1,27 @@ +{ "delay": + [ { "name": "D1", + "seconds": 1.0 }, + { "name": "D2", + "seconds": 2.0 } ], + "alias": + [ { "name": "One-second delay", + "aliasfor": + { "name": "D1" } }, + { "name": "Two-second delay finished", + "aliasfor": + { "name": "D2", + "event": "finished" } } ], + "log": + [ { "name": "Debug Logger", + "filter": {} }, + { "name": "Test Logger", + "filter": { "name": "Test" } } ], + "init": + [ { "name": "Test Procedure", + "commands": + [ { "name": "Test", "event": "started" }, + { "name": "D1", "command": "start" }, + { "name": "D2", "command": "start" }, + { "name": "D1", "command": "start" }, + { "name": "D2", "command": "start" }, + { "name": "Test", "event": "stopped" } ] } ] } diff --git a/controlpi/__init__.py b/controlpi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/controlpi/main.py b/controlpi/main.py new file mode 100644 index 0000000..1c2d6bc --- /dev/null +++ b/controlpi/main.py @@ -0,0 +1,74 @@ +import sys +import json +import asyncio +import pkgutil +import importlib + +import controlpi.plugins + + +def get_triggered(message, triggers): + result = [] + for key in triggers: + if key == '*': + result.extend(triggers[key]) + elif key in message: + value = message[key] + if value in triggers[key]: + result.extend(get_triggered(message, triggers[key][value])) + return result + + +class ControlPi: + def __init__(self): + self._queue = asyncio.Queue() + self._triggers = {} + + def register(self, message_template, async_callback): + current = self._triggers + for key in message_template: + value = message_template[key] + if key not in current: + current[key] = {} + if value not in current[key]: + current[key][value] = {} + current = current[key][value] + if '*' not in current: + current['*'] = [] + current['*'].append(async_callback) + + async def send(self, message): + await self._queue.put(message) + + async def run(self): + while True: + message = await self._queue.get() + for async_callback in get_triggered(message, self._triggers): + asyncio.create_task(async_callback(message)) + self._queue.task_done() + + +async def main(): + plugins = {name: importlib.import_module(name) + for finder, name, ispkg + in pkgutil.iter_modules(controlpi.plugins.__path__, + controlpi.plugins.__name__ + ".")} + control_pi = ControlPi() + coros = [control_pi.run()] + with open(sys.argv[1]) as json_data: + conf = json.load(json_data) + for plugin_name in conf: + full_plugin_name = 'controlpi.plugins.' + plugin_name + if full_plugin_name in plugins: + module = plugins[full_plugin_name] + plugin_confs = conf[plugin_name] + for plugin_conf in plugin_confs: + coros.append(module.init(control_pi, plugin_conf)) + await asyncio.gather(*coros) + + +if __name__ == '__main__': + try: + asyncio.run(main()) + except KeyboardInterrupt: + pass diff --git a/controlpi/plugins/delay.py b/controlpi/plugins/delay.py new file mode 100644 index 0000000..95e02eb --- /dev/null +++ b/controlpi/plugins/delay.py @@ -0,0 +1,20 @@ +import asyncio +import functools + + +async def waiter(control_pi, name, seconds, message): + await asyncio.sleep(seconds) + await control_pi.send({"name": name, "event": "delay finished"}) + + +async def init_finished(name): + print(f"{name} initialised") + + +def init(control_pi, conf): + control_pi.register({"name": conf['name'], "command": "start"}, + functools.partial(waiter, + control_pi, + conf['name'], + conf['seconds'])) + return init_finished(conf['name']) diff --git a/controlpi/plugins/init.py b/controlpi/plugins/init.py new file mode 100644 index 0000000..df10a9b --- /dev/null +++ b/controlpi/plugins/init.py @@ -0,0 +1,11 @@ +import asyncio + + +async def run(control_pi, conf): + print(f"{conf['name']} initialised") + for message in conf['commands']: + await control_pi.send(message) + + +def init(control_pi, conf): + return run(control_pi, conf) diff --git a/controlpi/plugins/log.py b/controlpi/plugins/log.py new file mode 100644 index 0000000..2b54318 --- /dev/null +++ b/controlpi/plugins/log.py @@ -0,0 +1,15 @@ +import functools + + +async def logger(name, message): + print(f"{name}: {message}") + + +async def init_finished(name): + print(f"{name} initialised") + + +def init(control_pi, conf): + control_pi.register(conf['filter'], + functools.partial(logger, conf['name'])) + return init_finished(conf['name']) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..890d134 --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +import setuptools + +with open("README.md", "r") as readme_file: + long_description = readme_file.read() + +setuptools.setup( + name="controlpi", + version="0.1.0", + author="Graph-IT GmbH", + author_email="info@graph-it.com", + description="Control-Pi-Infrastruktur", + long_description=long_description, + long_description_content_type="text/markdown", + url="http://docs.graph-it.com/graphit/controlpi", + packages=setuptools.find_namespace_packages(include=['controlpi_plugins.*']), + classifiers=[ + "Programming Language :: Python", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], +)