Nuki Pro 5: Installation mit CH-Zylinder und API-Programmierung

Inhalt
1. Vorwort
2. Installation des Nukis mit CH-Zylinder
3. Voraussetzungen zur Steuerung des Nuki via API
4. API-Befehle
5. Automatisches Sperren von manuell aufgesperrten Türen
6. Alarm bei offengelassener Türe
7. Abrufen des Protokolls (Activity-Log)

1, Vorwort
Im Rahmen unseres Projektes Mosliboss SmartHome und in Anbetracht der Tatsache, dass die Kinder gelegentlich das Haus verlassen, ohne die Haustüre abzuschliessen, wurden Überlegungen in Richtung SmartLock gemacht und nach etlichen Recherchestunden fiel unsere Wahl auf ein Nuki Smart Lock Pro (5. Gen).
Gestaunt haben wir ob der Geschwindigkeit der Lieferung: Am Sonntag, 25. Mai 2025 wurde die Bestellung online aufgegeben und am Dienstag, 27. Mai 2025 lag das Paket bereits im Briefkasten!! Seltsamerweise wurde im Nuki-Club-Account die Bestellung bis am 27. Mai 2025 stets nur als 'In Bearbeitung' angezeigt und entsprechend gross war die Überraschung, als das Paket bereits weniger als 48 Stunden nach der Bestellung in Graz/Österreich bei uns in der Schweiz angekommen war...
Zwar ist dieses Schloss für EU-Zylinder offiziell nur bedingt geeignet für Schweizer Rund-Schloss-Zylinder, doch im folgenden Abschnitt wird erklärt, wie dies bei uns recht einfach erfolgreich realisiert worden ist.

2. Installation des Nukis mit CH-Zylinder
Wir haben ein Keso2000-Schloss mit einem Zylinder, der einen Durchmesser von 22mm aufweist und auf der Türinnenseite vom Schild ca. 14mm übersteht. Die mit dem Nuki mitgelieferte Klebe-Platte weist eine Dicke von ca. 4mm auf. Somit benötigen wir ein Zwischenstück von ca. 10mm Dicke, damit das Zylinderende ungefähr bündig mit der Oberfläche der Klebeplatte ist. Da wir heute im Jumbo keine passende Scheibe in Metall oder Kunststoff gefunden haben, kauften wir ein kleines Stück beschichtete Spanplatte mit 10mm Dicke. Davon wurde ein 5x5 cm grosses Stück ausgesägt und in der Mitte mittels einem 25mm-Forstnerbohrer ein Loch gebohrt. Das Türschild und das Holzstück wurden jeweils mittels Brennsprit gereinigt und das Holzstück mittels dem sehr gut klebenden und dünnen "tesa Powerbond" (beidseitig klebend, transparent, 5mx19mm) verbunden, so, dass der Zylinder schön mittig im Loch platziert ist (Foto 1).
     
Anschliessend wurde die gelieferte selbstklebende Nuki-Platte mit der aussen befindlichen Kerbe nach oben auf das (mit Brennsprit gereinigte) Holzstück geklebt (Foto 2) und schliesslich das Nuki Pro gemäss Anleitung darauf aufgesteckt, leicht im Uhrzeigersinn gedreht und fixiert (Fotos 3 und 4, jeweils unten mit dem magnetischen Ladekabel angeschlossen).
Mit diesem Vorgehen konnte das Nuki Pro 5 problemlos in Betrieb genommen werden!

3. Voraussetzungen zur Steuerung des Nuki via API
Um das Nuki Pro mittels API von einem Linux-Rechner anzusteuern, muss zuerst ein Konto auf dem Nukiweb https://web.nuki.io eingerichtet werden. Dort kann unter API ein API-Token generiert werden. Dieser sehr lange String vom Typ (hier fiktiv) 87f095d9c2b390dbf5dbfd1e457848bc4bc4665315a3 sollte irgendwo sicher abgespeichert werden, solange er noch angezeigt wird. Das Nuki-Gerät muss unbedingt via Nuki-App (Einstellungen - Funktionen&Konfiguration - NukiWeb) in der Nuki Web API angemeldet werden. Anschliessend muss noch der hexadezimale SmartLock-ID bestimmt werden. Dazu geht man in der Nuki-App zuerst in folgendes Menu:

