#!/bin/bash # # tibberpulse2serial.sh # ===================== # # Macht einen Tibber Pulse (IR-Lesekopf + WLAN-Bridge) auf einem beliebigen # Linux-System als virtuelles serielles Geraet verfuegbar. Danach kann ihn # z. B. vzLogger genauso auslesen wie einen direkt angeschlossenen IR-Lesekopf. # # So funktioniert es: # Die Bridge liefert unter # http://:@/data.json?node_id= # bei jedem Aufruf genau ein transportkodiertes SML-Telegramm # (beginnt mit 1b 1b 1b 1b). Dieses Skript ruft die URL zyklisch per curl ab # und schreibt die rohen Telegramme in ein virtuelles serielles Geraet, das # mit socat als PTY angelegt wird (z. B. /dev/ttyTibber). # # Voraussetzungen: # - Der lokale Webserver der Tibber-Pulse-Bridge muss aktiviert sein # (einmalige Einrichtung, siehe Tibber-Anleitung). Benutzer ist "admin", # das Passwort steht im QR-Code auf der Rueckseite der Bridge. # - Installierte Programme: curl, socat (z. B. "sudo apt-get install curl socat"). # od gehoert zu den coreutils und ist ueberall vorhanden. # - Root-Rechte, weil das Geraet unter /dev angelegt wird ("sudo ./tibberpulse2serial.sh"). # # Benutzung: # 1. Unten im Abschnitt "Konfiguration" die Werte anpassen. # 2. Skript ausfuehrbar machen: chmod +x tibberpulse2serial.sh # 3. Starten: sudo ./tibberpulse2serial.sh # 4. Beenden mit Strg-C. # # Schnelltest ohne vzLogger: das Skript in einem Terminal starten und in einem # zweiten Terminal die rohen Telegramme mitlesen: # cat /dev/ttyTibber | od -A x -t x1z # Bei jedem Abfrageintervall erscheint ein SML-Telegramm, das mit den Bytes # 1b 1b 1b 1b beginnt. Kommt nichts, stimmen IP/Node/Benutzer/Passwort nicht # oder der lokale Webserver der Bridge ist nicht aktiviert. # # vzLogger-Beispiel (Ausschnitt der vzlogger.conf) fuer das angelegte Geraet: # "protocol": "sml", "device": "/dev/ttyTibber", "baudrate": 9600, "parity": "8n1" # # Dieses Skript ist bewusst einfach gehalten und hat keinerlei Bezug zu LoxBerry: # keine Konfigurationsdatei, kein Logfile. set -u # ============================ Konfiguration ============================ HOST="192.168.1.50" # IP-Adresse (oder Hostname) der Tibber-Pulse-Bridge NODE="1" # Node-Nummer (bei nur einem Zaehler meist 1) USERNAME="admin" # Benutzername der Bridge (in der Regel "admin") PASSWORD="GEHEIM" # Passwort der Bridge (QR-Code auf der Rueckseite) DEVICE="/dev/ttyTibber" # virtuelles serielles Geraet, das angelegt wird INTERVAL=3 # Sekunden zwischen zwei Abfragen TIMEOUT=4 # curl-Timeout je Abfrage in Sekunden # ====================================================================== # ---- Vorpruefungen --------------------------------------------------- if [ "$(id -u)" -ne 0 ]; then echo "Bitte als root starten (sudo): das Geraet wird unter /dev angelegt." >&2 exit 1 fi command -v curl >/dev/null 2>&1 || { echo "curl wird benoetigt: sudo apt-get install curl" >&2; exit 1; } command -v socat >/dev/null 2>&1 || { echo "socat wird benoetigt: sudo apt-get install socat" >&2; exit 1; } # ---- curl-Konfigurationsdatei (haelt das Passwort aus der Prozessliste) ---- # Statt das Passwort als Kommandozeilen-Argument zu uebergeben (waere in # "ps" sichtbar), schreiben wir URL und Zugangsdaten in eine temporaere, # nur fuer uns lesbare Datei und uebergeben sie curl mit -K. CURLCFG="$(mktemp)" TMPBIN="$(mktemp)" chmod 600 "$CURLCFG" # Sonderzeichen (\ und ") im Passwort fuer die curl-Konfig maskieren. esc_pw=$(printf '%s' "$PASSWORD" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g') { printf 'url = "http://%s/data.json?node_id=%s"\n' "$HOST" "$NODE" printf 'user = "%s:%s"\n' "$USERNAME" "$esc_pw" } > "$CURLCFG" cleanup() { rm -f "$CURLCFG" "$TMPBIN" "$DEVICE" 2>/dev/null pkill -P $$ 2>/dev/null } trap cleanup EXIT INT TERM mkdir -p "$(dirname "$DEVICE")" echo "Tibber-Pulse-Bridge : http://$HOST/data.json?node_id=$NODE" echo "Serielles Geraet : $DEVICE" echo "Abfrageintervall : ${INTERVAL}s (Strg-C zum Beenden)" echo # ---- Eine Abfrage: SML-Telegramm holen und weiterreichen ------------- # Nur echte SML-Telegramme (Startkennung 1b1b1b1b) werden weitergegeben; # HTML-Fehlerseiten o. Ae. werden verworfen. Meldungen gehen nach stderr, # damit sie nicht in den Datenstrom (stdout -> socat) geraten. fetch_one() { if curl -sS --max-time "$TIMEOUT" -K "$CURLCFG" -o "$TMPBIN" 2>/dev/null \ && [ -s "$TMPBIN" ] \ && [ "$(od -An -tx1 -N4 "$TMPBIN" | tr -d ' \n')" = "1b1b1b1b" ]; then cat "$TMPBIN" || return 1 # return 1 = Leser (socat) ist weg else echo "$(date '+%H:%M:%S') Bridge nicht erreichbar oder keine SML-Daten - neuer Versuch..." >&2 fi return 0 } # socat legt das PTY an und wartet auf einen Leser (wait-slave); trennt sich # der Leser (z. B. vzLogger-Neustart), endet socat und die aeussere Schleife # legt das Geraet fuer den naechsten Leser neu an. while true; do while fetch_one; do sleep "$INTERVAL" done | socat -u - "PTY,link=$DEVICE,raw,echo=0,mode=0666,wait-slave" sleep 1 done