ekey UDP-Datensenke

Einleitung

Ich habe das ekey Home Fingerscanner-Zutrittssystem im Einsatz.

Nun wollte ich das ganze über die Heimautomatisierung irgendwie auswertbar machen und habe mir den ekey CV LAN zugelegt.
Dieser sendet UDP-Datenpakete an eine zuvor definierte IP-Adresse ("Datensenke" im ekey-Jargon).

Die Herausforderung war nun, eine solche Datensenke zu erstellen.

In meinem Fall ist es ein simples Bash-Script geworden, das auf einem Raspberry Pi per systemd läuft. Es empfängt per socat die Pakete, wertet diese aus und sendet sie anschließend an die API meiner Heimautomatisierung. Das kann natürlich beliebig auf jedes andere System angepasst werden, das per HTML-API o.ä. ansprechbar ist.

Voraussetzungen:

  • ekey CV LAN für das ekey-Home-System (für ekey home oder multi muss es der mit der Produktnummer 100 460 sein, der andere funktioniert nur mit ekey net)
  • ein paar Linux-Kenntnisse schaden nicht
  • ein Debian-System (z.B. Raspberry mit Raspbian)
  • socat (apt install socat)

Vorarbeiten

Den ekey CV LAN nach Bedienungsanleitung in den ekey BUS und ans Netzwerk bringen.

Dann mit der mitgelieferten Software entsprechend einstellen.

Bestandteile

Das Auswertungsscript

In meinem Fall drückt das Script eine virtuelle Taste meiner Heimautomatisierung, falls der Finger nicht erkannt wurde und löst so ein Klingelsignal aus. Wurde der Finger erkannt, wird nur geloggt.

/usr/local/bin/ekey-converter.sh

#!/bin/bash

# --- ekey data sink ---

# The home protocol can only be used in ekey home systems. Data packets are created
# for each recognized finger and every time a refusal takes place at the finger
# scanner. The data fields within the data packet are ASCII-encoded. This protocol
# has the following structure:
# Base format: x_xxxx_x_xxxxxxxxxxxxxx_x_x
#
# Data field name | Number of digits | Data type       | Value range      | Meaning
# PACKET TYPE       1                  String            1                  *User data* packet type
# USER ID           4                  String (decimal)  0000-9999          User number (default 0000)
# FINGER ID         1                  String (decimal)  0-9                1 = left little finger
#                                                                           2 = left ring finger
#                                                                           3 = left middle finger
#                                                                           4 = left index finger
#                                                                           5 = left thumb
#                                                                           6 = right thumb
#                                                                           7 = right index finger
#                                                                           8 = right middle finger
#                                                                           9 = right ring finger
#                                                                           0 = right little finger
#                                                                           R = RFID
#                                                                           - = no finger
# SERIAL NO. FS     14                 String            xxxxxx xx xx xxxx  Digits 1-6 = item number
#                                                                           Digits 7-10 = week code
#                                                                           Digits 11-14 = sequential number
# ACTION            1                  String            1, 2               1 = Open
#                                                                           2 = Refuse unrecognized finger
#                                                                           8 = Digital input
# RELAY             1                  String            1-4; -             1 = Relay 1
#                                                                           2 = Relay 2
#                                                                           3 = Relay 3
#                                                                           4 = Relay 4
#                                                                           d = Double relay
#                                                                           - = no relay

log="/usr/bin/logger -i -p local0.info -t ekey-converter.sh"
log_dbg="/usr/bin/logger -i -p local0.debug -t ekey-converter.sh"
log_err="/usr/bin/logger -i -p local0.warning -t ekey-converter.sh"
#debug=true
$log "Start ekey-converter.sh"
# get data from stdin
read MESSAGE
if [ ! -z "$MESSAGE" ]; then
  $log " Message: '$MESSAGE'"
  # check if MESSAGE has expected format
  if [[ ${MESSAGE} =~ ^._.{4}_._12345678901234_._.$ ]]; then
    # split into array
    IFS='_' read -a msg <<< "${MESSAGE}"
    # arrays for naming etc.
    name=('PAKETTYPE' 'USERID' 'FINGERID' 'SERIALNO' 'ACTION' 'RELAIS')
    fingerids=('right little finger' 'left little finger' 'left ring finger' 'left middle finger' 'left index finger' 'left thumb' 'right thumb' 'right index finger' 'right middle finger' 'right ring finger')
    fingerid=${msg[2]}
    # resolve finger id to name
    if [ $fingerid == "-" ]; then
      fingername="None"
    elif [ $fingerid == "R" ]; then
      fingername="RFID"
    else
      fingername=${fingerids[$fingerid]}
    fi
    action=${msg[4]}
    userid=${msg[1]}
    # resolve userid to name
    if [ $userid == "0001" ]; then
      username="User1"
    elif [ $userid == "0002" ]; then
      username="User2"
    # etc...
    else
      username="Unknown"
    fi
    # debug output if debug is set
    if [ $debug ]; then
      for i in {0..5..1}; do
        $log_dbg " ${name[i]}: ${msg[i]}"
      done
    fi
    $log " User: $username (ID: $userid), Finger: $fingername (ID: $fingerid), Action: $action (1 = Open, 2 = Refuse unrecognized finger)"
    # HomeMatic CCU and device to press
    hm_server="192.168.0.15"
    hm_channel="Klingeltaster_ekey"
    hm_url="http://$hm_server:8181/ccu.exe?do=(dom.GetObject(ID_CHANNELS)).Get('$hm_channel').DPByHssDP('PRESS_SHORT').State(1)"
    # check if unrecognized finger
    if [ $action == "2" ]; then
      $log " Unrecognized finger, running: /usr/bin/curl -s '$hm_url'"
      /usr/bin/curl -s '$hm_url'
    elif [ $action == "1" ]; then
      $log " Finger accepted"
    fi
  else
    $log_err " Message corrupted or incomplete, should be 'x_xxxx_x_12345678901234_x_x'."
  fi
else
  $log_err " No input given, MESSAGE is empty"
fi
$log "End ekey-converter.sh"
# Done

Der Starter

Das vorhergehende Script wird jedes mal aufgerufen, wenn ein Paket vom CV LAN empfangen wird. Dies stellen wir mit folgendem Script sicher.

/usr/local/bin/ekey-converter-starter.sh

#!/bin/bash
while true
do
  /usr/bin/socat -u udp4-recvfrom:56000,keepalive,fork system:'/usr/local/bin/ekey-converter.sh'
done

Der systemd-Eintrag

/etc/systemd/system/ekey-cv.service

[Unit]
Description=Socat with ekey-converter
After=network-online.target
Requires=network-online.target

[Service]
ExecStart='/usr/local/bin/ekey-converter-starter.sh'
RestartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

Dann noch den systemd-Eintrag aktivieren und starten:

systemd enable ekey-cv.service

systemd start ekey-cv.service

Fazit

Man kann natürlich im eigentlichen Script auch alles mögliche andere anhand der empfangenen Pakete starten, der Fantasie sind hier kaum Grenzen gesetzt...