Add support for multiple serial devices

This commit is contained in:
Mike Phares 2022-06-30 09:20:13 -07:00
parent f6c206e0b1
commit 87e337a69d
8 changed files with 85 additions and 23 deletions

View File

@ -24,7 +24,8 @@ barcode_server:
# (optional) Serial push configuration
serial:
# URL to send events to using a request
path: "/dev/ttyUSB0"
pathA: "/dev/ttyUSB0"
pathB: "/dev/ttyUSB1"
# (optional) file push configuration
file:
@ -62,7 +63,7 @@ barcode_server:
# A list of regex patterns to match USB device names against
devices:
- ".*Barcode.*"
- ".*ode.*"
# A list of absolute file paths to devices
device_paths:
#- "/dev/input/barcode_scanner"

View File

@ -50,7 +50,7 @@ def c_run():
"""
from barcode_server.barcode import BarcodeReader
from barcode_server.config import AppConfig
from barcode_server.webserver import Webserver
from barcode_server.webserver import WebServer
signal.signal(signal.SIGINT, signal_handler)
@ -64,7 +64,7 @@ def c_run():
LOGGER.info(f"Instance ID: {config.INSTANCE_ID.value}")
barcode_reader = BarcodeReader(config)
webserver = Webserver(config, barcode_reader)
webserver = WebServer(config, barcode_reader)
# start prometheus server
if config.STATS_PORT.value is not None:

View File

@ -213,11 +213,20 @@ class AppConfig(ConfigBase):
required=True
)
SERIAL_PATH = StringConfigEntry(
SERIAL_PATH_A = StringConfigEntry(
key_path=[
CONFIG_NODE_ROOT,
CONFIG_NODE_SERIAL,
"path"
"pathA"
],
required=False
)
SERIAL_PATH_B = StringConfigEntry(
key_path=[
CONFIG_NODE_ROOT,
CONFIG_NODE_SERIAL,
"pathB"
],
required=False
)

View File

@ -1,11 +1,14 @@
import os
import logging
# import time as sleep
from pathlib import Path
from datetime import datetime
from prometheus_async.aio import time
from barcode_server.barcode import BarcodeEvent
from barcode_server.notifier import BarcodeNotifier
from barcode_server.stats import FILE_NOTIFIER_TIME
from barcode_server.util import barcode_event_to_json
LOGGER = logging.getLogger(__name__)
@ -13,8 +16,45 @@ class FileNotifier(BarcodeNotifier):
def __init__(self, path: str):
super().__init__()
self.inputDevicePathA = None
self.inputDevicePathB = None
self.path = path
pathObject = Path(path)
if not pathObject.exists():
pathObject.mkdir(exist_ok=True)
# def ticks(dt):
# return (dt - datetime(1, 1, 1)).total_seconds() * 10000000
@time(FILE_NOTIFIER_TIME)
async def _send_event(self, event: BarcodeEvent):
LOGGER.debug(f"Notified {self.path}: {event.barcode}")
now = datetime.now()
date_time = now.strftime("%Y-%m-%d")
weekNumberOfYear = now.strftime("%Y_Week_%U")
if self.inputDevicePathA is None:
self.inputDevicePathA = event.input_device.path
elif self.inputDevicePathB is None:
self.inputDevicePathB = event.input_device.path
weekPath = f"{self.path}/{weekNumberOfYear}"
dateTimePath = f"{weekPath}/{date_time}"
if event.input_device.path == self.inputDevicePathA:
fullPath = f"{dateTimePath}/A"
elif event.input_device.path == self.inputDevicePathB:
fullPath = f"{dateTimePath}/B"
else:
fullPath = f"{dateTimePath}/Z"
json = barcode_event_to_json(self.config.INSTANCE_ID.value, event)
ticks = int((datetime.utcnow() - datetime(1, 1, 1)).total_seconds() * 10000000)
pathObject = Path(weekPath)
if not pathObject.exists():
pathObject.mkdir(exist_ok=True)
pathObject = Path(dateTimePath)
if not pathObject.exists():
pathObject.mkdir(exist_ok=True)
pathObject = Path(fullPath)
if not pathObject.exists():
pathObject.mkdir(exist_ok=True)
f = open(f"{fullPath}/{str(ticks)}.json", 'wb')
f.write(json)
f.close()
LOGGER.debug(f"Notified {fullPath}: {event.barcode}")

View File

@ -1,6 +1,5 @@
import serial
import logging
# import time as sleep
from prometheus_async.aio import time
@ -12,12 +11,25 @@ LOGGER = logging.getLogger(__name__)
class SerialNotifier(BarcodeNotifier):
def __init__(self, path: str, usb: serial):
def __init__(self, pathA: str, pathB: str):
super().__init__()
self.path = path
self.usb = usb
self.pathA = pathA
self.pathB = pathB
self.inputDevicePathA = None
self.inputDevicePathB = None
self.usbA = serial.Serial(pathA, 9600, timeout=2)
if pathB is not None:
self.usbB = serial.Serial(pathB, 9600, timeout=2)
@time(SERIAL_NOTIFIER_TIME)
async def _send_event(self, event: BarcodeEvent):
self.usb.write(event.barcode.encode())
LOGGER.debug(f"Notified {self.path}: {event.barcode}")
if self.inputDevicePathA is None:
self.inputDevicePathA = event.input_device.path
elif self.inputDevicePathB is None:
self.inputDevicePathB = event.input_device.path
if event.input_device.path == self.inputDevicePathA:
self.usbA.write(event.barcode.encode())
LOGGER.debug(f"Notified {self.pathA}: {self.inputDevicePathA}: {event.barcode}")
elif event.input_device.path == self.inputDevicePathB:
self.usbB.write(event.barcode.encode())
LOGGER.debug(f"Notified {self.pathB}: {self.inputDevicePathB}: {event.barcode}")

View File

@ -27,3 +27,4 @@ WEBSOCKET_NOTIFIER_TIME = NOTIFIER_TIME.labels(type='websocket')
HTTP_NOTIFIER_TIME = NOTIFIER_TIME.labels(type='http')
SERIAL_NOTIFIER_TIME = NOTIFIER_TIME.labels(type='serial')
MQTT_NOTIFIER_TIME = NOTIFIER_TIME.labels(type='mqtt')
FILE_NOTIFIER_TIME = NOTIFIER_TIME.labels(type='file')

View File

@ -15,6 +15,7 @@ from barcode_server.notifier import BarcodeNotifier
from barcode_server.notifier.http import HttpNotifier
from barcode_server.notifier.mqtt import MQTTNotifier
from barcode_server.notifier.serial import SerialNotifier
from barcode_server.notifier.file import FileNotifier
from barcode_server.notifier.ws import WebsocketNotifier
from barcode_server.stats import REST_TIME_DEVICES, WEBSOCKET_CLIENT_COUNT
from barcode_server.util import input_device_to_dict
@ -23,7 +24,7 @@ LOGGER = logging.getLogger(__name__)
routes = web.RouteTableDef()
class Webserver:
class WebServer:
def __init__(self, config: AppConfig, barcode_reader: BarcodeReader):
self.config = config
@ -35,9 +36,8 @@ class Webserver:
self.barcode_reader = barcode_reader
self.barcode_reader.add_listener(self.on_barcode)
self.usb = {}
self.notifiers: Dict[str, BarcodeNotifier] = {}
if config.HTTP_URL.value is not None:
http_notifier = HttpNotifier(
config.HTTP_METHOD.value,
@ -58,13 +58,12 @@ class Webserver:
)
self.notifiers["mqtt"] = mqtt_notifier
if config.SERIAL_PATH.value is not None:
self.usb = serial.Serial(config.SERIAL_PATH.value, 9600, timeout=2)
serial_notifier = SerialNotifier(config.SERIAL_PATH.value, self.usb)
if config.SERIAL_PATH_A.value is not None:
serial_notifier = SerialNotifier(config.SERIAL_PATH_A.value, config.SERIAL_PATH_B.value)
self.notifiers["serial"] = serial_notifier
if config.FILE_PATH.value is not None:
file_notifier = SerialNotifier(config.FILE_PATH.value)
file_notifier = FileNotifier(config.FILE_PATH.value)
self.notifiers["file"] = file_notifier
async def start(self):

View File

@ -8,7 +8,7 @@ from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from barcode_server import const
from barcode_server.barcode import BarcodeEvent
from barcode_server.util import barcode_event_to_json
from barcode_server.webserver import Webserver
from barcode_server.webserver import WebServer
def create_barcode_event_mock(barcode: str = None):
@ -46,7 +46,7 @@ class WebsocketNotifierTest(AioHTTPTestCase):
Override the get_app method to return your application.
"""
barcode_reader = MagicMock()
self.webserver = Webserver(self.config, barcode_reader)
self.webserver = WebServer(self.config, barcode_reader)
app = self.webserver.create_app()
runner = aiohttp.web.AppRunner(app)
await runner.setup()