From 84b9ddcc2905f5d8667cfef1359b724c23d27365 Mon Sep 17 00:00:00 2001 From: xengineering Date: Thu, 29 Oct 2020 12:11:32 +0100 Subject: Setup basic Systemd Units --- Makefile | 27 +++++++++++++--------- README.md | 13 ++++++----- barcode_scanner_daemon.py | 43 ----------------------------------- barcode_transmit_daemon.py | 46 -------------------------------------- config.json | 6 ++--- iot-barcode-device-handler.service | 12 ++++++++++ iot-barcode.service | 14 ++++++++++++ iot_barcode/__init__.py | 0 iot_barcode/config.py | 24 ++++++++++++++++++++ iot_barcode/mqtt.py | 26 +++++++++++++++++++++ iot_barcode/static.py | 20 +++++++++++++++++ iot_barcode_daemon | 46 ++++++++++++++++++++++++++++++++++++++ iot_barcode_device_handler | 43 +++++++++++++++++++++++++++++++++++ iot_barcode_scanner/__init__.py | 5 ----- iot_barcode_scanner/config.py | 23 ------------------- iot_barcode_scanner/mqtt.py | 27 ---------------------- iot_barcode_scanner/static.py | 20 ----------------- 17 files changed, 212 insertions(+), 183 deletions(-) delete mode 100755 barcode_scanner_daemon.py delete mode 100755 barcode_transmit_daemon.py create mode 100644 iot-barcode-device-handler.service create mode 100644 iot-barcode.service create mode 100644 iot_barcode/__init__.py create mode 100644 iot_barcode/config.py create mode 100644 iot_barcode/mqtt.py create mode 100644 iot_barcode/static.py create mode 100755 iot_barcode_daemon create mode 100755 iot_barcode_device_handler delete mode 100644 iot_barcode_scanner/__init__.py delete mode 100644 iot_barcode_scanner/config.py delete mode 100644 iot_barcode_scanner/mqtt.py delete mode 100644 iot_barcode_scanner/static.py diff --git a/Makefile b/Makefile index 77c7fcf..895cb38 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -PKGNAME=iot_barcode_scanner +PKGNAME=iot_barcode PREFIX=/usr INSTALL=install INSTALL_PROGRAM=$(INSTALL) -m 755 @@ -8,8 +8,9 @@ INSTALL_DATA=$(INSTALL) -m 644 bindir=$(DESTDIR)$(PREFIX)/bin sharedir=$(DESTDIR)$(PREFIX)/share -confdir=$(DESTDIR)/etc/xengineering.eu/$(PKGNAME) +confdir=$(DESTDIR)/etc/$(PKGNAME) libdir=$(DESTDIR)$(PREFIX)/lib/python3/dist-packages/$(PKGNAME) +systemddir=$(DESTDIR)/lib/systemd/system .PHONY: install uninstall @@ -19,20 +20,24 @@ install: # install executables mkdir -p $(bindir) - $(INSTALL_PROGRAM) barcode_scanner_daemon.py $(bindir)/eu.xengineering.$(PKGNAME).scanner - $(INSTALL_PROGRAM) barcode_transmit_daemon.py $(bindir)/eu.xengineering.$(PKGNAME).transmitter + $(INSTALL_PROGRAM) iot_barcode_device_handler $(bindir)/ + $(INSTALL_PROGRAM) iot_barcode_daemon $(bindir)/ # install library / package mkdir -p $(libdir)/ - $(INSTALL_DATA) iot_barcode_scanner/__init__.py $(libdir)/__init__.py - $(INSTALL_DATA) iot_barcode_scanner/config.py $(libdir)/config.py - $(INSTALL_DATA) iot_barcode_scanner/mqtt.py $(libdir)/mqtt.py - $(INSTALL_DATA) iot_barcode_scanner/static.py $(libdir)/static.py + $(INSTALL_DATA) iot_barcode/__init__.py $(libdir)/__init__.py + $(INSTALL_DATA) iot_barcode/config.py $(libdir)/config.py + $(INSTALL_DATA) iot_barcode/mqtt.py $(libdir)/mqtt.py + $(INSTALL_DATA) iot_barcode/static.py $(libdir)/static.py # install config file mkdir -p $(confdir)/ $(INSTALL_DATA) config.json $(confdir)/config.json + # install systemd unit files + $(INSTALL_DATA) iot-barcode.service $(systemddir)/ + $(INSTALL_DATA) iot-barcode-device-handler.service $(systemddir)/ + # install license mkdir -p $(sharedir)/licenses/ $(INSTALL_DATA) LICENSE $(sharedir)/licenses/$(PKGNAME) @@ -40,10 +45,12 @@ install: uninstall: - rm -f $(bindir)/eu.xengineering.$(PKGNAME).scanner - rm -f $(bindir)/eu.xengineering.$(PKGNAME).transmitter + rm -f $(bindir)/iot_barcode_device_handler + rm -f $(bindir)/iot_barcode_daemon rm -f $(libdir)/__init__.py rm -f $(libdir)/config.py rm -f $(libdir)/mqtt.py rm -f $(libdir)/static.py + rm -f $(systemddir)/iot-barcode.service + rm -f $(systemddir)/iot-barcode-device-handler.service rm -f $(sharedir)/licenses/$(PKGNAME) diff --git a/README.md b/README.md index 97a5cc8..68b1235 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,12 @@ A service that makes barcode scanners available on the network for IoT use. git clone https://github.com/xengineering/iot-barcode-scanner.git cd iot-barcode-scanner sudo make install + sudo useradd -Urs /usr/bin/nologin iotbarcode ``` -2. Configure ```/etc/xengineering.eu/iot_barcode_scanner/config.json``` -3. Run ```sudo eu.xengineering.iot_barcode_scanner.scanner &``` -4. Run ```eu.xengineering.iot_barcode_scanner.transmitter &``` -5. Listen to MQTT output (e.g. with ```mosquitto_sub -h localhost -t "xengineering.eu/iot-barcode-scanner"```) +2. Configure ```/etc/iot_barcode/config.json``` +3. Run ```sudo systemctl enable --now iot-barcode-device-handler``` +4. Run ```sudo systemctl enable --now iot-barcode``` +5. Listen to MQTT output (e.g. with ```mosquitto_sub -h localhost -t "xengineering.eu/iot-barcode"```) ## Milestones @@ -27,10 +28,10 @@ A service that makes barcode scanners available on the network for IoT use. - [x] Disable scanner as regular input source and bind it only to the service - [x] Split into two executables to reduce root-priviledged code - [x] Write Makefile for easy installation +- [x] Implement systemd services +- [ ] Package it for Arch Linux - [ ] Make python package installation portable across linux distributions -- [ ] Implement systemd services - [ ] Implement auto discovery of barcode scanners -- [ ] Package it for Arch Linux ## Dependencies diff --git a/barcode_scanner_daemon.py b/barcode_scanner_daemon.py deleted file mode 100755 index 09139f7..0000000 --- a/barcode_scanner_daemon.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/python3 - - -"""Executable to read the Key Events from the Barcode Scanner (root Priviledges necessary)""" - - -import evdev -import os - -import iot_barcode_scanner.config as config - - -def main(): - - try: - # read config - cfg = config.get_config() - fifo_path = cfg["scanner"]["fifo_path"] - event_device_path = cfg["scanner"]["evdev_path"] - - # prepare fifo - os.makedirs(os.path.dirname(fifo_path), exist_ok=True) - os.mkfifo(fifo_path) - - barcode_scanner = evdev.InputDevice(event_device_path) - with barcode_scanner.grab_context(): - for event in barcode_scanner.read_loop(): - if event.type == evdev.ecodes.EV_KEY: - eventdata = evdev.categorize(event) - if eventdata.keystate: - with open(fifo_path, "w") as fifo: - fifo.write(eventdata.keycode) - fifo.flush() - - except KeyboardInterrupt: - pass - - finally: - os.remove(fifo_path) - - -if __name__ == "__main__": - main() diff --git a/barcode_transmit_daemon.py b/barcode_transmit_daemon.py deleted file mode 100755 index a2d7eb6..0000000 --- a/barcode_transmit_daemon.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/python3 - - -"""Executable to transmit the Barcode Data to MQTT without root Priviledges""" - - -from iot_barcode_scanner.static import KEYMAP -import iot_barcode_scanner.config as config -from iot_barcode_scanner.mqtt import MqttService - - -def main(): - try: - - # read config - cfg = config.get_config() - fifo_path = cfg["scanner"]["fifo_path"] - topic = cfg["mqtt"]["topic"] - - # setup mqtt - mqtt_service = MqttService(cfg) - mqtt_service.run() - - barcode = "" - - while True: - with open(fifo_path, "r") as fifo: - keycode = fifo.read() - character = KEYMAP[keycode] - if character is "\n": - mqtt_service.client.publish( - topic, - payload=barcode, - qos=0, - retain=False - ) - barcode = "" - else: - barcode += character - - except KeyboardInterrupt: - pass - - -if __name__ == "__main__": - main() diff --git a/config.json b/config.json index 223dbcf..9ee7179 100644 --- a/config.json +++ b/config.json @@ -2,10 +2,10 @@ "mqtt":{ "broker":"127.0.0.1", "port":1883, - "topic":"xengineering.eu/iot-barcode-scanner" + "topic":"xengineering.eu/iot-barcode" }, "scanner":{ - "evdev_path":"/dev/input/event4", - "fifo_path":"/tmp/xengineering.eu/iot-barcode-scanner/scanner_fifo" + "evdev_path":"/dev/input/event0", + "fifo_path":"/tmp/iot-barcode/scanner_fifo" } } diff --git a/iot-barcode-device-handler.service b/iot-barcode-device-handler.service new file mode 100644 index 0000000..8933cfd --- /dev/null +++ b/iot-barcode-device-handler.service @@ -0,0 +1,12 @@ + +[Unit] +Description=A Daemon to read Barcodes from a specified Barcode Reader + +[Service] +Type=simple +ExecStart=/usr/bin/iot_barcode_device_handler +User=root +Group=root + +[Install] +WantedBy=default.target diff --git a/iot-barcode.service b/iot-barcode.service new file mode 100644 index 0000000..fbd9940 --- /dev/null +++ b/iot-barcode.service @@ -0,0 +1,14 @@ + +[Unit] +Description=A Daemon to transmit Barcodes to an MQTT Broker +Requires=iot-barcode-device-handler.service +After=iot-barcode-device-handler.service + +[Service] +Type=simple +ExecStart=/usr/bin/iot_barcode_daemon +User=iotbarcode +Group=iotbarcode + +[Install] +WantedBy=default.target diff --git a/iot_barcode/__init__.py b/iot_barcode/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/iot_barcode/config.py b/iot_barcode/config.py new file mode 100644 index 0000000..7435f8b --- /dev/null +++ b/iot_barcode/config.py @@ -0,0 +1,24 @@ + + +"""Module to read the Configuration File for the Service""" + + +import sys +import json + +from iot_barcode.static import CONFIG_PATH + + +def get_config(): + """Read Config File and return it as Python Object""" + + try: + with open(CONFIG_PATH, "r") as config_file: + text = config_file.read() + except FileNotFoundError: + print("Config file does not exist.") + sys.exit(1) + + data = json.loads(text) + + return data diff --git a/iot_barcode/mqtt.py b/iot_barcode/mqtt.py new file mode 100644 index 0000000..2b0ece1 --- /dev/null +++ b/iot_barcode/mqtt.py @@ -0,0 +1,26 @@ + + +"""Provide MQTT Functionality for the Package""" + + +import paho.mqtt.client as mqtt + + +class MqttService(): + """Bundle for MQTT Functionality""" + + def __init__(self, config): + self.config = config + self.client = mqtt.Client() + self.client.on_connect = self.on_connect + + def run(self): + self.client.connect( + self.config["mqtt"]["broker"], + self.config["mqtt"]["port"], + 60 + ) + self.client.loop_start() + + def on_connect(self, client, userdata, flags, rc): + client.subscribe(self.config["mqtt"]["topic"]) diff --git a/iot_barcode/static.py b/iot_barcode/static.py new file mode 100644 index 0000000..638f017 --- /dev/null +++ b/iot_barcode/static.py @@ -0,0 +1,20 @@ + + +"""Module to store static Data for the whole Package""" + + +CONFIG_PATH = "/etc/iot_barcode/config.json" + +KEYMAP = { + "KEY_0": "0", + "KEY_1": "1", + "KEY_2": "2", + "KEY_3": "3", + "KEY_4": "4", + "KEY_5": "5", + "KEY_6": "6", + "KEY_7": "7", + "KEY_8": "8", + "KEY_9": "9", + "KEY_ENTER": "\n", +} diff --git a/iot_barcode_daemon b/iot_barcode_daemon new file mode 100755 index 0000000..5b08111 --- /dev/null +++ b/iot_barcode_daemon @@ -0,0 +1,46 @@ +#!/usr/bin/python3 + + +"""Executable to transmit the Barcode Data to MQTT without root Priviledges""" + + +from iot_barcode.static import KEYMAP +import iot_barcode.config as config +from iot_barcode.mqtt import MqttService + + +def main(): + try: + + # read config + cfg = config.get_config() + fifo_path = cfg["scanner"]["fifo_path"] + topic = cfg["mqtt"]["topic"] + + # setup mqtt + mqtt_service = MqttService(cfg) + mqtt_service.run() + + barcode = "" + + while True: + with open(fifo_path, "r") as fifo: + keycode = fifo.read() + character = KEYMAP[keycode] + if character is "\n": + mqtt_service.client.publish( + topic, + payload=barcode, + qos=0, + retain=False + ) + barcode = "" + else: + barcode += character + + except KeyboardInterrupt: + pass + + +if __name__ == "__main__": + main() diff --git a/iot_barcode_device_handler b/iot_barcode_device_handler new file mode 100755 index 0000000..5c05aab --- /dev/null +++ b/iot_barcode_device_handler @@ -0,0 +1,43 @@ +#!/usr/bin/python3 + + +"""Executable to read the Key Events from the Barcode Scanner (root Priviledges necessary)""" + + +import evdev +import os + +import iot_barcode.config as config + + +def main(): + + try: + # read config + cfg = config.get_config() + fifo_path = cfg["scanner"]["fifo_path"] + event_device_path = cfg["scanner"]["evdev_path"] + + # prepare fifo + os.makedirs(os.path.dirname(fifo_path), exist_ok=True) + os.mkfifo(fifo_path) + + barcode_scanner = evdev.InputDevice(event_device_path) + with barcode_scanner.grab_context(): + for event in barcode_scanner.read_loop(): + if event.type == evdev.ecodes.EV_KEY: + eventdata = evdev.categorize(event) + if eventdata.keystate: + with open(fifo_path, "w") as fifo: + fifo.write(eventdata.keycode) + fifo.flush() + + except KeyboardInterrupt: + pass + + finally: + os.remove(fifo_path) + + +if __name__ == "__main__": + main() diff --git a/iot_barcode_scanner/__init__.py b/iot_barcode_scanner/__init__.py deleted file mode 100644 index 6f92d9b..0000000 --- a/iot_barcode_scanner/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ - - -from iot_barcode_scanner.config import * -from iot_barcode_scanner.mqtt import * -from iot_barcode_scanner.static import * diff --git a/iot_barcode_scanner/config.py b/iot_barcode_scanner/config.py deleted file mode 100644 index 6b83393..0000000 --- a/iot_barcode_scanner/config.py +++ /dev/null @@ -1,23 +0,0 @@ - - -"""Module to read the Configuration File for the Service""" - - -import sys -import json -from iot_barcode_scanner.static import CONFIG_PATH - - -def get_config(): - """Read Config File and return it as Python Object""" - - try: - with open(CONFIG_PATH, "r") as config_file: - text = config_file.read() - except FileNotFoundError: - print("Config file does not exist.") - sys.exit(1) - - data = json.loads(text) - - return data diff --git a/iot_barcode_scanner/mqtt.py b/iot_barcode_scanner/mqtt.py deleted file mode 100644 index c5a075c..0000000 --- a/iot_barcode_scanner/mqtt.py +++ /dev/null @@ -1,27 +0,0 @@ - - -"""Provide MQTT Functionality for the Package""" - - -import paho.mqtt.client as mqtt - - -class MqttService(): - """Bundle for MQTT Functionality""" - - def __init__(self, config): - self.config = config - self.client = mqtt.Client() - self.client.on_connect = self.on_connect - - def run(self): - self.client.connect( - self.config["mqtt"]["broker"], - self.config["mqtt"]["port"], - 60 - ) - self.client.loop_start() - - def on_connect(self, client, userdata, flags, rc): - print("Connected with result code " + str(rc)) - client.subscribe(self.config["mqtt"]["topic"]) diff --git a/iot_barcode_scanner/static.py b/iot_barcode_scanner/static.py deleted file mode 100644 index af76683..0000000 --- a/iot_barcode_scanner/static.py +++ /dev/null @@ -1,20 +0,0 @@ - - -"""Module to store static Data for the whole Package""" - - -CONFIG_PATH = "/etc/xengineering.eu/iot_barcode_scanner/config.json" - -KEYMAP = { - "KEY_0": "0", - "KEY_1": "1", - "KEY_2": "2", - "KEY_3": "3", - "KEY_4": "4", - "KEY_5": "5", - "KEY_6": "6", - "KEY_7": "7", - "KEY_8": "8", - "KEY_9": "9", - "KEY_ENTER": "\n", -} -- cgit v1.2.3-70-g09d2