Einstellungen - Funktionen&Konfiguration - Allgemein -
Dort findet man die Geräte ID: AB123CD
Für die API wird jedoch die dezimale ID benötigt, wobei (nach Recherchen im Web) folgendes gilt:
- Für Smart Locks Gen 1 und Gen 2 gilt ein Prefix=0
- Für Smart Locks Gen 3 und Gen 4 gilt ein Prefix=4
- Für Smart Locks Go/Pro/Ultra gilt ein Prefix=5
In unserem Fall (Pro) wird dem GeräteID somit eine '5' vorangestellt und damit der Hex-Wert zu 5AB123CD . Dieser lässt sich nun z.B. mittels dem Hexadecimal to Decimal converter in einen dezimalen GeräteID mit dem Wert 1521558477 umrechnen; nein, dieses Beispiel ist natürlich nicht unsere GeräteID... :-)

4. API-Befehle
In diesem Abschnitt sollen einige Beispiele von API-Steuer-Befehlen erklärt werden.

API_token="87f095d9c2b390dbf5dbfd1e457848bc4bc4665315a3"
Nuki_ID="1521558477"
# Status abfragen:
curl --no-sessionid -X GET \
    --header "Accept: application/json" \
    --header "Authorization: Bearer $API_token" \
    "https://api.nuki.io/smartlock" \
    --output out.out 2>/dev/null

