Amazon ALEXA Lists Exercise – Put’em on Paper…
4.5 Raspberry Pi print server
This is perhaps the most complicated step, I hope I didn’t forget anything important.
4.5.1 Hardware and OS setup
- Well, plug the SD card into your desktop computer and install noobs lite onto it. It’s as simple as formating with FAT and copying the NOOBS files onto the card.
- Then, plug in the sd card into the pi and wire it up with Screen, keyboard and PSU. It should start the booting process. This link covers setup in detail.
- After choosing a WIFI or wired network connection, install Raspbian Lite as only operating system; you don’t need the data partion for this project.
- This may take a while.
With the default user „pi“ and password „raspberry“, do a sudo apt-get update and a sudo apt-get upgrade . This also takes a while.
4.5.2 Install the USB printer
Connect the Thermal printer via USB to your pi and power it up. In my case, I’d now see the appropriate dmesg (less /var/log/messages ) output and a new device /dev/usb/lp0 – perfect.
While it’s possible to access the printer already as super user, we’d probably not want Apache’s www-data user to have su privileges all the time, or ever, so – more work.
- use udevadm info -a -p $(udevadm info -q path -n /dev/usb/lp0) to view the chain of devices leading to the last endpoint within the printer. This is very tricky, in my case it was this:
looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/usbmisc/lp0': KERNEL=="lp0" SUBSYSTEM=="usbmisc" DRIVER=="" looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0': KERNELS=="1-1.4:1.0" SUBSYSTEMS=="usb" DRIVERS=="usblp" ATTRS{authorized}=="1" ATTRS{bAlternateSetting}==" 0" ATTRS{bInterfaceClass}=="07" ATTRS{bInterfaceNumber}=="00" ATTRS{bInterfaceProtocol}=="02" ATTRS{bInterfaceSubClass}=="01" ATTRS{bNumEndpoints}=="02" ATTRS{ieee1284_id}=="" ATTRS{supports_autosuspend}=="1" looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4': KERNELS=="1-1.4" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="64" ATTRS{bMaxPower}=="100mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="0200" ATTRS{bmAttributes}=="c0" ATTRS{busnum}=="1" ATTRS{configuration}=="" ATTRS{devnum}=="5" ATTRS{devpath}=="1.4" ATTRS{idProduct}=="0808" ATTRS{idVendor}=="0456" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="Thermal Printer " ATTRS{maxchild}=="0" ATTRS{product}=="H58 Printer USB " ATTRS{quirks}=="0x0" ATTRS{removable}=="removable" ATTRS{serial}=="Printer" ATTRS{speed}=="12" ATTRS{urbnum}=="55" ATTRS{version}==" 2.00" [...]
- The very first item is the interesting endpoint, see the /…/lp0 at the end? We need an appropriate /etc/udev/rules.d udev rule. I named it /etc/udev/rules.d/98-hillpow.rules and it contains only one single line:
KERNEL=="lp0", SUBSYSTEM=="usbmisc",ATTRS{idVendor}=="0456",ATTRS{idProduct}=="0808",MODE="0664",GROUP="plugdev",SYMLINK+="listprinter%n"
This generates a symlink /dev/listprinter0 accessible for read/write operations to the plugdev group as soon as the printer is plugged in and powered on. Do note that the vendor and product attributes may vary and that the end point tree may be completely different in your model. Hence the udevadm command to find the exact tree structure.
- reload the udev rules with udevadm control –reload-rules && udevadm trigger .
Remove and replug your USB printer. There should be a symlink named /dev/listprinter0 with 664 access permissions. Voila.
4.5.3 Install PHP7 and Apache 2
This is trivial even to the layman, I’d recommend going with PHP 7 and not installing anything fancy:
- sudo apt-get install apache2 php7.0 libapache2-mod-php7.0
- When this is done, create an index.php file in /var/www/html with the content <?php phpinfo(); ?> .
- Now rename the index.html into index.html_ with sudo mv index.html index.html_ .
- Test PHP with a web browser by navigating to your print server’s host name or IP address. The large PHP info page should be displayed.
- Lastly, add the www-data user to to plugdev group with sudo usermod -a -G plugdev www-data
- Restart Apache with sudo service apache2 restart
4.5.4 Installing mike24’s lib
- Navigate to your html directory cd /var/www/html .
- Get Mike24’s excellent code from here: https://github.com/mike42/escpos-php by issuing git clone https://github.com/mike42/escpos-php vendor/mike42/escpos-php
4.5.5 Print Server PHP script
Last but not least, we need to create the internal_printer.php file in /var/www/html/ with the following code:
<?php require __DIR__ . '/vendor/mike42/escpos-php/autoload.php'; use Mike42\Escpos\PrintConnectors\FilePrintConnector; use Mike42\Escpos\Printer; // ***** FIND THE FIRST USB PRINTER $printers = scandir("/dev"); foreach ($printers as $printerDevice) { if (strpos($printerDevice, "listprinter")===false) continue; try { $connector = new FilePrintConnector("/dev/". $printerDevice); $printer = new Printer($connector); break; } catch (Exception $e) { header("HTTP/1.1 503 Service Unavailable"); $error = array( "statusCode"=>500, "statusText"=>"Thermal printer '$printerDevice' could not be accessed." ); echo json_encode($error); exit(1); } } if ($printer==null) { header("HTTP/1.1 503 Service Unavailable"); $error = array( "statusCode"=>500, "statusText"=>"No thermal printer connected." ); echo json_encode($error); exit(1); } // ***** INPUT SANITY CHECKING $listItems = json_decode($_REQUEST["listItems"]); if (!is_array($listItems) || count($listItems)<1 || count($listItems)>30) { header("HTTP/1.1 400 Bad Request"); $error = array( "statusCode"=>400, "statusText"=>"Please provide at least 1 and at best 30 list item(s) in request parameter named 'listItems' in form of a JSON UTF8 list." ); //var_dump($listItems); //var_dump($_REQUEST["listItems"]); echo json_encode($error); exit(1); } $listName = mb_strtoupper($_REQUEST["listName"]); // make a default if ($listName=="") { $listName = "UNBENANNTE LISTE"; } // truncate to 32 chars $listName = mb_substr($listName, 0, 32); // Set print mode to double height only if (mb_strlen($listName)<=16) { $printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT|Printer::MODE_DOUBLE_WIDTH); } else { $printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT); } // **** PRINT THE HEADER $printer -> setJustification(Printer::JUSTIFY_CENTER); $printer -> setEmphasis(true); $printer -> text($listName."\n"); $printer -> selectPrintMode(); // **** PRINT THE DIME (10.10.2017 16:43) //$printer -> setReverseColors(true); $printer -> text(date("---- d.m.Y ----- H:i ----\n")); $printer -> setReverseColors(false); $printer -> setEmphasis(false); $printer -> setJustification(Printer::JUSTIFY_LEFT); $printer -> feed(1); // **** PRINT THE LIST foreach($listItems as $item) { $item = "* ". ucwords(strtolower(mb_substr($item, 0, 30))) ."\n"; $printer -> text($item); } $printer -> feed(5); $printer -> cut(); $printer -> close(); $error = array( "statusCode"=>200, "statusText"=>"List '$listName' was printed successfully." ); echo json_encode($error); ?>
The code should be fairly self-explanatory, you don’t need to change anything here. In less detail, this is what happens:
- find the first printer and assume it has a line width of 32 characters
- make sure we have a list name (or default to UNBENANNT)
- make sure we have from 1 to 30 items
- for each item:
- truncate to 30 chars
- capitalise each word
- prepend with „*“
- print it
- return success
If you want to test the printer stand-alone, just call http://IP/internal_printer.php?listName=TEST&listItems=[„item 1“, „item 2“, „item 3“]
5 Kommentare zu “Amazon ALEXA Lists Exercise – Put’em on Paper…”
Hi,
great post.
Could please tell which thermal printer you have used?
The amazon link isnt‘ working anymore.
Thanks
hi, Thanks. The one I used isn’t available on Amazon anymore, but any USB receipt printer should work… Just look for what mike24’s ESC/POS library is supporting and buy one of those models… Best, Christoph
Thanks for the reply. This product list on github helps a lot.
One further question: Could you really delete the original shopping list with the skill? In your video you use the original „Einkaufsliste“ so you could also delete this one per API? In your code for the lambda it is „shopping list“ and not the original code snipped?
Danke und Gruß
Tom
hi, well, the Einkaufsliste is used by the ALEXA language model. it translates into „shopping list“ in the skill. Therefore the difference… Cheers.
Hello!
Nice work ! I try to integrate it to home assistant .
Your video link is dead could you update it please?
regards
Ben
Einen Kommentar hinterlassen