diff --git a/.dockerignore b/.dockerignore index eaf6ab3..d69f7c6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -29,6 +29,13 @@ web/tmp/** __pycache__/** __pycache__ -# Remove test scripts +# Remove test scripts and test files tests/** -tests \ No newline at end of file +tests +barcodes.bin +receipt-with-logo.bin +receipt-with-qrcode.bin + +# Remove pybabel config and translation scripts from the runtime container +babel.cfg +*_babel_*.sh \ No newline at end of file diff --git a/README.md b/README.md index 6179e6e..218f465 100644 --- a/README.md +++ b/README.md @@ -10,35 +10,119 @@ The printer emulates a 80mm roll of paper. ## Limits This docker image is not to be exposed on a public network (see [known issues](#known-issues)) -A print cannot last longer than 10 seconds. This timeout could be changed at some point, or made configurable. +A print cannot last longer than 10 seconds. This timeout could be changed in the code, or made configurable at some later point. ## Quick start This project requires: - A Docker installation (kubernetes should work, but is untested.) -To install v3.0 from source: +### Use the prebuilt container +A prebuilt container of this project is avaliable on [Docker Hub](https://hub.docker.com/repository/docker/gilbertfl/escpos-netprinter). + +To run the prebuilt container: ```bash -wget --show-progress https://github.com/gilbertfl/escpos-netprinter/archive/refs/tags/3.0.zip -unzip 3.0.zip -cd escpos-netprinter-3.0 -docker build -t escpos-netprinter:3.0 . +docker run -d \ + -p 515:515/tcp \ + -p 80:80/tcp \ + -p 9100:9100/tcp \ + --mount source=receiptVolume,target=/home/escpos-emu/web \ + gilbertfl/escpos-netprinter:3.2 +``` +### Once started +Once started, the container will accept prints by JetDirect on the default port(9100) and by lpd on the default port(515). You can access all received receipts with the web application at port 80. + +The receipts are kept on a docker volume, so they will be kept if the container is restarted. To make the prints temporary, simply remove the `--mount` line from the run command. + +Version 3.2 is capable of dealing with all status requests from POS systems as described in the Epson APG. + +## Working on the code + +### Building from source + +To install v3.2 from source: + +```bash +wget --show-progress https://github.com/gilbertfl/escpos-netprinter/archive/refs/tags/3.2.zip +unzip 3.2.zip +cd escpos-netprinter-3.2 +docker build -t escpos-netprinter:3.2 . ``` To run the resulting container: ```bash -docker run -d --rm --name escpos_netprinter -p 515:515/tcp -p 80:80/tcp -p 9100:9100/tcp escpos-netprinter:3.0 +docker run -d \ + -p 515:515/tcp \ + -p 80:80/tcp \ + -p 9100:9100/tcp \ + --mount source=receiptVolume,target=/home/escpos-emu/web \ + escpos-netprinter:3.2 +``` + +### Debugging +Two interfaces have been made avaliable to help debugging. + +There is also a general environment flag that make the Docker logs verbose: set ```ESCPOS_DEBUG=True``` (case-sensitive) +```bash +docker run -d \ + -p 515:515/tcp \ + -p 80:80/tcp \ + -p 9100:9100/tcp \ + --mount source=receiptVolume,target=/home/escpos-emu/web \ + --env ESCPOS_DEBUG=True \ + escpos-netprinter:3.2 +``` +Setting this variable will generate logs from 3 different sources: +- The CUPS printer driver +- Jetdirect requests +- The ESC/POS to HTML conversion itself +- Browsing the web interface + +If you have problems with the CUPS interface, you can add port 631 to access the CUPS administrator interface. The CUPS administrative username is `cupsadmin` and the password is `123456`; you can change that in the dockerfile or at runtime inside the administrator interface. +```bash +docker run -d \ + -p 515:515/tcp \ + -p 80:80/tcp \ + -p 9100:9100/tcp \ + -p 631:631/tcp + --mount source=receiptVolume,target=/home/escpos-emu/web \ + escpos-netprinter:3.2 ``` -It should now accept prints by JetDirect on the default port(9100) and by lpd on the default port(515), and you can visualize it with the web application at port 80. -For debugging, you can add port 631 to access the CUPS interface. The CUPS administrative username is `cupsadmin` and the password is `123456`. -As of version 2.0, this has been tested to work with a regular POS program without adapting it. +### Runtime Directory Structure + +The following directories inside the container are useful: +- `/home/escpos-emu/web/`: Stores all the printed receipts and printer state (including logs) +- `/home/escpos-emu/web/receipts`: Stores the HTML receipts +- `/home/escpos-emu/web/tmp`: Stores temporary files during processing (for debugging only) +- `/home/escpos-emu/web/receipt_list.csv`: Created at runtime, this file contains the list of the printed receipts with the file location. + +## Translations + +This project supports internationalization using [Flask-Babel](https://python-babel.github.io/flask-babel). All translation files are in the `/translations` subdirectory, including the `messages.pot` file. + +You can create a new locale using the following scripts: +- `init_babel_locale.sh`: to create a new locale file NOTE: you will need to add the locale in `babel_config.py` manually after this. +- `compile_babel_translations.sh`: to compile all locales and make them available to Flask. This should be launched after every change to the translations, not immediately after creating a locale. + +Other helpful scripts for developers : +- `update_babel_messages.sh`: If you add more translatable text in the UI or code, use this script to make Babel extract and add them to the locale files +- `extract_babel_messages.sh`: If you ever want to generate the `messages.pot` file without updating any locale, this is the script. + +## Configuration Options -Version 3.0 is now dealing with all status requests from POS systems as described in the Epson APG. +The following environment variables can be configured: +| Variable | Default | Description | +|----------|---------|-------------| +| ESCPOS_DEBUG | false | Enable debug mode for detailed logs | +| PRINTER_PORT | 9100 | JetDirect port for printer communication | +| FLASK_RUN_DEBUG | false | Enable Flask debug mode | +| FLASK_RUN_PORT | 80 | Sets the listening port for the web interface | +| ESCPOS_TIMEZONE | "America/Montreal" | Sets the timezone for all datetime formatting | ## Known issues -While version 3.0 is no longer a beta version, it has known defects: +While version 3.2 is ready for production, it has known defects: - It still uses the Flask development server, so it is unsafe for public networks. - While it works with simple drivers, for example the one for the MUNBYN ITPP047 printers, the [Epson utilities](https://download.epson-biz.com/modules/pos/) refuse to speak to it. diff --git a/babel.cfg b/babel.cfg new file mode 100644 index 0000000..a76950c --- /dev/null +++ b/babel.cfg @@ -0,0 +1,2 @@ +[python: ./*.py] +[jinja2: templates/**.html.j2] \ No newline at end of file diff --git a/babel_config.py b/babel_config.py new file mode 100644 index 0000000..1c029ac --- /dev/null +++ b/babel_config.py @@ -0,0 +1,4 @@ +# This is the flask-babel runtime config file + +class Config: + LANGUAGES = ['fr', 'en'] \ No newline at end of file diff --git a/barcodes.bin b/barcodes.bin new file mode 100644 index 0000000..6342322 --- /dev/null +++ b/barcodes.bin @@ -0,0 +1,21 @@ +@ +.ta!8Code128: +Hh-kI012z !., +.ta!8Code93: +Hh-kH012.ABZ +.ta!8Codabar: +Hh-kGA012$+-./:A +.ta!8Code39: +Hh-kEABCZ012 +.ta!8Ean8: +Hh-kD0123456 +.ta!8Ean13: +Hh-kC012345678901 +.ta!8UpcE: +Hh-kB1234567 +.ta!8UpcA: +Hh-kA036000291452 +.ta!8ITF: +Hh-kF +0123456789 +d \ No newline at end of file diff --git a/compile_babel_translations.sh b/compile_babel_translations.sh new file mode 100755 index 0000000..1ea05da --- /dev/null +++ b/compile_babel_translations.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# This script compiles all locales and makes them usable by Python. + +pybabel compile -d translations \ No newline at end of file diff --git a/composer.json b/composer.json index 3c22314..7bb88e4 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,8 @@ "squizlabs/php_codesniffer" : "^2.8", "mike42/escpos-php": "^1.5", "chillerlan/php-qrcode": "^5.0.3", - "zbateson/mb-wrapper": "2.0.1" + "zbateson/mb-wrapper": "2.0.1", + "picqer/php-barcode-generator": "^3.2" }, "autoload" : { "psr-4" : { diff --git a/doc/esc2html.md b/doc/esc2html.md index 3dd09aa..6390eab 100644 --- a/doc/esc2html.md +++ b/doc/esc2html.md @@ -14,12 +14,21 @@ This utility is included with escpos-tools. See the ## Usage +Basic usage: ``` php esc2html FILE ``` +Optional debugging: +``` +php esc2html --debug FILE +``` +In the debug mode, the debugging messages are sent to the debug console while the output is the same as in basic mode. + + ## Example +### Basic example ``` $ php esc2html.php receipt-with-logo.bin > receipt-with-logo.html ``` @@ -38,6 +47,15 @@ $ cat receipt-with-logo.bin > /dev/usb/lp0 The input file used as an example here was generated by [escpos-php](https://github.com/mike42/escpos-php), and is available [here](https://raw.githubusercontent.com/receipt-print-hq/escpos-tools/master/receipt-with-logo.bin). +### Saving debugging output separately from the real output + +``` +$ php esc2html.php receipt-with-qrcode.bin 1>test.html 2>log.txt +``` + +The HTML representation of the receipt is saved to test.html, and the debugging output to log.txt. + + ## Further conversions This utility will create a formatted HTML file. This can be converted accurately to PDF diff --git a/dockerfile b/dockerfile index 3ae81d7..204bb85 100644 --- a/dockerfile +++ b/dockerfile @@ -12,6 +12,7 @@ RUN install-php-extensions mbstring @composer imagick #Install Flask RUN apt-get update RUN apt-get install -y python3-flask +RUN apt-get install -y python3-flask-babel RUN apt-get install -y python3-lxml #Install CUPS @@ -54,6 +55,11 @@ ENV FLASK_RUN_DEBUG=false # To activate the netprinter debug mode, set at True (case-sensitive) ENV ESCPOS_DEBUG=false +#Localization support environment variables +ENV ESCPOS_TIMEZONE="America/Montreal" + + +# Expose all necessary ports EXPOSE ${PRINTER_PORT} EXPOSE ${FLASK_RUN_PORT} #Expose the lpd port diff --git a/esc2html.php b/esc2html.php index 1879f8d..3b9c9c4 100644 --- a/esc2html.php +++ b/esc2html.php @@ -18,7 +18,7 @@ exit(1); } else { - if ($argv[1]=='--debug'){ + if ($argv[1]=='--debug'){ $debugMode = true; if (!isset($argv[2])) { print("Usage: php " . $argv[0] . " [--debug] filename ". $argc-1 . " arguments received\n"); @@ -46,7 +46,7 @@ if ( !$fp ) { error_log("File ". $targetFilename . "not found."); exit(1); -} +} $parser = new Parser(); $parser -> addFile($fp); @@ -60,6 +60,9 @@ $imgNo = 0; $skipLineBreak = false; $code2dStorage = new Code2DStateStorage(); +$barcodeHeight = null; +$barcodeWidth = null; +$barcodeHri = null; foreach ($commands as $cmd) { if ($debugMode) error_log("". get_class($cmd) ."", 0); //Output the command class in the debug console @@ -121,7 +124,7 @@ error_log("Data size:". $sub->getDataSize() ."",0); error_log("Data: " . $sub->get_data() ."",0); } - if($sub->isAvailableAs('QRCodeSubCommand')){ + if($sub->isAvailableAs('QRCodeSubCommand')){ switch ($sub->get_fn()) { case 65: //set model $code2dStorage->setQRModel($sub->get_data()); @@ -158,13 +161,83 @@ $qrcodeData = $code2dStorage->getQRCodeData(); $outp[] = "