Command Keypad


If have to admit, the idea of having some small physical keyboard to bind arbitrary commands to control my Raspberry Pi came up long time ago. After that I learned that you could control the Kodi media center running on that small computer with the TV remote via CEC (HDMI control) the plan was dropped again. These days, I finally did it, because I felt like having some easy possibility to quickly pause music or shutdown the Raspberry Pi would after all be very useful.

In short

To realize this I wrote a simple python script called command-keypad to handle my keypad inputs and map them to custom command sets. It is heavily inspired by Peter Dikant’s rpi-ola-controller.

The script is executed whenever the keypad is plugged in and stopped when removed. This is done via udev and systemd. However, if run on an OSMC Pi Box as in my case, you additionally need to hide the keypad from Kodi, otherwise the media center alone will have the power over your command pad.

Hands on!

First, you need a couple of files, to be found in my command-keypad project on github.

Make sure you have a linux system with python installed. In particular the script needs python-evdev available in many distributions repositories. Otherwise install it via pip.

sudo pip install PyYAML evdev

Now you can run the controller with the sample configuration file:

sudo ./ -c conf/simpleconfig.yaml

The evdev library captures the keyboard input on device level and needs root privileges. The above command will search for all available input devices and list them:

Error: You need to specify one of the following input devices:
  /dev/input/event3    ImExPS/2 Generic Explorer Mouse 
  /dev/input/event2    AT Translated Set 2 keyboard    
  /dev/input/event1    Sleep Button                    
  /dev/input/event0    Power Button

Select your keyboard and add the device to the command line:

sudo ./ -c conf/simpleconfig.yaml -i /dev/input/event2

The script will now listen to your keyboard inputs. Try pressing a key to execute the mapped command. If you press a key that is not mapped, the key code will be displayed, so that you can configure this key in the yaml file.

Setup hotplugging

If you are happy with your key mappings, setup some links, so that the script is run, whenever the dedicated command keypad is connected. My OSMC system uses systemd, therefore I prepared two files which will do the trick for such a system. However, you have first to use udevadm to identify you command-keypad:

~$ udevadm info --attribute-walk /dev/input/event0 | less

looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3.2/1-1.3.2:1.1/0003:05A4:9750.0002/input/input1/event1':

looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3.2/1-1.3.2:1.1/0003:05A4:9750.0002/input/input1':
ATTRS{name}=="NOVATEK USB Keypad"

The bold attributes are well defined if you do not use several keyboards of the same kind, so we use them to setup an udevd rule to unically identify the device. Change those values in the *.rules file, provided. Be aware that udev does not support any sort of line breaks. Now link the rule file to /etc/udev/rules.d/ by issuing

~$ sudo ln -s /path/to/command-keypad/999-command-keypad.rules /etc/udev/rules.d/999-keypad.rules
~$ sudo udevadm control --reload-rules

udev will trigger to execution of the, so link that as well to the appropriate location (udev links our keypad at /dev/command-keypad so we don’t have to worry about device names afterwards).

~$ sudo ln -s /path/to/command-keypad/command-keypad.service /etc/systemd/system/command-keypad.service
~$ sudo systemctl daemon-reload

Also set the path to your configuration layout file in command-keypad.service. Since udev will trigger the service, you don’t have to activate it within systemd.

There you go. You can check whether your daemon is actually started on plugging in the keypad with

~$ sudo journalctl -f
Nov 19 23:09:12 pi kernel: input: NOVATEK USB Keypad as /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3.2/1-1.3.2:1.1/0003:05A4:9750.0016/input/input21
Nov 19 23:09:12 pi kernel: hid-generic 0003:05A4:9750.0016: input,hidraw1: USB HID v1.00 Mouse [NOVATEK USB Keypad] on usb-3f980000.usb-1.3.2/input1
Nov 19 23:09:12 pi systemd[1]: Starting command-keypad daemon...
Nov 19 23:09:12 pi systemd[1]: Started command-keypad daemon.
Nov 19 23:09:10 pi kernel: usb 1-1.3.2: USB disconnect, device number 17
Nov 19 23:09:10 pi[1271]: Device removed. Exiting Script.

