Setting up CUPS with LPR on Raspbian

without comments

With CUPS you can easily set up a Raspberry Pi as print-server. Out of the box client can connect to CUPS over IPP (Wiki – Internet Printing Protocol). However, on Windows machines this have unwanted side-effects whenever the server is turned off: everytime I opened a document in LibreOffice the program froze for more than a minute. This is due to the Windows Spooler searching for the print-server until a time-out occurs. This behavior can be avoided by using the LPR protocol (Wiki – Line Printer Daemon protocol). In the following I will describe the necessary steps for this setup.

I tried this on a Raspberry Pi 1 running Raspbian Jessie Lite (2016-11-25).

Step 1

First you’ll have to install CUPS. For LPR to work you’ll also need xinetd. And I also needed splix as it contains the driver for my printer (Samsung ML-2010PR).

sudo apt-get install -y splix cups xinetd
sudo cupsctl --share-printers --remote-admin
sudo usermod -a -G lpadmin pi

The second commands enables printer-sharing and the CUPS web-interface. The last command allows the user pi to change the settings for CUPS.

Step 2

To enable LPR you’ll have to configure xinetd. Create a new config file named cups-lpd in /etc/xinetd.d:

sudo nano /etc/xinetd.d/cups-lpd

Paste the following configuration into the file:

service printer
        socket_type = stream
        protocol = tcp
        wait = no
        user = lp
        server = /usr/lib/cups/daemon/cups-lpd
        server_args = -o document-format=application/octet-stream -o job-sheets=none,none
        disable = no

Then restart xinetd:

sudo /etc/init.d/xinetd restart

Step 3 and Finish

Now add your printer through the CUPS web-interface. It can by found at https://YOUR-IP:631/admin and use the credentials for the standard user pi. Make sure you enable network sharing. Then you can add the printer on the clients. For Windows you have to add a Generic Network Interface. Make sure to set the queue name to the one you chose in the web-interface. Also, you have to enable LPR Byte Counting or it will not work!

Written by Ferdinand

Januar 15th, 2017 at 15:56

Read-only Filesystem for Raspberry Pi

without comments

I recently set up a Raspberry Pi as a print- and scan-server. I want to be able to just turn off the Raspberry Pi without a proper shutdown, so to prevent SD-card corruption a read-only filesystem was needed. The easy way to implement this is to just mount the root filesystem as read-only. An unwanted side-effect of this is that all writes to the filesystem fail. The superior solution uses a read-only root with an overlay stored in RAM. Luckily ejolson on the Raspberry Pi forum has written a nice tutorial to implement this.

I successfully configured Raspbian Jessie Lite (2016-11-25) running on a Raspberry Pi 1. I have not tested it with any other Pi, but they should work just as well. If you try this tutorial with a more recent Raspbian version it might not work!

Step 1

Change into a root shell and change to /usr/share/initramfs-tools by typing:

sudo bash
cd /usr/share/initramfs-tools # type into root shell

You have to change the file hook-functions. Just add overlay to the modules in line 528.

# The modules "most" classes added per default to the initramfs
        local arg
        local modules=

        if [ "$#" -eq 0 ] ; then
                set -- base net ide scsi block ata i2o dasd ieee1394 firewire mmc usb_storage

        for arg in "$@" ; do
                case "$arg" in
                        modules="$modules ehci-pci ehci-orion ehci-hcd ohci-hcd ohci-pci uhci-hcd usbhid overlay"
                        modules="$modules xhci xhci-pci xhci-hcd"
                        modules="$modules btrfs ext2 ext3 ext4 ext4dev "
                        modules="$modules isofs jfs reiserfs udf xfs"
                        modules="$modules nfs nfsv2 nfsv3 nfsv4"
                        modules="$modules af_packet atkbd i8042 psmouse"
                        modules="$modules virtio_pci virtio_mmio"

You can find my version on Gist: /usr/share/initramfs-tools/hook-functions.

This takes care of loading the overlay module at boot time.

Step 2

Next, you have to create a new boot script. Change to /usr/share/initramfs-tools/scripts and copy the existing boot script. Don’t worry if the last command fails, it will still work.

cd /usr/share/initramfs-tools/scripts
cp local overlay
cp -rp local-premount overlay-premount
cp -rp local-bottom overlay-bottom # don't mind if this fails

Now you’ll have to change the file overlay to mount the root read-only. The changes start in line 138.

	ROOT=$(resolve_device "$ROOT")

#	if [ "${readonly}" = "y" ]; then
#		roflag=-r
#	else
#		roflag=-w
#	fi

	# FIXME This has no error checking
	modprobe ${FSTYPE}

	checkfs ${ROOT} root

	# FIXME This has no error checking
	# Mount root
#	if [ "${FSTYPE}" != "unknown" ]; then
#		mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}
#	else
#		mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}
#	fi
	mkdir /upper /lower
	if [ "${FSTYPE}" != "unknown" ]; then
		mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} /lower
		mount ${roflag} ${ROOTFLAGS} ${ROOT} /lower
	modprobe overlay
	mount -t tmpfs tmpfs /upper
	mkdir /upper/data /upper/work
	mount -t overlay \
		-olowerdir=/lower,upperdir=/upper/data,workdir=/upper/work \
		overlay ${rootmnt}

Gist: /usr/share/initramfs-tools/scripts/overlay

Step 3 (Raspberry Pi 1, Zero, B+)

You can now generate a suitable initramfs. However, you’ll have to determine the kernel version first. In this example it is 4.4.34+. For a Raspberry Pi 2 or later it would be 4.4.34-v7+ (notice the v7). Then you can run update-initramfs using the kernel version. Then you just rename the resulting file.

uname -a
# Linux raspberrypi 4.4.34+ #930 Wed Nov 23 15:12:30 GMT 2016 armv6l GNU/Linux
update-initramfs -c -k 4.4.34+
cd /boot
mv initrd.img-4.4.34+ initrd.img

Now you have to tell the bootloader to load the initramfs. This can be done by adding the following lines to /boot/config.txt:

# Enable audio (loads snd_bcm2835)

initramfs initrd.img

Gist: /boot/config.txt

Step 3 (Raspberry Pi 2 and later)

As the later Raspberry Pi models use a different CPU, the output of uname will have an additional v7 in the kernel version (e.g. 4.4.34-v7+). The commands change to:

uname -a
# Linux raspberrypi 4.4.34-v7+ #930 Wed Nov 23 15:12:30 GMT 2016 armv6l GNU/Linux
update-initramfs -c -k 4.4.34-v7+
cd /boot
mv initrd.img-4.4.34-v7+ initrd7.img

Notice the 7 in initrd7.img. Now change /boot/config.txt:

# Enable audio (loads snd_bcm2835)

initramfs initrd7.img

Step 4

The last step is to change the boot command. Just add boot=overlay to the command in /boot/cmdline.txt:

boot=overlay dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait fastboot noswap

To disable the overlay this string has to be removed. As this file is found in the FAT-formatted boot partition this can be done by inserting the SD-card into a Windows PC as well. Notice that I have also added fastboot and noswap to the command. These options disable filesystem checking at boot and the swap.


If you have followed all the steps you can now reboot. After reboot run df to see if it worked.

# Filesystem     1K-blocks  Used Available Use% Mounted on
# udev               10240     0     10240   0% /dev
# tmpfs              37092  4596     32496  13% /run
# overlay            92720  1180     91540   2% /
# tmpfs              92720     0     92720   0% /dev/shm
# tmpfs               5120     4      5116   1% /run/lock
# tmpfs              92720     0     92720   0% /sys/fs/cgroup
# /dev/mmcblk0p1     64456 26528     37928  42% /boot
# tmpfs              18548     0     18548   0% /run/user/1000

If the filesystem for root (/) shows up as overlay it worked.

Written by Ferdinand

Januar 15th, 2017 at 15:35

Posted in Raspberry Pi

Tagged with ,

Drahtloser Temperatur- und Luftfeuchtesensor mit dem ESP8266

without comments


Über den ESP8266 der chinesischen Firma Espressif ist ja schon an vielen Stellen berichtet worden, aber hier nochmal die Kurzfassung: für ca. 3,– € bringen die verschiedenen ESP8266-Platinen einen Mikrocontroller mit WLAN-Schnittstelle, mehrere MB Flash und diverse Schnittstellen mit. Der Mikrocontroller kann mit eigenen Programmen beschrieben werden und damit eigene Projekte an das Internet anbinden.

Ich habe vor Kurzem ein ESP12-Modul mit passender Adapterplatine geschenkt bekommen. Als ersten Versuch mit diesem neuen Modul habe ich einen drahtlosen Temperatur- und Luftfeuchtesensor gebaut. Als Sensor habe ich den günstigen DHT11 verwendet. Dazu noch ein 3,3 V Linearregler und eine Spannungsquelle – das war’s. Das Programm habe ich in Lua geschrieben und mittels dem genialen NodeMCU Projekt auf dem ESP8266 laufen lassen. Dabei habe ich auf Code von Martin Han aufgebaut.

Der Code setzt die dht_lib ein um den Sensor auszulesen. Diese liegt im Repository von NodeMCU und muss mit auf den ESP8266 hochgeladen werden. Für den Upload des Programms habe ich ein günstiges USB-zu-seriell Modul und den ESPlorer von 4refr0nt benutzt.

-- ***************************************************************************
-- Drahtloser Temperatur- und Luftfeuchtesensor
-- von Ferdinand Keil
-- basierend auf Code von Martin Han
-- Public Domain
-- ***************************************************************************
-- HTML Template
<meta http-equiv="refresh" content="2">
<style type="text/css">
#sensor {
  font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;
#sensor td, #sensor th {
  border:1px solid #98bf21;
  padding:3px 7px 2px 7px;
#sensor th {
#sensor tr.alt td {
<table id="sensor">
<th>Input Source</th>
<td>DHT Temp&Humi Sensor</td>
CSS_2=[[ deg C</td>
CSS_3=[[ %</td>
-- Hauptprogramm
pin = 4 -- Pin mit dem der DHT11 verbunden ist
wifi.sta.config("SSID","PASSWORD") -- WLAN Zugangsdaten
dht = require("dht_lib")
humi = "Fehler"
temp = "Fehler"
-- Server starten wenn Verbindung steht
tmr.alarm(0,1000,1, function()
  if wifi.sta.getip() ~= nil then
    print("NodeMcu's IP Address:"..wifi.sta.getip())
    srv=net.createServer(net.TCP, 10)
        payload = nil
        print("Got request")
        conn:send("HTTP/1.0 200 OK\r\nServer: nodemcu-httpserver\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n")
-- regelmäßig den Sensor abfragen
tmr.alarm(1,1000,1, function()
  until dht.getHumidity() ~= nil
  temp = dht.getTemperature()/10
  humi = dht.getHumidity()/10
  print("Temperature: "..temp.." deg C, Humidity: "..humi.." %relH")

Sobald sich das Modul mit dem WLAN verbunden hat können die Messwerte über einen Browser angezeigt werden. Dazu muss nur die IP-Adresse die dem Modul zugewiesen wurde aufgerufen werden. Sie Ausgabe sieht dann in etwa so aus:


Written by Ferdinand

Juli 1st, 2015 at 21:47