Falls der Output im File out.out eine Fehlermeldung der Form
{"detailMessage":"Your access token is not authorized","stackTrace":[],"suppressedExceptions":[]}
enthält, ist irgendetwas schief gelaufen. Insbesondere ist es wichtig, dass bei den curl-Parametern Gänsefüsschen (") und nicht Apostrophe (') verwendet werden, weil letztere die Variablen wie $API_token und $Nuki_ID nicht in die wahren Werte übersetzen!

Um nun z.B. den Status von zwei Nukis in entsprechenden Files zu listen und einige kritische Parameter in der Konsole darzustellen, kann folgendes Script namens get_nuki_status.sh verwendet werden:

#!/bin/bash
# get_nuki_status.sh 28May2025/uk
OUTFILE="out.out"
API_token="87f095d9c2b390dbf5dbfd1e457848bc4bc4665315a3"
Nuki1="1521558477"
Nuki2="1521558488"

# Status abfragen
curl --no-sessionid -X GET \
    -H "Accept: application/json" \
    -H "Authorization: Bearer $API_token" \
    "https://api.nuki.io/smartlock" \
    --output $OUTFILE 2>/dev/null
if test $? -ne 0 ; then
   echo "Fehler bei der curl-Abfrage - exit!"
   exit
fi

# Die Daten der beiden Nukis extrahieren und jeweils in eine Datei speichern
jq '.[0]' "$OUTFILE" > Nuki1.status
jq '.[1]' "$OUTFILE" > Nuki2.status

#echo "Statusdateien erstellt: Nuki1.status und Nuki2.status"

# Kritische Parameter:
tuerstatus=$(jq '.[0].state.doorState' "$OUTFILE")
schlossstatus=$(jq '.[0].state.state' "$OUTFILE")
batteriestatus=$(jq '.[0].state.batteryCharge' "$OUTFILE")
echo "Nuki1:"
echo "Tuere: $tuerstatus   (2: geschlossen, 3: offen)"
echo "Schloss: $schlossstatus (1: zugesperrt, 3: entsperrt)"
echo "Akku: $batteriestatus%"
tuerstatus=$(jq '.[1].state.doorState' "$OUTFILE")
schlossstatus=$(jq '.[1].state.state' "$OUTFILE")
batteriestatus=$(jq '.[1].state.batteryCharge' "$OUTFILE")
echo " "
echo "Nuki2:"
echo "Tuere: $tuerstatus   (2: geschlossen, 3: offen)"
echo "Schloss: $schlossstatus (1: zugesperrt, 3: entsperrt)"
echo "Akku: $batteriestatus%"
#

Dies ergibt dann z.B. folgenden Output:

Nuki1:
Tuere: 2   (2: geschlossen, 3: offen)
Schloss: 1 (1: zugesperrt, 3: entsperrt)
Akku: 100%
 
Nuki2:
Tuere: 2   (2: geschlossen, 3: offen)
Schloss: 3 (1: zugesperrt, 3: entsperrt)
Akku: 80%
und die gesamten Statusinformationen der Nukis sind in recht gut lesbarer Form in den Files Nuki1.status und Nuki2.status enthalten.

5. Automatisches Sperren von manuell aufgesperrten Türen
Es kann vorkommen, dass jemand ein Nuki von innen absichtlich aufsperrt, die Türe dann jedoch nicht öffnet. In diesem Fall greift die Regel "Autolock" nicht, welche nachdem Schliessen der Türe diese automatisch verriegelt (zusperrt). Für diesen Fall wurde bei uns ein Script check_locked_doors.sh implementiert, welches via Cron-Job
*/3 * * * * nice -n 15 $HOME/smarthome/nuki/check_locked_doors.sh >> $HOME/smarthome/nuki/check_locked_doors.log 2>>$HOME/smarthome/nuki/check_locked_doors.errlog
alle drei Minuten kontrolliert, ob eine Türe zwar geschlossen,, aber nicht zugesperrt ist. Falls dies der Fall ist, wird die Türe automatisch zugesperrt. Bemerkung: In den folgenden Scripts ist jeweils eine Zeile source $HOME/smarthome/HA/MASTER.file zu finden. Die steht deshalb da, weil wir ein Hochverfügbarkeitssystem in Betrieb haben und diverse Scripts nur dann ausgeführt werden sollen, wenn der Rechner den Status MASTER hat. Zudem sind etliche Files, die sich öfters ändern, in einer RAM-Disk abgespeichert - siehe dazu "RAM-Disk auf Raspi einrichten zur Schonung der SD-Karte".

#!/bin/bash
# check_locked_doors.sh 29May2025/uk
#
source $HOME/smarthome/HA/MASTER.file
if test "$MASTER" = "no" ; then
#      echo "Not MASTER - exit! `date +%d.%m.%Y_%H:%M`"
   exit
fi
mkdir -p /mnt/ramdisk/Nuki
cd $HOME/smarthome/nuki
# Nicht, dass alle 3 Minuten 0 Sekunden mehrere Prozesse laufen:
sleep 13
#
OUTFILE="/mnt/ramdisk/Nuki/check.out"
#
API_token="87f095d9c2b390dbf5dbfd1e457848bc4bc4665315a3"
Nuki_EG_ID="1521558477"
Nuki_UG_ID="1521558488"
#
get_status() {
   curl --no-sessionid -X GET \
       -H "Accept: application/json" \
       -H "Authorization: Bearer $API_token" \
       "https://api.nuki.io/smartlock" \
       --output $1 2>/dev/null
   if test $? -ne 0 ; then
      echo "check_locked_doors.sh - Fehler bei der curl-Status-Abfrage - exit! `date +%d.%m.%Y_%H:%M`"
      exit 1
   fi
   EGtuerstatus=$(jq '.[0].state.doorState' "$OUTFILE")
   EGschlossstatus=$(jq '.[0].state.state' "$OUTFILE")
   UGtuerstatus=$(jq '.[1].state.doorState' "$OUTFILE")
   UGschlossstatus=$(jq '.[1].state.state' "$OUTFILE")
}
#
lock_door() {
   action="lock"
   curl --no-sessionid -X POST \
       -H "Authorization: Bearer $API_token" \
       -H "Accept: application/json" \
       "https://api.nuki.io/smartlock/$2/action/$action" \
       --output $1 2>/dev/null
   if test $? -ne 0 ; then
      echo "check_locked_doors.sh - Fehler beim curl-Lock-Befehl - exit! `date +%d.%m.%Y_%H:%M`"
      exit 1
   fi
}
#
get_status $OUTFILE
if test $EGtuerstatus -eq 2 && test $EGschlossstatus -eq 1 ; then
#   echo "Türe EG geschlossen und zugesperrt"
   :
fi
if test $UGtuerstatus -eq 2 && test $UGschlossstatus -eq 1 ; then
#   echo "Türe UG geschlossen und zugesperrt"
   :
fi
#
if test $EGtuerstatus -eq 2 && test $EGschlossstatus -eq 3 ; then
   echo "check_locked_doors.sh - EG-Türe geschlossen aber nicht zugesperrt - 10 Sek. warten `date +%d.%m.%Y_%H:%M`"
   sleep 10
   get_status $OUTFILE
   if test $EGtuerstatus -eq 2 && test $EGschlossstatus -eq 3 ; then
      lock_door $OUTFILE $Nuki_EG_ID
      echo "check_locked_doors.sh - EG-Türe geschlossen aber nicht zugesperrt - wird zugesperrt `date +%d.%m.%Y_%H:%M`"
   fi
fi
if test $UGtuerstatus -eq 2 && test $UGschlossstatus -eq 3 ; then
   echo "check_locked_doors.sh - UG-Türe geschlossen aber nicht zugesperrt - 10 Sekunden warten `date +%d.%m.%Y_%H:%M`"
   sleep 10
   get_status $OUTFILE
   if test $UGtuerstatus -eq 2 && test $UGschlossstatus -eq 3 ; then
      lock_door $OUTFILE $Nuki_UG_ID
      echo "check_locked_doors.sh - UG-Türe geschlossen aber nicht zugesperrt - wird zugesperrt `date +%d.%m.%Y_%H:%M`"
   fi
fi
#

6. Alarm bei offengelassener Türe
Bei all diesen Automatismen kann in findiger Junior, der nur "kurz" draussen ein bisschen Turnen woltle, auf die Idee kommen, die Haustüre einfach offen stehen zu lassen, was verantwortliche Eltern natürlich nicht gutheissen können.
Aus diesem Grund wurde für jede Türe mit einem Nuki ein Cron-Job eingerichtet, der jede Minute testet, ob eine Türe geöffnet ist:
* * * * * nice -n 15 $HOME/smarthome/nuki/check_closed_doors.sh EG >> $HOME/smarthome/nuki/check_closed_doors.log 2>>$HOME/smarthome/nuki/closed_doors.errlog
* * * * * nice -n 15 $HOME/smarthome/nuki/check_closed_doors.sh UG >> $HOME/smarthome/nuki/check_closed_doors.log 2>>$HOME/smarthome/nuki/closed_doors.errlog
Falls eine Türe längere Zeit offen bleibt, wurde mittels einem von früheren Experimenten vorhandenen "Shelly Plug S" zum Schalten einer günstigen kleinen Sirene und einem 12 Volt Netzteil eine Alarmeinheit beschafft.

Das Script namens check_closed_doors.sh sieht wie folgt aus:

#!/bin/bash
# check_closed_doors.sh 02Jun2025/uk - flexible Alarme

source $HOME/smarthome/HA/MASTER.file
if test "$MASTER" = "no" ; then
  exit
fi

if test $# -ne 1 ; then
  echo "Usage: $0 {EG|UG} `date +%d.%m.%Y_%H:%M`"
  exit 1
fi

door="$1"
# Damit nicht zu viele Jobs um *:00 Minuten laufen:
if test "$door" = "EG" ; then
   sleep 2
fi
if test "$door" = "UG" ; then
   sleep 7
fi

mkdir -p /mnt/ramdisk/Nuki
cd $HOME/smarthome/nuki

OUTFILE="/mnt/ramdisk/Nuki/check_closed_doors_$door.out"
LOCKFILE="/mnt/ramdisk/Nuki/check_closed_doors_$door.lock"
STATEFILE="/mnt/ramdisk/Nuki/check_closed_doors_${door}.state"
ALARM_INDEX_FILE="/mnt/ramdisk/Nuki/alarm_index_${door}.txt"

API_token="87f095d9c2b390dbf5dbfd1e457848bc4bc4665315a3"
Nuki_EG_ID="1521558477"
Nuki_UG_ID="1521558488"
[ "$door" = "EG" ] && Nuki_ID="$Nuki_EG_ID"
[ "$door" = "UG" ] && Nuki_ID="$Nuki_UG_ID"

# Alarm- und Sirenenkonfiguration
Alarms_after=(60 120 180 240 300 360 420 480 540 600 660 720)
Siren_duration=(0 1.0 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 3.0)

# Längen vergleichen
if [ "${#Alarms_after[@]}" -ne "${#Siren_duration[@]}" ]; then
  echo "<font color=orange>Fehler: Die Arrays Alarms_after und Siren_duration sind nicht gleich lang!"
  echo "Länge Alarms_after: ${#Alarms_after[@]}"
  echo "Länge Siren_duration: ${#Siren_duration[@]}"
  exit 1
fi

get_status() {
  curl --no-sessionid -X GET \
    -H "Accept: application/json" \
    -H "Authorization: Bearer $API_token" \
    "https://api.nuki.io/smartlock" \
    --output "$OUTFILE" 2>/dev/null
  if test $? -ne 0 || ! test -s "$OUTFILE" ; then
    echo "<font color=orange>Fehler bei curl - keine oder leere Antwort! - exit! `date`"
    rm -f "$LOCKFILE"
    exit 1
  fi

  # Prüfe, ob die Datei wirklich JSON ist
  if ! jq . "$OUTFILE" >/dev/null 2>&1; then
    echo "<font color=orange>Fehler: Ungültige JSON-Antwort in $OUTFILE (`date`)"
    rm -f "$LOCKFILE"
    exit 1
  fi

  if [ "$door" = "EG" ]; then
    TuerStatus=$(jq '.[0].state.doorState' "$OUTFILE")
    SchlossStatus=$(jq '.[0].state.state' "$OUTFILE")
  else
    TuerStatus=$(jq '.[1].state.doorState' "$OUTFILE")
    SchlossStatus=$(jq '.[0].state.state' "$OUTFILE")
  fi

  # Prüfen, ob TuerStatus eine Zahl ist
  if ! [[ "$TuerStatus" =~ ^[0-9]+$ ]]; then
    echo "<font color=orange>Fehler: Kein gültiger Türstatus (doorState=$TuerStatus) - Abbruch! `date`"
    rm -f "$LOCKFILE"
    exit 1
  fi
  # Prüfen, ob SchlossStatus eine Zahl ist
  if ! [[ "$SchlossStatus" =~ ^[0-9]+$ ]]; then
    echo "<font color=orange>Fehler: Kein gültiger Schlossstatus (LockState=$SchlossStatus) - Abbruch! `date`"
    rm -f "$LOCKFILE"
    exit 1
  fi
}

if test -e "$LOCKFILE" ; then
  exit 0
else
  touch "$LOCKFILE"
fi

get_status

# Prüfen, ob TuerStatus eine Zahl ist
if ! [[ "$TuerStatus" =~ ^[0-9]+$ ]]; then
  echo "<font color=orange>Fehler: Kein gültiger Türstatus - wahrscheinlich Fehler bei der API/JSON. Türstatus: '$TuerStatus' (`date`)"
  rm -f "$LOCKFILE"
  exit 1
fi
# Prüfen, ob SchlossStatus eine Zahl ist
if ! [[ "$SchlossStatus" =~ ^[0-9]+$ ]]; then
  echo "<font color=orange>Fehler: Kein gültiger Schlossstatus - wahrscheinlich Fehler bei der API/JSON. Schlossstatus: '$SchlossStatus' (`date`)"
  rm -f "$LOCKFILE"
  exit 1
fi

if [ "$TuerStatus" -ne 3 ]; then
  # Tür nicht offen → alles ok, State-Dateien löschen
  rm -f "$STATEFILE" "$ALARM_INDEX_FILE" "$LOCKFILE"
  exit 0
fi

# Türe OFFEN und gleichzeitig GESCHLOSSEN - sollte nie der Fall sein --> Alarm!!
if test "$TuerStatus" -eq 3 && test "$SchlossStatus" -eq  1 ; then
   siren_time=5
   message="Türe $door OFFEN und gleichzeitig GESCHLOSSEN! (SD=$siren_time) `date +%d.%m.%Y_%H:%M`"
   echo "<font color=yellow>$message"
   /usr/local/bin/send_telegram "$message"
   ./sirene_schalten.sh $siren_time
   rm -f "$STATEFILE" "$ALARM_INDEX_FILE" "$LOCKFILE"
   exit 0
fi

now=$(date +%s)
if test -e "$STATEFILE"; then
  start=$(cat "$STATEFILE")
else
  start=$now
  echo "$start" > "$STATEFILE"
  echo "Tür $door seit jetzt offen: `date +%d.%m.%Y_%H:%M`"
fi

duration=$((now - start))

# Aktueller Alarm-Index
if test -e "$ALARM_INDEX_FILE"; then
  ALARM_INDEX=$(cat "$ALARM_INDEX_FILE")
else
  ALARM_INDEX=0
fi

# Prüfen, ob nächster Alarm fällig ist
if [ $ALARM_INDEX -lt ${#Alarms_after[@]} ]; then
  next_alarm=${Alarms_after[$ALARM_INDEX]}
  if [ $duration -ge $next_alarm ]; then
    # Sende Alarm
    minutes=$((duration / 60))
    siren_time=${Siren_duration[$ALARM_INDEX]}
    message="Türe $door seit $minutes Minuten offen! (SD=$siren_time) `date +%d.%m.%Y_%H:%M`"
    echo "<font color=yellow>$message"
    /usr/local/bin/send_telegram "$message"
    ./sirene_schalten.sh $siren_time

    # Sirene auslösen (nur Beispiel, anpassen)
    # /usr/local/bin/trigger_siren $siren_time

    # Index erhöhen
    ALARM_INDEX=$((ALARM_INDEX + 1))
    echo "$ALARM_INDEX" > "$ALARM_INDEX_FILE"
  fi
fi

rm -f "$LOCKFILE"
#
In diesem Script wird auch das Script sirene_schalten.sh verwendet, welches wie folgt aussieht:
#!/bin/bash
# sirene_schalten.sh 02Jun2025/uk
#
# Schaltet einen Shelly-PlugS ein oder aus
# Einschalten kann auch nur für eine bestimmte Zeitdauer gelten
# Statusabfrage: EIN oder AUS
#
sirene_starten () {
   taskON="http://$shelly/relay/0?turn=on"
   taskOFF="http://$shelly/relay/0?turn=off"
#
   curl --fail --silent --show-error --no-sessionid --request $request_method  \
   $taskON --output $OUTFILE
   sleep 0.01
   curl --fail --silent --show-error --no-sessionid --request $request_method  \
   $taskOFF --output $OUTFILE
   sleep 1
#
   curl --fail --silent --show-error --no-sessionid --request $request_method  \
   $taskON --output $OUTFILE
   sleep 0.01
   curl --fail --silent --show-error --no-sessionid --request $request_method  \
   $taskOFF --output $OUTFILE
   sleep 1
#
   curl --fail --silent --show-error --no-sessionid --request $request_method  \
   $taskON --output $OUTFILE
   sleep $duration
   curl --fail --silent --show-error --no-sessionid --request $request_method  \
   $taskOFF --output $OUTFILE
#
}
#
n=$#
if test $n -ne 1 ; then
   echo "Usage: ./sirene_schalten.sh duration"
   echo "Example: ./sirene_schalten.sh 0.3"
fi
duration=$1
#
shelly="shellyplugs"
request_method="get"
#
source $HOME/smarthome/HA/MASTER.file
if test "$MASTER" = "no" ; then
#      echo "Nicht Master. shelly_schalten.sh - exit! `date +%d.%m.%Y_%H:%M`"
   exit
fi
#
mkdir -p /mnt/ramdisk/Nuki
cd $HOME/smarthome/nuki
#
OUTFILE="/mnt/ramdisk/Nuki/${0##*/}.result"
#
# Set PlugS to default power-on state to OFF:
taskDefaultOFF="http://$shelly/settings/relay/0?default_state=off"
curl --fail --silent --show-error --no-sessionid --request $request_method  \
   $taskDefaultOFF --output $OUTFILE
#
sirene_starten
#
wobei der shellyplugs im File /etc/hosts mit dessen IP-Nummer definiert ist. Das Script /usr/local/bin/send_telegram ist im Beitrag Automatisierte Message an Handy erklärt.

7. Abrufen des Protokolls (Activity-Log)
Um die letzten Aktivitäten der Nukis abzurufen und auf einer Web-Seite darzustellen, wurde ein entsprechendes Script get_activity_log.sh geschrieben:

#!/bin/bash
# get_activity_log.sh 30May2025/uk
#
source $HOME/smarthome/HA/MASTER.file
if test "$MASTER" = "no" ; then
#      echo "Not MASTER - exit! `date +%d.%m.%Y_%H:%M`"
   exit
fi
mkdir -p /mnt/ramdisk/Nuki
cd $HOME/smarthome/nuki
#
OUTFILE="/mnt/ramdisk/Nuki/activity_log.out"
#
API_token="87f095d9c2b390dbf5dbfd1e457848bc4bc4665315a3"
Nuki_EG_ID="1521558477"
Nuki_UG_ID="1521558488"
#
echo "Nuki EG"
curl -X GET \
   -H "Accept: application/json" \
   -H "Authorization: Bearer $API_token" \
    "https://api.nuki.io/smartlock/$Nuki_EG_ID/log?limit=50" \
   --output $OUTFILE 2>/dev/null
#
if test $? -ne 0 ; then
   echo "get_activity_log.sh - Fehler bei der curl-Status-Abfrage - exit! `date +%d.%m.%Y_%H:%M`"
   exit 1
fi
#    jq -r '.[] | "\(.date) - \(.action|tostring|gsub("1";"Lock")|gsub("2";"Unlock")|gsub("3";"Unlatch")) - \(.name)"' /mnt/ramdisk/Nuki/activity_log.out
INPUT="/mnt/ramdisk/Nuki/activity_log.out"
jq -c '.[]' "$INPUT" | while read -r entry; do
  date_utc=$(echo "$entry" | jq -r '.date')
  action=$(echo "$entry" | jq -r '.action')
  name=$(echo "$entry" | jq -r '.name')
  if test "$name" = "User1" ; then
     name="<font color=blue>User1"
  fi
  if test "$name" = "User2" ; then
     name="<font color=blue>User2"
  fi
#  if test "$name" = "- Nuki Keypad" ; then
#     name="- Ungültiger Fingerprint"
#  fi
  source=$(echo "$entry" | jq -r '.source')
  trigger=$(echo "$entry" | jq -r '.trigger')
  if test $trigger -eq 6 ; then
     name="AutoLock"
  fi
  if test $trigger -eq 1 || test $trigger -eq 2 ; then
     name="manual_Nuki"
  fi

  # Aktion umsetzen
  case $action in
    1) action_txt="Unlock" ;;
    2) action_txt="Lock" ;;
    3) action_txt="Unlatch" ;;
    4) action_txt="Lock'n'go" ;;
    240) action_txt="Door opened"
         name="" ;;
    241) action_txt="Door closed"
         name="" ;;
    242) action_txt="<font color=yellow>DoorSensor jammed!!"
         name="" ;;
    *) action_txt="Other (action=$action)" ;;
  esac

  # Source umsetzen
  source_nr=$source
  case $source in
