-"""ControlPi Plugin for <PURPOSE>."""
+"""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 <PURPOSE>."""
+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))
-# ControlPi-Plugin für <ZWECK>
-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
Der Code dieses Plugins kann mit git geclonet werden:
```sh
-$ git clone git://git.graph-it.com/graphit/controlpi-<NAME>.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.)
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-<NAME>.git
+(venv)$ pip install git+git://git.graph-it.com/graphit/controlpi-readjson.git
```
## Benutzung
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:
-
+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:
+