Smarthome: AVM-Steckdosen per Skript auslesen

Zusammenfassung

In diesem Artikel stelle ich ein bash-Skript vor, mit welchem man Smart-Home-Daten der Steckdosen FRITZ!DECT 200 oder FRITZ!DECT 210 aus einer FRITZ!Box der Firma AVM auslesen kann. Ein weiteres Skript bedient sich des ersten Skripts und speichert Daten in einer einfachen MySQL-Datenbank.

Voraussetzungen

  • Es wird eine der neueren FRITZ!Boxen der Firma AVM mit aktueller Firmware eingesetzt. Eine 7490 ist zählt bereits als eine der “neueren” Boxen; insofern stehen die Chancen gut, dass viele Interessenten dieses Skript einsetzen können.
  • Es werden eine oder mehrere der AVM-Steckdosen FRITZ!DECT 200 oder FRITZ!DECT 210 eingesetzt. Mit diesen ist das Skript erfolgreich getestet worden.
  • Getestet wurde mit einer schon älteren FRITZ!Box 7490 und der Firmware 7.57.
  • Idealerweise hat man einen dauerhaft laufenden kleinen Linux-Server, auf dem die hier gezeigten Skripte und die MySQL-Datenbank laufen können.

Beschreibung und Nutzung

Die beiden AVM-Steckdosen FRITZ!DECT 200 oder FRITZ!DECT 210 sind, in Verbindung mit einer der neueren FRITZ!-Boxen, eine sehr gute Möglichkeit zur Steuerung von Strom-Verbrauchen und -Erzeugern und zur Leistungs-, Energie- und Temperaturmessung. Die Steckdosen messen dabei die durchfließende Leistung unabhängig von der Richtung und können daher auch sehr gut zur Erfassung der Stromerzeugung bei Balkon-Kraftwerken benutzt werden.

Wenn die FRITZ!Box konfiguriert wird, legt sie einen Standardbenutzer fritzxxxx an, sofern man den Login mit lediglich einem Passwort aus dem Heimnetzwerk erlaubt hat. In der FRITZ!Box findet man diesen Benutzer auf der Seite SystemFRITZ!Box-Benutzer. Dieser Benutzer sollte für unsere Zwecke die Rechte Smart Home haben. Bei mir sieht das so aus:

Rechte des Standard FRITZ!-Benutzers in meiner FRITZ!-Box

Die üder das Protokoll DECT verbundenen Smarthome-Geräte findet man in der FRITZ!-Box auf der Seite Smart Home → Geräte und Gruppen.

Übersicht der Smart-Home-Geräte und -Gruppen

Klickt man auf ein Gerät, so findet man in den Konfigurationseinstellungen, dann findet man die Aktor Identifikationsnummer (AIN) des entsprechenden Geräts. Diese wird für das Skript benötigt. Man beachte, dass es sich um zwei Zahlenblöcke handelt, die durch genau ein Leerzeichen getrennt sind.

Aktor Identifikationsnummer (AIN) eines Smart-Home-Geräts

Im folgenden Skript sind die AINs meiner vier Steckdosen mit den bei diesen Modellen möglichen Abfragen für Leistung, Energie, Temperatur und Spannung eingetragen. Das Skript basiert auf einer Vorlage aus [1], die aber nach einem Firmware-Update nicht mehr richtig funktionierte, weswegen ich Änderungen durchgeführt habe. Dabei habe ich mich an der technischen Dokumentation aus [2], [3] orientiert. Man muss natürlich noch die IP-Adresse seiner FRITZ!-Box (hier mit 192.168.2.8 angenommen), den Benutzernamen (USER) und das Passwort (PASS) anpassen.

Der erste Teil des Skripts erzeugt eine gültige Session ID, die man im Verlauf der eigentlichen Abfrage benötigt. Das Vorgehen dazu ist in [2] beschrieben; im Wesentlichen müssen Zeichenfolgen ausgewertet werden, zwischendrin muss mal auf UTF-16LE-Codierung gewechselt werden, und es müssen auch noch der Benutzername und das Passwort übermittelt werden.

Im zweiten Teil nutzen wir die Session ID und fragen eines der vier Geräte und eines der vier möglichen Argumente ab. Aufgerufen wird das Skript (es heißt bei mir “avm_smartsocket.sh”) mit:

./avm_smartsocket.sh Fernseher|Solaranlage|Wärmepumpe|Entfeuchter energy|power|temperature|voltage

Ich denk, durch die klare Struktur lässt sich das Skript auch sehr leicht für eigene Zwecke anpassen.

#!/bin/bash
#
# https://raspberrypiandstuff.wordpress.com/2017/08/03/reading-the-temperature-from-fritzdect-devices/
# modified by Gabriel Rüeck, 2023-12-06
#
# -----------
# definitions
# -----------
readonly TERM_LRED='\e[91m'
readonly TERM_RESET='\e[0m'
readonly FBF="http://192.168.2.8"
readonly USER="fritz1234"
readonly PASS="geheimes_fritzbox_passwort"
# -------------------
# check for arguments
# -------------------
if [ $# -lt 2 ]; then
   echo -e "${TERM_LRED}Call the function with ${0} Fernseher|Solaranlage|Wärmepumpe|Entfeuchter energy|power|temperature|voltage.${TERM_RESET}\n"
   exit 1
fi
# ---------------
# fetch challenge
# ---------------
CHALLENGE=$(curl -s "${FBF}/login_sid.lua" | grep -Po '(?<=<Challenge>).*(?=</Challenge>)')
# -----
# login
# -----
MD5=$(echo -n ${CHALLENGE}"-"${PASS} | iconv -f UTF-8 -t UTF-16LE | md5sum -b | awk '{print substr($0,1,32)}')
RESPONSE="${CHALLENGE}-${MD5}"
SID=$(curl -i -s -k -d "response=${RESPONSE}&username=${USER}" "${FBF}/login_sid.lua" | sed -n 's/.*<SID>\([[:xdigit:]]\+\)<\/SID>.*/\1/p')
# ----------
# define AIN
# ----------
case "${1}" in
  Fernseher)        AIN="11630%200239598";;
  Solaranlage)      AIN="11657%200732166";;
  Wärmepumpe)       AIN="11630%200325768";;
  Entfeuchter)      AIN="11630%200325773";;
  *)                exit 1;;
esac
# ------------
# fetch values
# ------------
case "${2}" in
  energy)       RESULT=$(curl -s ${FBF}'/webservices/homeautoswitch.lua?ain='${AIN}'&sid='${SID}'&switchcmd=getswitchenergy');;
  power)        RESULT=$(curl -s ${FBF}'/webservices/homeautoswitch.lua?ain='${AIN}'&sid='${SID}'&switchcmd=getswitchpower');;
  temperature)  RESULT=$(curl -s ${FBF}'/webservices/homeautoswitch.lua?ain='${AIN}'&sid='${SID}'&switchcmd=gettemperature')
                [[ ${RESULT} -lt 0 ]] && RESULT=0;;
  voltage)      RESULT=$((curl -s ${FBF}'/webservices/homeautoswitch.lua?ain='${AIN}'&sid='${SID}'&switchcmd=getdevicelistinfos') |  sed -n 's/.*<voltage>\(.*\)<\/voltage>.*/\1/p');;
  *)            exit 1;;
esac
# -------------
# output values
# -------------
echo ${RESULT}

Wichtig ist noch wissen, welche Werte wir jeweils erhalten, und das sind bei den AVM-Steckdosen FRITZ!DECT 200 oder FRITZ!DECT 210:

ArgumentAngezeigtes Resultat
powerMomentane Leistung in mW
energyAkkumulierte Energiemenge in Wh
temperatureMomentane Temperatur in 0,1 °C (Beispiel: 65 ≙ 6,5 °C)
voltageMomentane Netzspannung in mV
Argumente und deren Resultate bei der Abfrage der Steckdosen FRITZ!DECT 200 oder FRITZ!DECT 210

Nun wollen wir mit dem oben gelisteten Skript Daten der Steckdose Solaranlage auslesen und in einer MySQL-Datenbank speichern. Dazu setzen wir eine kleine und sehr einfache Datenbank auf:

# Datenbank für Analysen der Solaranlage
# V1.0; 2023-05-01, Gabriel Rüeck <gabriel@rueeck.de>, <gabriel@caipirinha.spdns.org>
# Create a new database
CREATE DATABASE solaranlage DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL ON solaranlage.* TO 'gabriel';
USE solaranlage;
SET default_storage_engine=Aria;

CREATE TABLE anlage          (zeitstempel    TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\
                              leistung       INT UNSIGNED DEFAULT NULL,\
                              energie        INT UNSIGNED DEFAULT NULL);

Zugegebenermaßen ist das CHARSET der Datenbank ziemlich egal; man hätte nicht unbedingt noch utf8mb4 vorsehen müssen. Ich setze das aber generell für meine Datenbanken, nachdem ich mal längere Zeit nach einem Fehler in einer komplexeren Datenbank gesucht hatte und dann lernen musste, dass UTF-8 bei MySQL nicht automatisch alle UTF-8-Zeichen beinhaltet [4].

Der Zeitstempel muss beim Beschreiben der Datenbank nicht explizit gesetzt werden; per Default wird der momentane Zeitstempel des Datenbank-Servers benutzt.

Das nun folgende Skript nutzt unser erstes Skript, liest Daten für Leistung und Energie aus und speichert sie in der MySQL-Datenbank:

#!/bin/bash
#
# Dieses Skript liest die Leistung und die erzeugte Energiemenge der Solaranlage und speichert das Ergebnis in einer MySQL-Datenbank ab.
#
# V1.0; 2023-05-01, Gabriel Rüeck <gabriel@rueeck.de>, <gabriel@caipirinha.spdns.org>
#
# CONSTANTS
declare -r    MYSQL_DATABASE='solaranlage'
declare -r    MYSQL_SERVER='localhost'
declare -r    MYSQL_USER='gabriel'
declare -r    MYSQL_PASS='geheimes_mysql_passwort'
declare -r    READ_SCRIPT='~/avm_smartsocket.sh'

# VARIABLES
declare -i power energy

# PROGRAM
power=$(${READ_SCRIPT} Solaranlage power)
energy=$(${READ_SCRIPT} Solaranlage energy)
mysql --default-character-set=utf8mb4 -B -N -r -D "${MYSQL_DATABASE}" -h ${MYSQL_SERVER} -u ${MYSQL_USER} -p ${MYSQL_PASS} -e "INSERT INTO anlage (leistung,energie) VALUES (${power},${energy});"

Abhängig davon, wie oft man dieses Skript laufen lässt und Daten abspeichern lässt, ergeben sich dann im folgenden Beispiel genannten Einträge in der Datenbank:

Auszug aus den Datenbank-Daten (Ansicht in der MySQL Workbench)

Diese Daten können dann in anderen Systemen ausgewertet und visualisiert werden.

Zusammenfassung

In diesem einfachen Beispiel sieht man, wie man Smart-Home-Daten der Steckdosen Fritz!DECT 200 oder Fritz!DECT 210 aus einer FRITZ!-Box der Firma AVM abfragen und sich die Daten in einer MySQL-Datenbank zur weiteren Verwendung speichern kann. Sicherlich lässt sich dieses Prinzip auch auf Smart-Home-Geräte anderer Hersteller anwenden, sofern deren Schnittstellen hinreichend offen und beschrieben sind.

Quellenangaben

Disclaimer

  • Der Programmcode und die Beispiele sind lediglich zu Demonstrationszwecken gedacht.
  • Der Programmcode wurde nicht auf Geschwindigkeit optimiert (Es ist sowieso ein Bash-Skript, da darf man keine Wunder erwarten.).
  • Der Programmcode wurde nicht unter dem Gesichtspunkt der Cybersicherheit geschrieben. Für den Einsatz in Produktivumgebungen müssen möglicherweise Anpassungen vorgenommen werden.
  • Der Programmcode wurde zwar getestet, kann aber dennoch Fehler enthalten.
Posted on: 2023-12-09Gabriel Rüeck