#    0) source_txt="default" ;;
    0) source_txt=""
       source_nr="" ;;
    1) source_txt="KeypadCode" ;;
    2) source_txt="Fingerprint" ;;
    *) source_txt="Other (source=$source)" ;;
  esac
  if test "$source_txt" = "KeypadCode" && test "$name" = "Nuki Keypad" ; then
     name="<font color=yellow>ungültig/dev/null
#
if test $? -ne 0 ; then
   echo "get_activity_log.sh - Fehler bei der curl-Status-Abfrage - exit! `date +%d.%m.%Y_%H:%M`"
   exit 1
fi
#    jq -r '.[] | "\(.date) - \(.action|tostring|gsub("1";"Lock")|gsub("2";"Unlock")|gsub("3";"Unlatch")) - \(.name)"' /mnt/ramdisk/Nuki/activity_log.out
INPUT="/mnt/ramdisk/Nuki/activity_log.out"
jq -c '.[]' "$INPUT" | while read -r entry; do
  date_utc=$(echo "$entry" | jq -r '.date')
  action=$(echo "$entry" | jq -r '.action')
  name=$(echo "$entry" | jq -r '.name')
  if test "$name" = "Urs" ; then
     name="<font color=blue>User1"
  fi
  if test "$name" = "Caro" ; then
     name="<font color=blue>User2"
  fi
  source=$(echo "$entry" | jq -r '.source')
  trigger=$(echo "$entry" | jq -r '.trigger')
  if test $trigger -eq 6 ; then
     name="AutoLock"
  fi
  if test $trigger -eq 1 || test $trigger -eq 2 ; then
     name="manual_Nuki"
  fi

  # Aktion umsetzen
  case $action in
    1) action_txt="Unlock" ;;
    2) action_txt="Lock" ;;
    3) action_txt="Unlatch" ;;
    4) action_txt="Lock'n'go" ;;
    240) action_txt="Door opened"
         name="" ;;
    241) action_txt="Door closed"
         name="" ;;
    242) action_txt="DoorSensor jammed!!"
         name="" ;;
    *) action_txt="Other (action=$action)" ;;
  esac

  # Source umsetzen
  source_nr=$source
  case $source in
#    0) source_txt="default" ;;
    0) source_txt=""
       source_nr="" ;;
    1) source_txt="KeypadCode" ;;
    1) source_txt="KeypadCode" ;;
    2) source_txt="Fingerprint" ;;
    *) source_txt="Other (source=$source)" ;;
  esac
  if test "$source_txt" = "KeypadCode" && test "$name" = "Nuki Keypad" ; then
     name="<font color=yellow>ungültig"  # Zahlencode
  fi
  if test "$source_txt" = "Fingerprint" && test "$name" = "Nuki Keypad" ; then
     name="<font color=yellow>ungültig"  # Fingerprint
  fi
  if test "$name" = "Zutrittscode" ; then
     name="OK"
  fi
  if test "$name" = "Nuki Keypad" ; then
     name="manual_Keypad"
  fi
  if test "$name" = "Nuki Web" ; then
     name="<font color=blue>via_API"
  fi

  # UTC → Lokalzeit
  date_local=$(date -d "$date_utc" +"%Y-%m-%d %H:%M:%S")

# Zeile MIT Codes:
#  echo "$date_local $action $action_txt $source_nr $source_txt $name" | tr -s '  ' ' '
# Zeile OHNE Codes:
  echo "$date_local $action_txt $source_txt $name" | tr -s '  ' ' '
done
#


Last update: 21Jun2025 - Created: 27May2025/uk