Skip to content
Snippets Groups Projects
Verified Commit 61401a1a authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Develop kort-client

parent a36b40f7
No related branches found
No related tags found
No related merge requests found
SUBSYSTEM=="usb", ATTRS{idVendor}=="0f49", ATTRS{idProduct}=="0b00", MODE="0664", GROUP="dialout"
......@@ -24,6 +24,7 @@ class KortAPI:
"printer": "app/kort/api/v1/printers/",
"next_job": "app/kort/api/v1/printers/{}/jobs/next/",
"job_status": "app/kort/api/v1/jobs/{}/status/",
"chip_number": "app/kort/api/v1/jobs/{}/chip_number/",
}
def __init__(self):
......@@ -54,6 +55,11 @@ class KortAPI:
r = self._do_request("PUT", "job_status", [job_id], data=data)
return r
def set_chip_number(self, job_id: int, chip_number: str) -> dict[str, Any]:
data = {"chip_number": chip_number}
r = self._do_request("PUT", "chip_number", [job_id], data=data)
return r
def set_printer_status(
self, printer_id: int, status: str, status_text: str = None
) -> dict[str, Any]:
......
import os
import subprocess # noqa
from .usb_barcode_scanner.scanner import BarcodeReader
class CardDetector:
id_ = None
def read_id(self):
raise NotImplementedError()
def abort(self):
pass
def clear(self):
pass
@classmethod
def get_id(cls):
if not cls.id_:
raise NotImplementedError()
return cls.id_
@classmethod
def get_card_detectors(cls):
card_detectors = cls.__subclasses__()
return {d.get_id(): d() for d in card_detectors}
class EvolisCardDetector(CardDetector):
"""This is a card detector for Evolis card printers like Evolis Primacy.
To use it, you have to get the evocom tool from the Evolis customer support.
Then place it at /opt/evocom/evocom.
"""
id_ = "evolis_evocom"
EVOCOM_PATH = "/opt/evocom/evocom"
def get_detector(self):
from kort_client.run import KortClientException
files = []
for __, __, files in os.walk("/dev/"):
files = files
break
files = {f for f in files if f.startswith("hidraw")}
possible_interfaces = []
for hid_interface in list(files):
path_to_read = f"/sys/class/hidraw/{hid_interface}/device/uevent"
with open(path_to_read) as f:
content = f.read()
if "rfid" in content.lower():
possible_interfaces.append(hid_interface)
if len(possible_interfaces) != 1:
raise KortClientException("No or more than one reader found")
return os.path.join("/dev", possible_interfaces[0])
def get_printer(self):
from kort_client.run import KortClientException
files = []
for __, __, files in os.walk("/dev/usb/"):
files += files
files = {f for f in files if f.startswith("lp")}
if len(files) != 1:
raise KortClientException("No or more than one printer found")
suffix = list(files)[0]
return f"/dev/usb/{suffix}"
def read_id(self):
from kort_client.run import KortClientException
reader = BarcodeReader(self.get_detector())
# Transport the card to the printer
try:
r = subprocess.run( # noqa
[self.EVOCOM_PATH, "-p", self.get_printer(), "Sis"]
)
except (subprocess.CalledProcessError, OSError) as e:
raise KortClientException(e)
# Read the card
chip_number = reader.read_barcode()
try:
r.check_returncode()
except (subprocess.CalledProcessError, OSError) as e:
raise KortClientException(e)
return chip_number
def clear(self):
subprocess.run([self.EVOCOM_PATH, "-p", self.get_printer(), "Ser"]) # noqa
def abort(self):
self.clear()
......@@ -7,6 +7,7 @@ import cups
import requests
from kort_client.api import KortAPIException
from kort_client.card_detectors import CardDetector
class KortClientException(Exception):
......@@ -22,6 +23,9 @@ class PrintClient:
self.api = api
self.printer_id = None
self.conn = cups.Connection()
self.card_detectors = CardDetector.get_card_detectors()
self.card_detector = None
self.card_detector_in_process = False
def run(self):
try:
......@@ -35,6 +39,8 @@ class PrintClient:
"An error occured, try again in five seconds: {}".format(e),
fg="red",
)
if self.card_detector_in_process and self.card_detector:
self.card_detector.abort()
else:
printer_status = "online"
status_text = ""
......@@ -56,6 +62,8 @@ class PrintClient:
self.api.set_printer_status(
self.printer_id, "offline", "Printer client was stopped by user."
)
if self.card_detector and self.card_detector_in_process:
self.card_detector.abort()
raise
def _validate_printer(self):
......@@ -77,6 +85,13 @@ class PrintClient:
self._validate_printer()
self.card_detector = self.card_detectors.get(
self.printer_config["card_detector"], None
)
self.card_detector_in_process = False
if self.card_detector:
self.card_detector.clear()
next_job = self.api.get_next_job(self.printer_id)
print(next_job)
......@@ -84,9 +99,24 @@ class PrintClient:
job_id = next_job["id"]
click.secho("Got new print job {}".format(next_job), fg="green")
self.api.set_job_status(
job_id,
"in_progress",
)
if not self.printer_config.get("generate_number_on_server"):
# Now do something to set the number, but irrelevant for this example
pass
click.secho("Generate number on server disabled", fg="yellow")
if self.card_detector:
self.card_detector_in_process = True
chip_number = self.card_detector.read_id()
if chip_number:
next_job = self.api.set_chip_number(job_id, str(chip_number))
time.sleep(1)
else:
raise KortClientException("No valid chip number read")
else:
raise KortClientException("No card detector configured")
if next_job["card"]["chip_number"]:
# Download PDF file
......
#!/usr/bin/python
# Inspired by https://www.piddlerintheroot.com/barcode-scanner/
# https://www.raspberrypi.org/forums/viewtopic.php?f=45&t=55100
# from 'brechmos' - thank-you!
CHARMAP_LOWERCASE = {
4: "a",
5: "b",
6: "c",
7: "d",
8: "e",
9: "f",
10: "g",
11: "h",
12: "i",
13: "j",
14: "k",
15: "l",
16: "m",
17: "n",
18: "o",
19: "p",
20: "q",
21: "r",
22: "s",
23: "t",
24: "u",
25: "v",
26: "w",
27: "x",
28: "y",
29: "z",
30: "1",
31: "2",
32: "3",
33: "4",
34: "5",
35: "6",
36: "7",
37: "8",
38: "9",
39: "0",
44: " ",
45: "-",
46: "=",
47: "[",
48: "]",
49: "\\",
51: ";",
52: "'",
53: "~",
54: ",",
55: ".",
56: "/",
}
CHARMAP_UPPERCASE = {
4: "A",
5: "B",
6: "C",
7: "D",
8: "E",
9: "F",
10: "G",
11: "H",
12: "I",
13: "J",
14: "K",
15: "L",
16: "M",
17: "N",
18: "O",
19: "P",
20: "Q",
21: "R",
22: "S",
23: "T",
24: "U",
25: "V",
26: "W",
27: "X",
28: "Y",
29: "Z",
30: "!",
31: "@",
32: "#",
33: "$",
34: "%",
35: "^",
36: "&",
37: "*",
38: "(",
39: ")",
44: " ",
45: "_",
46: "+",
47: "{",
48: "}",
49: "|",
51: ":",
52: '"',
53: "~",
54: "<",
55: ">",
56: "?",
}
CR_CHAR = 40
SHIFT_CHAR = 2
ERROR_CHARACTER = "?"
class BarcodeReader:
def __init__(self, device_path="/dev/hidraw0"):
self.device_path = device_path
self.f = open(self.device_path, "rb")
def read_barcode(self):
barcode_string_output = ""
# barcode can have a 'shift' character; this switches the character set
# from the lower to upper case variant for the next character only.
CHARMAP = CHARMAP_LOWERCASE
while True:
# step through returned character codes, ignore zeroes
for char_code in [element for element in self.f.read(8) if element > 0]:
if char_code == CR_CHAR:
# all barcodes end with a carriage return
self.f.close()
return barcode_string_output
if char_code == SHIFT_CHAR:
# use uppercase character set next time
CHARMAP = CHARMAP_UPPERCASE
else:
# if the charcode isn't recognized, use ?
barcode_string_output += CHARMAP.get(char_code, ERROR_CHARACTER)
# reset to lowercase character map
CHARMAP = CHARMAP_LOWERCASE
def barcode_reader(dev="/dev/hidraw0"):
barcode_string_output = ""
# barcode can have a 'shift' character; this switches the character set
# from the lower to upper case variant for the next character only.
CHARMAP = CHARMAP_LOWERCASE
with open(dev, "rb") as fp:
while True:
# step through returned character codes, ignore zeroes
for char_code in [element for element in fp.read(8) if element > 0]:
if char_code == CR_CHAR:
# all barcodes end with a carriage return
return barcode_string_output
if char_code == SHIFT_CHAR:
# use uppercase character set next time
CHARMAP = CHARMAP_UPPERCASE
else:
# if the charcode isn't recognized, use ?
barcode_string_output += CHARMAP.get(char_code, ERROR_CHARACTER)
# reset to lowercase character map
CHARMAP = CHARMAP_LOWERCASE
#!/bin/bash
FILES=/dev/hidraw*
for f in $FILES
do
FILE=${f##*/}
DEVICE="$(cat /sys/class/hidraw/${FILE}/device/uevent | grep HID_NAME | cut -d '=' -f2)"
printf "%s \t %s\n" $FILE "$DEVICE"
done
\ No newline at end of file
......@@ -16,6 +16,7 @@ usersettings = "^1.1.5"
requests = "^2.27.1"
requests-oauthlib = "^1.3.1"
pycups = "^2.0.1"
usb-barcode-scanner-julz = "^0.2"
[tool.poetry.dev-dependencies]
safety = "^1.8.5"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment