From: Benjamin Braatz Date: Wed, 23 Aug 2023 08:34:38 +0000 (+0200) Subject: First version finished. X-Git-Url: http://git.graph-it.com/?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=graphit%2Fcontrolpi-readjson.git First version finished. --- diff --git a/.gitignore b/.gitignore index 6ece8bc..4cb81f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /venv/ /controlpi_readjson.egg-info/ +__pycache__/ diff --git a/conf.json b/conf.json index 559c702..d8d6c1d 100644 --- a/conf.json +++ b/conf.json @@ -1,16 +1,10 @@ { - "Debug": { - "plugin": "WSServer", - "web": { - "/": { - "module": "controlpi_plugins.wsserver", - "location": "Debug" - } - } - }, "Log": { "plugin": "Log", "filter": [{}] }, - <...> + "SerialTest": { + "plugin": "ReadJSON", + "device": "/tmp/serialout" + } } diff --git a/controlpi_plugins/readjson.py b/controlpi_plugins/readjson.py index 72284c9..e8cbf0d 100644 --- a/controlpi_plugins/readjson.py +++ b/controlpi_plugins/readjson.py @@ -1,41 +1,58 @@ -"""ControlPi Plugin for .""" +"""ControlPi Plugin for Reading JSON from a Serial Device.""" import asyncio +import json +import serial # type: ignore +import serial_asyncio # type: ignore from controlpi import BasePlugin, Message, MessageTemplate from controlpi.baseplugin import JSONSchema -class Example(BasePlugin): - """ControlPi plugin for .""" +class ReadJSON(BasePlugin): + """ControlPi plugin for reading JSON from a serial device.""" CONF_SCHEMA: JSONSchema = {'properties': - {'init': {'type': 'boolean', - 'default': False}}, - 'required': []} + {'device': {'type': 'string'}, + 'baudrate': {'type': 'integer', + 'enum': [2400, 4800, 9600, + 19200, 38400, 57600, + 115200], + 'default': 115200}, + 'parity': {'type': 'string', + 'enum': ['even', 'odd', 'none'], + 'default': 'none'}, + 'stopbits': {'type': 'integer', + 'minimum': 1, + 'maximum': 2, + 'default': 1}}, + 'required': ['device']} def process_conf(self) -> None: - """Register bus client.""" - self._state = self.conf['init'] - self.bus.register(self.name, 'Example', - [MessageTemplate({'event': - {'const': 'changed'}, - 'state': - {'type': 'boolean'}}), - MessageTemplate({'state': - {'type': 'boolean'}})], - [([MessageTemplate({'target': - {'const': self.name}, - 'command': - {'const': 'get state'}})], - self._get_state)]) - - async def _get_state(self, message) -> None: - await self.bus.send(Message(self.name, {'state': self._state})) + """Process configuration and register bus client.""" + # Translate string in configuration to constant from serial module: + if self.conf['parity'] == 'even': + self._parity = serial.PARITY_EVEN + elif self.conf['parity'] == 'odd': + self._parity = serial.PARITY_ODD + elif self.conf['parity'] == 'none': + self._parity = serial.PARITY_NONE + # Register message bus client: + # Can send arbitrary messages, receives nothing. + self.bus.register(self.name, 'ReadJSON', [MessageTemplate()], []) async def run(self) -> None: - """Run main loop of the plugin.""" + """Run main loop of the plugin reading the serial device.""" + reader, writer = await serial_asyncio.open_serial_connection( + url=self.conf['device'], baudrate=self.conf['baudrate'], + parity=self._parity, stopbits=self.conf['stopbits']) while True: - self._state = not self._state - await self.bus.send(Message(self.name, {'event': 'changed', - 'state': self._state})) - await asyncio.sleep(10) + line = await reader.readline() + message = None + try: + message = json.loads(line.decode()) + except UnicodeDecodeError: + pass + except json.decoder.JSONDecodeError: + pass + if message and isinstance(message, dict): + await self.bus.send(Message(self.name, message)) diff --git a/doc/Test.png b/doc/Test.png new file mode 100644 index 0000000..b543de6 Binary files /dev/null and b/doc/Test.png differ diff --git a/doc/index.md b/doc/index.md index 4a1d3c2..fcd673d 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,5 +1,9 @@ -# ControlPi-Plugin für -Dieses Paket enthält ein Plugin für das ControlPi-System, mit dem <...> +# ControlPi-Plugin für das Lesen von JSON von einem seriellen Device +Dieses Paket enthält ein Plugin für das ControlPi-System, mit dem von einem +seriellen Device JSON-Nachrichten gelesen und auf den Message-Bus des +ControlPi-Systems gelegt werden können. +Alle auf der seriellen Schnittstelle gelesenen Zeilen, die keine +JSON-Objekte sind, werden ignoriert. ## Installation Eine ausführliche Dokumentation ist in der Dokumentation der @@ -8,7 +12,7 @@ finden. Der Code dieses Plugins kann mit git geclonet werden: ```sh -$ git clone git://git.graph-it.com/graphit/controlpi-.git +$ git clone git://git.graph-it.com/graphit/controlpi-readjson.git ``` (Falls Zugang zu diesem Server per SSH besteht und Änderungen gepusht werden sollen, sollte stattdessen die SSH-URL benutzt werden.) @@ -21,7 +25,7 @@ Dann kann es editierbar in ein virtuelles Environment installiert werden: Auf dem Raspberry Pi (oder wenn keine Code-Änderungen gewünscht sind) kann es auch direkt, ohne einen git-Clone installiert werden: ```sh -(venv)$ pip install git+git://git.graph-it.com/graphit/controlpi-.git +(venv)$ pip install git+git://git.graph-it.com/graphit/controlpi-readjson.git ``` ## Benutzung @@ -29,25 +33,26 @@ Eine minimale ControlPi-Konfiguration, die dieses Plugin benutzt, ist im git-Repository enthalten: ```json { - "Debug": { - "plugin": "WSServer", - "web": { - "/": { - "module": "controlpi_plugins.wsserver", - "location": "Debug" - } - } - }, "Log": { "plugin": "Log", "filter": [{}] }, - <...> + "SerialTest": { + "plugin": "ReadJSON", + "device": "/tmp/serialout" + } } ``` -<...> +Als weitere Schlüssel können in der Konfiguration `"baudrate"`, `"parity"` +und `"stopbits"` angegeben werden, wobei die Voreinstellungen `115200`, +`"none"` und `1` sind. -Mit dieser Beispiel-Konfiguration kann <...> in der Debug-Oberfläche des -ControlPi und im Log in `journalctl -u controlpi` gesehen werden: -![Debug-Oberfläche](graphit/controlpi-/DebugView.png) +Wir können das Plugin ohne serielle Hardware testen, in dem wir mit `socat` +eine virtuelle serielle Verbindung aufmachen: +```shell +$ socat -d -d pty,raw,echo=0,link=/tmp/serialin pty,raw,echo=0,link=/tmp/serialout +``` +Dann kann die Beispiel-Konfiguration von `/tmp/serialout` lesen und mit +`echo` Test-Nachrichten in `/tmp/serialin` geschrieben werden: +![Test mit virtuellem seriellen Device](graphit/controlpi-readjson/Test.png)