Python und Smart Home – Part 1 – Zugriff auf die Fritz!Box und AVM Smart Home Geräte

Wenn man Smart Home oder Internet der Dinge (IoT) hört, denkt man vielleicht an eine hoch automatisierte, technisierte Wohnung oder Haus. Da wird vielleicht das Leben oder die Lebensqualität gefördert und geregelt, vielleicht die Sicherheit erhöht. Um vieles muss der Mensch sich nicht mehr kümmern. Manches ist schon möglich, vieles ist aber noch Zukunftsmusik.

Hier wollen wir, oder ich, aber mal klein anfangen. Viele haben zuhause eine Fritz!Box stehen, die für den Online-/Internet-Zugang sowie Festnetz-Telefonie über DSL/Kabel/Glasfaser zuständig ist. Bei den ersten Fritz!Boxen war auch nicht mehr verlangt, als für alle Computer zuhause eine Internet-Verbindung bereit zu stellen und für Festnetz-Telefonie zu sorgen.

Aktuell werkelt bei uns eine Fritz!Box 7490 und mit der Zeit haben wir schon einiges daran „angeschlossen“… Unsere ersten Smart Home-Geräte (farbige WLAN-LED-Lampen und WLAN-Steckdosen) gehörten noch nicht ins AVM Smart Home Universum und auch das aktuelle Licht-System werden hier erst mal außer Acht gelassen. Beschränken wir uns auf die Fritz!Box und die AVM DECT Smart Home Geräte.

Nun stellt sich die Frage: Ich habe ein bisschen programmieren gelernt (Java, Python, …) und wie bekomme ich nun Zugriff auf die Fritz!Box sowie die angeschlossenen Geräte (z.B. die Lampe FRITZ!DECT 500 oder Steckdosen FRITZ!DECT 200/210)? Vor einiger Zeit fand ich dann erste Infos bei YouTube zur FritzConnection… Die FritzConnection Bibliothek für Python dient der Kommunikation mit der Fritz!Box über das TR-064 Protokoll. Die Bibliothek gibt es schon einige Jahre und aktuell in der Version 1.12.0 ( https://fritzconnection.readthedocs.io/en/1.12.0/index.html ) verfügbar. Mittels Google Translate kann man die Webseite auch gut ins Deutsche übersetzen.

Alles, was gemacht werden muss, um mit Python und der Bibliothek auf die Fritz!Box und die Geräte zuzugreifen, ist sehr gut erklärt. Nur kurz: Neben Python (bei mir Python 3.11.3) ist FritzConnection (v1.12.0) zu installieren. Dann sind noch Einstellungen in der Fritz!Box (http://fritz.box/) zu ändern (unter Netzwerkeinstellungen siehe https://fritzconnection.readthedocs.io/en/1.12.0/sources/getting_started.html). Falls es nicht auftaucht, gerne die „Erweiterte Ansicht“ in der Fritz!Box einschalten! Außerdem gibt es auf der FritzConnection-Webseite auch einige Beispiel-Abfragen und -Progrämmchen.

Um die API-Zugriffe der eigenen Fritz!Box zu erfahren, kann man über die Eingabeaufforderung (Achtung, nicht in der Python-Shell!) den Befehl

 

$ fritzconnection -i 192.168.178.1 -c > api.txt

ausführen. Dann bekommt man eine ausführliche Textdatei mit den verfügbaren API-Aufrufen der eigenen Fritz!Box aufgelistet. Alle Angaben und Programme beruhen jetzt auf unserer Fritz!Box 7490 mit der Firmware Fritz!OS 7.29!

Als erstes fragen wir nun mal ein paar Statistische Werte ab, wie welche Box habe ich mit welcher Firmware, welche IP-Adressen (IPv4 und IPv6) hat die Box und wie schnell ist die DSL-Leitung und was gönnt mir mein Provider. Dazu wird die IP-Adresse der Fritz!Box abgefragt. Ist es die Standard-IP kann hier eine 0 eingetragen werden. Dann noch das Passwort für die Box. Ein Benutzername ist hier noch nicht nötig. Falsche Werte werden noch nicht abgefangen und falls die Box überhaupt nicht Online ist gibt es Fehlermeldungen und -Codes der Bibliothek! Zur Kontrolle der Daten kann man alles über die Weboberfläche der Fritz!Box (http://fritz.box/) nachsehen.

 

 

from fritzconnection import FritzConnection

# Standard-IP-Adresse eine FritzBox
# ip_address = '192.168.178.1'


# Eingabe der IP-Adresse der FritzBox und des Passwortes (beides Strings)
ip_address = input("IP-Adresse der Fritz!Box? (0 für Default-Wert 192.168.178.1)   ")
if ip_address == '0':
    ip_address = '192.168.178.1'

# Eingabe des Fritz!Box Passwortes
fb_password = input("Wie lautet das Passwort?  ")

print(" ")
print(60* "#")

# Abfrage Fritz!Box Modell und Firmware und Instanz (fc) erstellen
fc = FritzConnection(address=ip_address ,password=fb_password)
print(fc)

# Geschwindigkeit des DSL-Anschlusses abfragen
downstream = fc.call_action('WANDSLInterfaceConfig', 'GetInfo')['NewDownstreamCurrRate']
max_downstream = fc.call_action('WANDSLInterfaceConfig', 'GetInfo')['NewDownstreamMaxRate']
upstream = fc.call_action('WANDSLInterfaceConfig', 'GetInfo')['NewUpstreamCurrRate']
max_upstream = fc.call_action('WANDSLInterfaceConfig', 'GetInfo')['NewUpstreamMaxRate']
print(60* "=")
print("Leistungskapazität der DSL-Leitung:")
print("Downstream:  ", max_downstream, " kbit/s")
print("Upstream:     ", max_upstream, " kbit/s")
print(60* "-")
print("Von Ihrem Provider laut Tarif zur Verfügung gestellte Geschwindigkeiten:")
print("Download:    ", downstream, " kbit/s")
print("Upload:       ", upstream, " kbit/s")
print(60* "=")
print(" ")

# Abfragen der IP-Adressen
print("Aktuelle IP-Adressen der Fritz!Box:")
external_ip_address = fc.call_action('WANIPConn1','GetExternalIPAddress')['NewExternalIPAddress']
print("aktuelle IPv4 - IP-Adresse: ", external_ip_address)
external_ipv6_address = fc.call_action('WANIPConn1','X_AVM_DE_GetExternalIPv6Address')['NewExternalIPv6Address']
print("aktuelle IPv6 - IP-Adresse: ", external_ipv6_address)

 

Screenshot der Python-Programmausgabe der FRITZ!Box
Ausgabe des Python-Programms: Abfrage der FRITZ!Box

Wenden wir uns nun den Smart Home-Produkten von AVM zu. Die Fritz!Box dient zum einen für Schnurlostelefone als DECT-Basisstation und zum anderen über DECT als Smart Home-Basis. Lange Zeit hatten wir nur eine FRITZ!DECT 500 LED-Lampe angeschlossen. Nicht wirklich viel Smart Home und eigentlich nur zum Testen. Aber Mitte letzten Jahres dann eine FRITZ!DECT 200 Steckdose zum Strom sparen und die FRITZ!DECT 310 und 320 Heizkörperthermostate sowie einige FRITZ!DECT 440-Schalter dazu. So sind nun aktuell 11 Geräte im Smart Home-Bereich der Fritz!Box eingetragen.

Um nun auf die FRITZ!DECT 500 LED-Lampe (kurz Lampe) zugreifen zu können, brauchen wir von der Lampe Informationen: Die AIN. AIN steht für „Aktor Identifikationsnummer“ und besteht aus einer Zahl mit zwei Blöcken (Block 1 fünfstellig und Block 2 siebenstellig) getrennt durch ein Leerzeichen. Von AIN, bzw. Gerätekennung wird auch in der FritzConnection-Anleitung gesprochen. Bei den Heizkörperthermostaten steht statt AIN aber IPEI (Identifikationsnummer) in der Weboberfläche der Fritz!Box, ist aber für die Programmierung erst mal egal. Die nötige AIN können wir nun über die Weboberfläche der Fritz!Box in der Geräteverwaltung auslesen oder über einen Befehl in der Eingabeaufforderung

 

$ fritzhomeauto -i 192.168.178.1 -p <password>

erfahren. Und hier in der Liste kam es zu einem Phänomen, was ich nicht beantworten kann, denn meine einzige Lampe tauchte dort zweimal auf. Mit der „normalen“ AIN und einer erweiterten AIN.

Beispiel: normale AIN: 12345 1234567, erweiterte AIN: 12345 1234567-1

Und: Mein Programm zum Ein- und Ausschalten funktioniert nur mit der erweiterten AIN! Was macht mein zweites Programm? Zuerst wieder Abfrage von Fritz!Box-IP und Passwort. Danach geht das Programm in eine while-Schleife und fragt immer wieder ab, was zu machen ist. Hier kann man über die Eingaben „an“, „aus“ und „exit“ das Programm steuern. „an“ schaltet die Lampe an, „aus“ schaltet die Lampe aus und mit „exit“ verlässt man die Schleife und das Programm. Wird irgendwas anderes eingetragen, kommt „Eingabe ungültig!“ und die Abfrage kommt wieder. Auch hier „noch“ keine Fehlerbehandlung (Exceptions) und schön wäre, das Schalten mal als Funktion implementieren. Die original-AIN habe ich gegen eine Beispiel AIN ausgetauscht.

 

from fritzconnection import FritzConnection

# Eingabe der IP-Adresse der FritzBox und des Passwortes (beides Strings)
ip_address = input("IP-Adresse der Fritz!Box? (0 für Default-Wert 192.168.178.1)   ")
if ip_address == '0':
    ip_address = '192.168.178.1'

# Eingabe des Fritz!Box Passwortes
fb_password = input("Wie lautet das Passwort?  ")

print(" ")
print(60* "#")

# Abfrage Fritz!Box Modell und Firmware und Instanz (fc) erstellen
fc = FritzConnection(address=ip_address ,password=fb_password)
print(fc)

print("Programm zum ein- und ausschalten einer Lampe an der Fritz!Box")
print("Eingaben sind: an (Lampe ein), aus (Lampe aus) und exit (Programm verlassen")

schleife = True

while schleife:
    eingabe = input("Was ist zu machen? (an/aus/exit) ")
    if eingabe == "exit" or eingabe == "EXIT" or eingabe == "Exit":
        schleife = False
    elif eingabe == "an" or eingabe == "AN" or eingabe == "An":
        print("Lampe einschalten...")
        #Lampe anschalten!
        lampe_on = fc.call_action('X_AVM-DE_Homeauto1', 'SetSwitch', NewAIN='12345 0012345-1', NewSwitchState='ON')
        #print(lampe_on) #wenn alles funktioniert, dann gibt es keinen Rückgabewert
        print("...ist an!")
    elif eingabe == "aus" or eingabe == "AUS" or eingabe == "Aus":
        print("Lampe aus!...")
        #Lampe ausschalten!
        print("Lampe ausschalten...")
        lampe_off = fc.call_action('X_AVM-DE_Homeauto1', 'SetSwitch', NewAIN='12345 0012345-1', NewSwitchState='OFF')
        #print(lampe_off)
        print("... ist aus!")
    else:
        print("Eingabe ungültig!")

print("Programmende!")

 

Aktuell lässt sich die Lampe nur ein- und ausschalten, und zwar so, wie sie beim letzten Mal geleuchtet hat (gesteuert über die Fritz!Box oder die AVM Smart Home-App). Wenn die Lampe blau leuchtete, dann blau, wenn sie weiß leuchtete, dann weiß. Ändern lässt sich die Farbe und Helligkeit wohl „noch“ nicht, jedenfalls habe ich nichts dazu gefunden.

Schalten lässt sich zum Beispiel auch die FRITZ!DECT Steckdosen 200/210. Was mich interessiert, sind die Temperaturangaben. Hier liefern die Heizkörperthermostate, die Schalter FRITZ!DECT 440 sowie die Steckdosen Temperaturwerte. Aktuell, ohne selbst zu programmieren, kann ich mir die Werte nur in schönen Diagrammen in der Fritz!Box Weboberfläche anschauen. In der Push-Nachricht der Steckdose wird auch ein Diagramm angezeigt, in der .csv-Datei stehen aber auch nur die Strom-Verbrauchswerte…

Diese Temperaturwerte regelmäßig über den Tag ausgelesen und zum Beispiel in einer Datenbank speichern wäre schön. :-)

Das war jetzt nur ein erster kleiner Einblick im Bezug auf Smart Home-Programmierung. Möglich wäre zum Beispiel für das Schalten der Lampe und der Steckdose eine Fensteranwendung (GUI) mit Tkinter zu erstellen, wo dann vielleicht auch regelmäßig die Temperaturen abgefragt und angezeigt werden…

Als nächstes wäre dann das Philips Hue Lichtsystem dran. Dafür habe ich auch ein kleines Python-Beispiel gefunden. Java-Beispiele hatte ich mal vor einiger Zeit getestet, aber wenn wir schon bei Python sind…!

Unsere aller ersten Smart Home-Geräte wie WLAN LED-Lampen und WLAN-Steckdosen sind von Luminea (Pearl). Zuerst über die io.e App angesteuert, sind sie jetzt alle in der Elesion-App drin. Eigentlich hatte ich es schon aufgegeben, irgendwie darauf mit Python (oder Java!) zugreifen zu können. Aber zufällig fand ich gestern den Hinweis, dass die Elesion-App nur eine gebrandete Tuya-App wäre! Mhm…! Und für smarte Tuya WLAN-Geräte gibt es TinyTuya (https://pypi.org/project/tinytuya/) für Python. Bevor alle Geräte aus der Elesion-App in die Tuya-App wandern um dann mit TinyTuya darauf zugreifen zu können, werde ich erst einmal mit zwei, drei Geräten (Steckdosen, Lampen, Fensterkontakte) testen!

Python wäre dann die Umgebung, wo alle meine Systeme zusammenlaufen könnten. Ich muss es dann nur programmieren… :-)

Wer sich mit Smart Home beschäftigt, wird beispielsweise auch von Matter, IFTTT, Home Connect Plus, homematic IP und natürlich Alexa und Siri gehört haben. Viele Systeme, viele Standards und noch mehr…

 

Bei Interesse der hier aufgeführten Flohmarkt-Artikel einfach bei mir melden...