Well done. You should now have a customizable hotplugging command keyboard!

Tagged with: , ,
Posted in Linux, Technik

Whatsapp with pidgin on Windows and Linux

I do not like Whatsapp. Not a bit. The reason is not, that it used to be very unsafe (today they claim to use a secure encryption), but rather that this affiliated company of the social media giant facebook has access to your contacts. That does not only include your own telephone number but also numbers, addresses etc. of all your friends and buisiness partners. Did you ask them, if you are allowed to give away their data? I doubt that. And although WhatsApp says that they do not store and use this data, I would doubt that. What should they hinder to do so? Who is able to keep track on that? After all, it’s facebook we’re dealing with.

But because Whatsapp is so popular, it is hard to avoid it completely. However, I found a nice compromise. You can install the software on your laptop! There is a plugin for the well-known messaging client pidgin, which works completely independently of every phone.

There is also a portable version which can be run from your pen-drive. The plugin for windows and linux can be found here. The plugin is free for linux only, but you may find a portable version of the software with WhatsApp plugin already included. But how to register without the official app? Or, if already registered, how to find username and password? That’s easy. Remember, WhatsApp is insecure. With the help of the simple python software yowsoup, you can register for WhatsApp of find your password without having the official App.

  1. Download and extract the zip archive on the right side of the page.
  2. Open a terminal (command line) and change to the directory of yowsoup
  3. Create a file config.txt in that directory with the following content
  4. In the command line, run the following command to request a new confirmation code
    yowsup-cli registration --requestcode sms --config config.txt
  5. Receive the code on your phone and get your password
    yowsup-cli registration --register <code-code> --config config.txt

Then youre done. You may add a WhatsApp account to pidgin using your phone number (as written in the config.txt file) and the received password. Of course, you have now to add contacts by yourself, because there is no address book to spy on.

