Implemented Node-RED backend, solves #88
This commit is contained in:
parent
588e16df5d
commit
d498c21518
4 changed files with 87 additions and 0 deletions
47
platypush/backend/nodered/__init__.py
Normal file
47
platypush/backend/nodered/__init__.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from platypush.backend import Backend
|
||||||
|
|
||||||
|
|
||||||
|
class NoderedBackend(Backend):
|
||||||
|
"""
|
||||||
|
This backend publishes platypush actions to a Node-RED instance.
|
||||||
|
If you enable this backend on a host that runs Node-RED then a new block (platypush -> run) can be
|
||||||
|
used in your flows. This block will accept JSON requests as input in the format
|
||||||
|
``{"type":"request", "action":"plugin.name.action_name", "args": {...}}`` and return the output
|
||||||
|
of the action as block output, or raise an exception if the action failed.
|
||||||
|
|
||||||
|
Requires:
|
||||||
|
|
||||||
|
* **pynodered** (``pip install pynodered``)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, port: int = 5051, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
:param port: Listening port for the local publishing web server (default: 5051)
|
||||||
|
"""
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.port = port
|
||||||
|
self._runner_path = os.path.join(
|
||||||
|
os.path.dirname(inspect.getfile(self.__class__)), 'runner.py')
|
||||||
|
self._server = None
|
||||||
|
|
||||||
|
def on_stop(self):
|
||||||
|
if self._server:
|
||||||
|
self._server.terminate()
|
||||||
|
self._server = None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
super().run()
|
||||||
|
|
||||||
|
self._server = subprocess.Popen([sys.executable, '-m', 'pynodered.server',
|
||||||
|
'--port', str(self.port), self._runner_path])
|
||||||
|
|
||||||
|
self.logger.info('Started Node-RED backend on port {}'.format(self.port))
|
||||||
|
self._server.wait()
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
35
platypush/backend/nodered/runner.py
Normal file
35
platypush/backend/nodered/runner.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
from pynodered import node_red
|
||||||
|
from platypush.context import get_plugin
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
|
@node_red(name='run', title='run', category='platypush', description='Run a platypush action')
|
||||||
|
def run(node, msg):
|
||||||
|
msg = msg['payload']
|
||||||
|
if isinstance(msg, bytes):
|
||||||
|
msg = msg.decode()
|
||||||
|
if isinstance(msg, str):
|
||||||
|
msg = json.loads(msg)
|
||||||
|
|
||||||
|
assert isinstance(msg, dict) and 'action' in msg
|
||||||
|
|
||||||
|
if 'type' not in msg:
|
||||||
|
msg['type'] = 'request'
|
||||||
|
|
||||||
|
plugin_name = '.'.join(msg['action'].split('.')[:-1])
|
||||||
|
action_name = msg['action'].split('.')[-1]
|
||||||
|
plugin = get_plugin(plugin_name)
|
||||||
|
action = getattr(plugin, action_name)
|
||||||
|
args = msg.get('args', {})
|
||||||
|
|
||||||
|
response = action(**args)
|
||||||
|
if response.errors:
|
||||||
|
raise response.errors[0]
|
||||||
|
|
||||||
|
msg['payload'] = response.output
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
|
@ -184,3 +184,6 @@ croniter
|
||||||
|
|
||||||
# Support for RST->HTML docstring conversion
|
# Support for RST->HTML docstring conversion
|
||||||
# docutils
|
# docutils
|
||||||
|
|
||||||
|
# Support for Node-RED integration
|
||||||
|
# nodered
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -248,6 +248,8 @@ setup(
|
||||||
'cv': ['cv2', 'numpy'],
|
'cv': ['cv2', 'numpy'],
|
||||||
# Support for the generation of HTML documentation from docstring
|
# Support for the generation of HTML documentation from docstring
|
||||||
'htmldoc': ['docutils'],
|
'htmldoc': ['docutils'],
|
||||||
|
# Support for Node-RED integration
|
||||||
|
'nodered': ['pynodered'],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue