[Info] AHA HTTP Interface

Odium

Neuer User
Mitglied seit
22 Sep 2007
Beiträge
49
Punkte für Reaktionen
7
Punkte
8
Anbei ein schmales Python Script zum Auslesen der SmartHome Geräte über das AVM Home Automation HTTP Interface (AHA HTTP Interface). Die Anmeldung erfolgt per MD5 oder PBKDF2 Methode. Für das Auslesen reichen Benutzerrechte "SmartHome" aus.
Das Script zeigt aktuell nur Details für Heizkörperregler, Schaltaktoren und Taster an. Weitere Geräte müssten mit Anpassung weiterer IF-Abfragen ergänzt werden. "Getdevicelistinfos" übermittelt auch Geräteinformationen von den Geräten, die am FRITZ!Smart Gateway angemeldeten sind.

Python:
#!/usr/bin/env python3

#Import
import requests, hashlib, re

# URL der Fritzbox
fritzbox_url = "http://192.168.178.1"

# Benutzername
Username = "User"

# Passwort
Password = "123456"

# Anmeldemethode
#version=1 ist MD5
#version=2 ist PBKDF2
version = 2

# Linie ziehen
print ("------------------------------------------------------------------------")

# Anmeldemethode mit PBKDF2 
# ========================================================================================================================== 
if version == 2:
        
        #Payload erzeugen 
        request_payload = {'version': '2'}

        # Anfrage starten
        request_result = requests.get(fritzbox_url + "/login_sid.lua", params=request_payload)

        # Zum Debuggen, alles Ausgeben
        #print (request_result.text)

        # Daten herausfiltern
        SID = str((request_result.text).split("<SID>")[1].split("</SID>")[0])
        BlockTime = int((request_result.text).split("<BlockTime>")[1].split("</BlockTime>")[0])
        Challenge = str((request_result.text).split("<Challenge>")[1].split("</Challenge>")[0])

        if SID == '0000000000000000':

                # SID ist 0, daher Response Erzeugen und neu anfordern: Berechnung mit PBKDF2
                Challenge_split = Challenge.split("$")
                #notused = int(Challenge_split[0])
                iter1 = int(Challenge_split[1])
                salt1 = bytes.fromhex(Challenge_split[2])
                iter2 = int(Challenge_split[3])
                salt2 = bytes.fromhex(Challenge_split[4])
                hash1 = hashlib.pbkdf2_hmac("sha256", Password.encode(), salt1, iter1)
                hash2 = hashlib.pbkdf2_hmac("sha256", hash1, salt2, iter2)
                Response = Challenge_split[4] + "$" + hash2.hex()
                
                # Daten erstellen für POST
                request_data = {"username": Username, "response": Response}
                
                # Header erstellen
                request_headers = {"Content-Type": "application/x-www-form-urlencoded"}
                
                # Und Daten anfordern
                request_result = requests.post(fritzbox_url + "/login_sid.lua", data=request_data, headers=request_headers)

                # Zum Debuggen, alles Ausgeben
                #print (request_result.text)

                SID = str((request_result.text).split("<SID>")[1].split("</SID>")[0])
                BlockTime = int((request_result.text).split("<BlockTime>")[1].split("</BlockTime>")[0])
                Name = str((request_result.text).split("<Name>")[1].split("</Name>")[0])
                Access = int((request_result.text).split("<Access>")[1].split("</Access>")[0])
                
                # Ausgabe der einzelnen Variablen
                print ("Challenge:            ",Challenge)
                print ("Response:             ",Response)
                print ("SID:                  ",SID)
                print ("BlockTime:            ",BlockTime)
                print ("Name:                 ",Name)
                print ("Access:               ",Access)
                
        else:
                # Ausgabe der einzelnen Variablen
                print ("SID:                  ",SID)
                print ("BlockTime:            ",BlockTime)

# Anmeldemethode mit MD5 
# ==========================================================================================================================
if version == 1:
        
        #Payload erzeugen 
        request_payload = {'version': '1'}

        # Anfrage starten
        request_result = requests.get(fritzbox_url + "/login_sid.lua", params=request_payload)

        # Zum Debuggen, alles Ausgeben
        #print (request_result.text)

        # Daten herausfiltern
        SID = str((request_result.text).split("<SID>")[1].split("</SID>")[0])
        BlockTime = int((request_result.text).split("<BlockTime>")[1].split("</BlockTime>")[0])
        Challenge = str((request_result.text).split("<Challenge>")[1].split("</Challenge>")[0])

        if SID == '0000000000000000':

                # SID ist 0, daher Response Erzeugen und neu anfordern: Berechnung mit MD5
                MD5 = hashlib.md5((Challenge + "-" + Password).encode("utf_16_le")).hexdigest()
                Response = Challenge + "-" + MD5
                
                # Daten erstellen für POST
                request_data = {"username": Username, "response": Response}
                
                # Header erstellen
                request_headers = {"Content-Type": "application/x-www-form-urlencoded"}
                
                # Und Daten anfordern
                request_result = requests.post(fritzbox_url + "/login_sid.lua", data=request_data, headers=request_headers)

                # Zum Debuggen, alles Ausgeben
                #print (request_result.text)

                SID = str((request_result.text).split("<SID>")[1].split("</SID>")[0])
                BlockTime = int((request_result.text).split("<BlockTime>")[1].split("</BlockTime>")[0])
                Name = str((request_result.text).split("<Name>")[1].split("</Name>")[0])
                Access = int((request_result.text).split("<Access>")[1].split("</Access>")[0])
                
                # Ausgabe der einzelnen Variablen
                print ("Challenge:            ",Challenge)
                print ("MD5:                  ",MD5)
                print ("Response:             ",Response)
                print ("SID:                  ",SID)
                print ("BlockTime:            ",BlockTime)
                print ("Name:                 ",Name)
                print ("Access:               ",Access)
                
        else:
                # Ausgabe der einzelnen Variablen
                print ("SID:                  ",SID)
                print ("BlockTime:            ",BlockTime)

# Getdevicelistinfos
# ==========================================================================================================================

# Linie ziehen
print ("------------------------------------------------------------------------")

# Payload erzeugen
request_payload = {'switchcmd': 'getdevicelistinfos', 'sid': SID}

# Und Daten anfordern
request_result = requests.get(fritzbox_url + "/webservices/homeautoswitch.lua", params=request_payload)

# Zum Debuggen, alles Ausgeben
#print (request_result.text)

# Teile die devices in einzelne Abschnitte
request_result_split_array = re.findall("<device (.*?)</device>", request_result.text)

for i, request_result_split in enumerate(request_result_split_array):

        # Ausgabe der einzelnen Variablen
        #print (request_result_split)
        
        device_ain = str((request_result_split).split('identifier="')[1].split('" id=')[0])
        device_id = int((request_result_split).split('id="')[1].split('" functionbitmask=')[0])
        device_function_bitmask = int((request_result_split).split('functionbitmask="')[1].split('" fwversion=')[0])
        device_firmware = str((request_result_split).split('" fwversion="')[1].split('" manufacturer=')[0])
        device_manufacturer = str((request_result_split).split('manufacturer="')[1].split('" productname=')[0])
        device_product_name = str((request_result_split).split('productname="')[1].split('"><present>')[0])
        device_device_name = str((request_result_split).split("<name>")[1].split("</name>")[0])
        device_present = str((request_result_split).split("<present>")[1].split("</present>")[0])
        device_busy = str((request_result_split).split("<txbusy>")[1].split("</txbusy>")[0])
        
        # Ausgabe der einzelnen Variablen
        print ("AIN:                  ",device_ain)
        print ("ID:                   ",device_id)
        print ("Function bitmask:     ",device_function_bitmask)
        print ("Firmware version:     ",device_firmware)
        print ("Manufacturer:         ",device_manufacturer)
        print ("Product name:         ",device_product_name)
        print ("Device name:          ",device_device_name)
        print ("Present?:             ",device_present)
        print ("TX busy:              ",device_busy)

       # ab hier unvollstaendig: nur Heizkoerperregler, Schaltaktor, Taster. Andere Geraete ergaenzen...
        if "<hkr>" in request_result_split:
                device_battery = int((request_result_split).split("<battery>")[1].split("</battery>")[0])
                device_batterylow = str((request_result_split).split("<batterylow>")[1].split("</batterylow>")[0])
                device_temperature_celsius = float((request_result_split).split("<celsius>")[1].split("</celsius>")[0])/10
                device_temperature_offset = float((request_result_split).split("<offset>")[1].split("</offset>")[0])/10
                #Temperatur-Wert in 0,5 °C, Wertebereich: 16 – 56 -> 8 bis 28°C, z.B.: 16 <= 8°C, 17 = 8,5°C...... 56 >= 28°C, 254 = ON , 253 = OFF
                device_hkr_set = float((request_result_split).split("<tsoll>")[1].split("</tsoll>")[0])/2
                device_hkr_is = float((request_result_split).split("<tist>")[1].split("</tist>")[0])/2
                device_hkr_absenk = float((request_result_split).split("<absenk>")[1].split("</absenk>")[0])/2
                device_hkr_komfort = float((request_result_split).split("<komfort>")[1].split("</komfort>")[0])/2
                device_hkr_lock = int((request_result_split).split("<lock>")[1].split("</lock>")[0])
                device_hkr_devicelock = int((request_result_split).split("<devicelock>")[1].split("</devicelock>")[0])
                device_hkr_errorcode = int((request_result_split).split("<errorcode>")[1].split("</errorcode>")[0])
                device_hkr_windowopenactiv = int((request_result_split).split("<windowopenactiv>")[1].split("</windowopenactiv>")[0])
                device_hkr_windowopenactiveendtime = int((request_result_split).split("<windowopenactiveendtime>")[1].split("</windowopenactiveendtime>")[0])
                device_hkr_boostactive = int((request_result_split).split("<boostactive>")[1].split("</boostactive>")[0])
                device_hkr_boostactiveendtime = int((request_result_split).split("<boostactiveendtime>")[1].split("</boostactiveendtime>")[0])
                device_hkr_endperiod = int((request_result_split).split("<endperiod>")[1].split("</endperiod>")[0])
                device_hkr_tchange = int((request_result_split).split("<tchange>")[1].split("</tchange>")[0])
                device_hkr_summeractive = int((request_result_split).split("<summeractive>")[1].split("</summeractive>")[0])
                device_hkr_adaptiveHeatingActive = int((request_result_split).split("<adaptiveHeatingActive>")[1].split("</adaptiveHeatingActive>")[0])
                device_hkr_adaptiveHeatingRunning = int((request_result_split).split("<adaptiveHeatingRunning>")[1].split("</adaptiveHeatingRunning>")[0])
                        
                print ("Type:                  HKR")
                print ("Battery:              ",device_battery,"%")
                print ("Battery low?:         ",device_batterylow)
                print ("Temperature:          ",device_temperature_celsius,"°C")
                print ("Temperature offset:   ",device_temperature_offset,"°C")
                print ("Temperature set:      ",device_hkr_set,"°C")
                print ("Temperature is:       ",device_hkr_is,"°C")
                print ("Temperature lowering: ",device_hkr_absenk,"°C")
                print ("Temperature comfort:  ",device_hkr_komfort,"°C")
                print ("HKR lock:             ",device_hkr_lock)
                print ("HKR devicelock:       ",device_hkr_devicelock)
                print ("HKR error:            ",device_hkr_errorcode)
                print ("HKR Window open:      ",device_hkr_windowopenactiv)
                print ("HKR Window open timer:",device_hkr_windowopenactiveendtime)
                print ("HKR Boost active:     ",device_hkr_boostactive)
                print ("HKR Boost time:       ",device_hkr_boostactiveendtime)
                print ("HKR endperiod:        ",device_hkr_endperiod)
                print ("HKR temp change:      ",device_hkr_tchange)
                print ("HKR summer active:    ",device_hkr_summeractive)
                print ("HKR adapt heating on: ",device_hkr_adaptiveHeatingActive)
                print ("HKR adapt heating run:",device_hkr_adaptiveHeatingRunning)
                
        if "<button " in request_result_split:
                device_battery = int((request_result_split).split("<battery>")[1].split("</battery>")[0])
                device_batterylow = str((request_result_split).split("<batterylow>")[1].split("</batterylow>")[0])
                                
                print ("Type:                  Button")
                print ("Battery:              ",device_battery,"%")
                print ("Battery low?:         ",device_batterylow)
                                
        if "<switch>" in request_result_split:
                device_switch_state = int((request_result_split).split("<state>")[1].split("</state>")[0])
                device_switch_mode = str((request_result_split).split("<mode>")[1].split("</mode>")[0])
                device_switch_lock = int((request_result_split).split("<lock>")[1].split("</lock>")[0])
                device_switch_devicelock = int((request_result_split).split("<devicelock>")[1].split("</devicelock>")[0])
                device_simpleonoff_state = int((request_result_split).split("<devicelock>")[1].split("</devicelock>")[0])
                device_powermeter_voltage = float((request_result_split).split("<voltage>")[1].split("</voltage>")[0])/1000
                device_powermeter_power = float((request_result_split).split("<power>")[1].split("</power>")[0])/1000
                device_powermeter_energy = float((request_result_split).split("<energy>")[1].split("</energy>")[0])/1000
                device_temperature_celsius = float((request_result_split).split("<celsius>")[1].split("</celsius>")[0])/10
                device_temperature_offset = float((request_result_split).split("<offset>")[1].split("</offset>")[0])/10
                
                print ("Type:                  Switch")
                print ("Switch state:         ",device_switch_state)
                print ("Switch mode:          ",device_switch_mode)
                print ("Switch lock:          ",device_switch_lock)
                print ("Switch devicelock:    ",device_switch_devicelock)
                print ("Simple on/off state:  ",device_simpleonoff_state)
                print ("Powermeter voltage:   ",device_powermeter_voltage,"V")
                print ("Powermeter power:     ",device_powermeter_power,"W")
                print ("Powermeter energy:    ",device_powermeter_energy,"kWh")
                print ("Temperature:          ",device_temperature_celsius,"°C")
                print ("Temperature offset    ",device_temperature_offset,"°C")

        # Linie ziehen
        print ("------------------------------------------------------------------------")

#Ende
# ==========================================================================================================================

Beschreibung:
 

Neueste Beiträge

Statistik des Forums

Themen
244,880
Beiträge
2,220,046
Mitglieder
371,605
Neuestes Mitglied
michaelwarwel
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.

IPPF im Überblick

Neueste Beiträge