After setting up the account in pidgin, you may get the message “Server closed the connection”. To circumvent this, change the default ressource in that very account to “Android-2.31.151-443” (see

Be always careful in the digital country.

Tagged with: , , ,
Posted in Gesellschaft, Technik

Set links on custom bibtex-keys with bibtex OR biblatex

Long time ago, while working on my thesis I fumbled with bibtex (do NOT do this) that creates bibliographies from *.bib files using a horrible stack-based scripting language for the styling. I wanted to have references directly linked to the matching articles in the web as many scientific journals do, see e.g. Nature Materials (hyperlink in blue):


Citation style of Nature Materials

You can do that either by using the URL directly or resolve the digital object identifier (DOI) via DOIs are very useful, if you can get them. See e.g. this article.

So my task was to implement that using bibtex (biblatex was not very common at that time). I succeeded, by introducing some linker function, named link_it, which was able to set an appropriate link on some sequence of bibtex-keys that were processed with bibtex. For technical details look at the custom style file unsrtnat_abbrv_link_it.bst on and search for that linker-function. Also see this article. However, here is how it looks like (hyperlink in green):


BibTeX reference using the style file unsrtnat_abbrv_link_it.bst found at

and here is how you use it:


Quite simple, apart from the difficulties altering the style file. However, every slight change involves stack-based horrors again, so better use the new approach with the biblatex package. For later works I used that with great success, so this is what I wanted to share with you today.

The result with the near-default style with the linker-function in it looks somewhat different from the one of natbib (hyperlink again in green):

Reference style created by the biblatex package

A bit longer is the piece of code that you have to add to your Header.tex file. But note, that you only need LaTeX-code here. Customization does not involve bibtex-style files! Okay, some of you might say that LaTeX code is also horrible to write at some deeper level. That’s true. But if you take this as an argument towards old-style bibtex, I would just say, you know nothing [John Snow].

% bibliography file
% clear some fields
% define a link format for arbitrary bibtex keys
% if hyperref is used, set doi/url links
% if not url and not doi, print without link
% use url only if doi is NOT present
% if doi is present, set a link on the key
% if no hyperref, do not link
% format settings
\DeclareFieldFormat[book,incollection]{isbn}{% set url link on ISBN
\mkbibacro{ISBN}\addcolon\space \usebibmacro{link_it}{#1}}
\DeclareFieldFormat[article]{number}{\mkbibparens{#1}} % number in brackets
\DeclareFieldFormat[article]{pages}{#1} % do not add anything to pages
\renewbibmacro{in:}{} % suppress "in:"
% define a "volume(number):pages" key
\clearfield{pages} % pages used, where not intended, clear field
% use "et al."
andothers={et\addabbrvspace al\adddot}}

I’m very hapy with this now. Another pro for biblatex is, that you only have to compile once, not twice, to update your bibliography. You may also have multiple bibtex-ressource files.

Feel free to comment or to use the code above. As always: everything CC BY-NC-SA🙂

Tagged with: , , , ,
Posted in Technik

Disable google click-tracking

I blogged already about the nicest firefox addons and improving google search by using greasemonkey userscripts. Only recently, I noticed, that the click-tracking redirection by google search is not blocked anymore. To not being click-tracked, please use this userscript, Remove-Google-Redirection, instead. It works very well (at least in Firefox).

Tagged with: , , ,
Posted in Technik

Script: notify by e-mail before running out of disk space

I just wanted to share another useful script, that can be run as a cronjob and send a warning notification via e-mail if your disk is running out of space. You may check it out on pastebin. It is supposed to work in conjunction with a small script examining the space used by trash bins on your system. You may install pydf on your system to make it more beautiful.

Tagged with: , , ,
Posted in Linux, Technik

Management of ProFTPD users with kolab-webadmin

ProFTPD is a versatile ftp server. I recently integrated it in my Kolab 3.3 server environment, so that user access be can easily organized by the standard kolab-webadmin. The design looks as follows:

Kolab users are be able to login to ProFTPD but every user gets jailed in his own separate (physical) home directory. According to his group memberships, aditional shared folders can be displayed and accessed within this home directory.

You will need proftpd with support for ldap and virtual root environments. In Debian and Ubuntu, this is achieved via module packages:

  • proftpd-mod-ldap, proftpd-mod-vroot

On other platforms you may need to compile your own proftpd.

Via kolab-webadmin I created a new organizational unit FTPGroups within parent unit Groups. Within this unit, you can now add groups of type (Pure) POSIX Group. These groups are later used to restrict or permit access to certain directories or apply other custom settings per group by using the IfGroup directive of ProFTPD.

Note, that you stick to sub-units of ou=Groups here, so that this unit will be recognized by the kolab-webadmin. The LDAP-record of such a group may look like this:

dn: cn=ftp_test_group,ou=FTPGroups,ou=Groups,dc=domain,dc=com
cn: ftp_test_group
gidnumber: 1234
objectclass: top
objectclass: groupofuniquenames
objectclass: posixgroup
uniquemember: uid=testuser,ou=People,dc=domain,dc=com

To make sure that our kolab-users and groups within the sub-unit get mapped correctly to their equivalents in the ftp-server, we have to edit the directives for mod_ldap. Just start with my working sample configuration ldap.conf on pastebin, which should be included in your main proftpd configuration.

Because we use the standard kolab ldap-schema, the users do neither posess a user nor group ID. Therefore, ProFTPD will fallback to the LDAPDefaultUID (example: ID of “nobody”) and LDAPDefaultGID (example: 10000). From the system side, a user with this combination of UID and GID should be allowed to read from (and maybe write to) your physical FTP directory tree. You can either add the user or group to your system and set the permissions accordingly or use the access control list (ACL). Since I use the acl-approach, the group with ID 10000 does not have to exist in /etc/group. You may install acl by executing

~# apt-get install acl

and mount your ftp storage device with the acl option (to be persistent add it in /etc/fstab) by executing

~# mount -o remount,defaults,noexec,rw,acl /dev/sda1 /var/ftp

To allow the access for users in our default group 10000 (for both existing and newly created files), we have to use the setfacl command. Think carefully about this. We want the users not to be able to remove one of the shared folders accidentally!

~# setfacl     -m g:10000:rx  /var/ftp/
~# setfacl -d  -m g:10000:rx  /var/ftp/
~# setfacl -d -Rm g:10000:rwx /var/ftp/*
~# setfacl    -Rm g:10000:rwx /var/ftp/*

We wanted all users to have their own home directory, which resides in /var/ftp/home/, so make sure this directory exists. To jail each user to their own home directory, change the DefaultRoot directive in your main configuration file /etc/proftpd.conf to look like

DefaultRoot  /var/ftp/home/%u

Nonexistent home directories /var/ftp/home/username will be created as requested by ldap.conf (see above). At this point, ldap users should be able to login and will be dropped in their empty home directory. Now we have to setup the directory permissions and have shared directories linked to the home directory. To achieve this we will make extensive use of the IfGroup directive. It’s very important, that the module mod_ifsession.c is the last module to load in /etc/proftpd/modules.conf! Additionally you should have lines, which load mod_vroot.c and mod_ldap.c.

Linking is very simple and works as follows:

<IfGroup ftp_test_group>
   VRootAlias /var/ftp/share /share>

Very useful in terms of security is to limit the use of particular FTP-Commands to the admin group

# limit login to users with valid ftp_* groups
<Limit LOGIN>
   AllowGroup ftp_admin_group,ftp_test_group
# in general allow ftp-commands for all users
<Directory />
   <Limit ALL ALL FTP>
      AllowGroup ftp_admin_group,ftp_test_group
# deny deletion of files (does not cover overwriting)
<Directory />
   <Limit DELE RMD>
      DenyGroup !ftp_admin_group

I think we are done here now. Restart your ftp server by

~# service proftpd restart

Here you go! For testing purposes set the log level to debug and monitor the login process. Also force SSL (mod_tls.c), because otherwise everything, even passwords, will be transferred as cleartext! If you run into trouble somewhere, just let me know.

Tagged with: ,
Posted in Linux, Technik

Record two audio sources simultaneously

Have you ever wanted to record microphone sources seperately and had no mixer deck at hand? Here is an interactive bash script that uses pulseaudio to combine two hardware-sources (sinks are also possible) as left and right channel of a new virtual sink. This enables you to use these sources as separable inputs for VoIP applications or home-recording. You can also check it out at pastebin. Of course, you think of altering the remap-module to record two or even more stereo sources as a single virtual multi-channel source. As always, the net helped me a lot with this task.


#    Script to map two pulseaudio hardware input sources as mono inputs
#    to left and right channel of a new loopback-sink respectively. This
#    sink can be used e.g. to use VoIP or record two microphones seperately.
#    Copyright (C) 2013, Henning Hollermann,
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <>.

do_activate() {
    while [ "x" = "x$LEFT" ]; do
        echo "Choose Source for left channel by ID"
        pactl list short sources
        read ID
        LEFT=$(pactl list short sources|awk '/^'$ID'/{print $2}')
    while [ "x" = "x$RIGHT" ]; do
        echo "Choose Source for right channel by ID"
        pactl list short sources | grep -v $LEFT
        read ID
        RIGHT=$(pactl list short sources | grep -v $LEFT|awk '/^'$ID'/{print $2}')
    # Create the name of the Combined sink
    NAME="Combined_Mics:_Left:_"$(echo $LEFT|awk -F'.' '$0=$2')"_Right:_"$(echo $RIGHT|awk -F'.' '$0=$2')

    echo "[LOAD] null sink as \"$NAME\" to connect the two mics to"
    pactl load-module module-null-sink \
            sink_name=combined channels=2 \

    echo "[LOAD] map source 1 ($LEFT) to left channel of \"$NAME\""
    pactl load-module module-remap-source \
            source_name=${LEFT}_left_channel master=$LEFT channels=2 \
            master_channel_map=mono,mono channel_map=left,left
    pactl load-module module-loopback sink=combined source=${LEFT}_left_channel

    echo "[LOAD] map source 2 ($RIGHT) to right channel of \"$NAME\""
    pactl load-module module-remap-source \
            source_name=${RIGHT}_right_channel master=$RIGHT channels=2 \
            master_channel_map=mono,mono channel_map=right,right
    pactl load-module module-loopback sink=combined source=${RIGHT}_right_channel
    echo "[DONE] Now adjust the left and right channel volume of the new sink to be equally loud"

do_deactivate() {
    echo "[UNLOAD] pulseaudio modules..."
    echo "[UNLOAD] module-loopback"
    pactl unload-module module-loopback
    echo "[UNLOAD] module-remap-source"
    pactl unload-module module-remap-source
    echo "[UNLOAD] module-null-sink"
    pactl unload-module module-null-sink

init() {
    for exe in /usr/bin/pulseaudio /usr/bin/pactl; do
        if [ ! -x "$exe" ]; then
            echo "[ERROR] required file $exe not found or not executable"
            exit 1
    [ ! -x /usr/bin/pavucontrol ] && echo "[NOTICE] pavucontrol might be very useful."

case $1 in
    echo "Usage: $0 [enable|disable]";;

Tagged with: , , , ,
Posted in Linux, Musik, Technik

yMPD a simply nice standalone webclient for MPD

yMPD ist a simple webclient application for the music player daemon, that consists of only one single executable. It serves as webserver and is written in C and JavaScript. Only recently I enhanced the frontend by adding some more columns as artist and album to the browsing and queue mode.

However, it still lacks the ability to edit the playlist (“queue”). If you speak C or JS, please feel free to add more flexibility to this wonderful and good looking client.

Posted in Allgemeines

AMaViS, SpamAssassin, roundcube and mySQL – a wedding story

Some time ago I blogged about fighting spam with amavis for the Kolab community. Now the story continues by means of the roundcube integration with amavis.

As earlier mentioned spamassassin is able to store recipient-based preferences in a mysql table with some settings in its (see spamassassin wiki)

# Spamassassin for Roundcubemail
user_scores_dsn DBI:mysql:ROUNDCUBEMAILDBNAME:localhost:3306
user_scores_sql_password ROUNCUBEMAILPASSWORD
user_scores_sql_username ROUNDCUBEMAILDBUSERNAME
user_scores_sql_custom_query SELECT preference, value FROM _TABLE_ WHERE username = _USERNAME_ OR username = '$GLOBAL' OR username = CONCAT('%',_DOMAIN_) ORDER BY username ASC

However, accessing this with amavis is a real bis problem for many users. Amavis has it’s own user-based configuration policies, but email-plugins as the roundcubemail plugin sauserprefs often only use spamassassin and not amavis. Originally, SA was only called once per message by amavis and therefore recipient-based preferences were not possible at all. This has changed. Now you can use the options @sa_userconf_maps and @sa_username_maps to perform such lookups. Unfortunately these options are still poorly documented. We use them anyway.

The values in @sa_userconf_maps define where amavis has to look for the user preferences. I use mySQL lookups for all recipient addresses.

# use userpref SQL connection from SA for ALL recipients
@sa_userconf_maps = ({
  '.' => 'sql:'

The variable @sa_username_maps tells amavis what to pass to spamassassin as _USERNAME_ (see above) for the mySQL lookup. By default the amavis system user is used. In my setup with Kolab and sauserprefs I use here a regexp which is supposed to match the recipient email-address:

# use recipient email address as _USERNAME_ in userpref mySQL table (_TABLE_)
@sa_username_maps = new_RE (
  [ qr'^([^@]+@.*)'i => '${1}' ]

With these additional bits sauserprefs should work. However it seems to me that the string “*** Spam ***”, which should be added to the subject does not work (maybe it does in the most recent version). The thresholds do, though, but better check it carefully.

Did you succeed? Comments are appreciated!

Tagged with: , , ,
Posted in Technik

What do nazis cook?

What do nazis cook? The answer is: vegan. Why? Because it’s in.

There is a dangerous new wave of right-wing extremism in germany, which presents itself closer to the “ordinary people” as never before. Under the cloak of citizens’ initiatives covering regional aspects as speaking up against expensive projects or similar they try to reach out further to the center of the political spectrum.

So you can e. g. watch nazis with ski masks cook vegan meals on youtube — but please, only german bananas!

Tagged with: ,
Posted in Gesellschaft, Politik
Posts by topic…
…by month
Have a look at…