Man benötigt dazu eine SessionID, die nicht trivial zu bekommen ist. Hier ein Beispiel:
menencodeUTF19_LE.py:
# the Py3 code uses an edcoding which does not produce an error in microPython - but - gives a totally different and unuseful result
def enc0(char): # first character
return bytes(str(char), 'ascii')
def enc(char): # following characters
string="\x00"+char
return bytes(string, 'ascii')
def mencodeUTF16_LE(hexString: str) -> bytes:
encoded=bytes()
encoded+=enc0(hexString[0])
i=1
while i<len(hexString):
encoded+=enc(hexString)
i+=1 # why is there no i++?
encoded+=b'\x00' # termination
return encoded
def to_hex(b: bytes) -> str: # helper
ret=''.join('{:02x}'.format(x) for x in b)
return ret
fritzactors_sample.py:
# Controlling Fritz!Box smarthome components requires obtaining a sessonID according to protocol AVM TR-064.
# If done in Python3 there is a very elegant solution on Git: Tugzrida/fritzsid.py.
# Unfortunately this does not work in microPython for several reasons.
# This is a solution including a sample component access
from md5lib import md5
from mencodeUTF16_LE import * # code is below
import requests
import network
import time
# WIFI configuration
# your SSID
wlSsid = 'xxxx' # to be replaced
# your PW
wlPw = 'yyyy' # likewise
# WIFI connection
wlan = network.WLAN(network.STA_IF)
if not wlan.isconnected():
print('Connecting...')
wlan.active(True)
wlan.connect(wlSsid, wlPw)
for i in range(10):
if wlan.status() < 0 or wlan.status() >= 3:
break
print('->', wlan.status())
time.sleep(0.5)
if wlan.isconnected():
print('Connection OK')
else:
print('No connection')
print('WIFI-Status:', wlan.status())
def actors(act): # to address multiple actors/sensors
# we assume microPython sytem is in local network, otherwise see original post
response = requests.get("http://192.168.178.1/login_sid.lua")
response_content = response.content.decode('utf-8')
ia=response_content.index("nge>")
ie=response_content.index("</Cha")
challenge=response_content[ia+4:ie]
#print(challenge)
password="zzzz" # PW for user uuuu in line 51
tmp="{}-{}".format(challenge, password)
#print(tmp)
tmp2=mencodeUTF16_LE(tmp)
h = md5()
h.update(tmp2)
hash = (h.digest())
hash = to_hex(has)
username="uuuu" # FritzBox user for this specific application
respons = "{}-{}".format(challenge, hash)
response = requests.get("http://192.168.178.1/login_sid.lua?user ... {}".format(username, respons))
response_content = response.content.decode('utf-8')
ia=response_content.index("SID>")
SID=response_content[ia+4:ia+20]
#print(SID) - we've got it
if act==x: # example to get a power value from an actor with ain <ain>, e.g. a Fritz!SmartEnergy device
# for more details see AHA-HTTP-Interface document by AVM
resp=requests.get("http://192.168.178.1/webservices/homeau ... ormat(SID))
response_content = resp.content.decode('utf-8')
if resp.status_code==200: # means OK
resp1=requests.get("http://192.168.178.1/?sid={}&security:c ... SID,"dmy")) # better logout
return(float(response_content)/1000) # power in watts
else:
return -1
Zugriff auf FriztBox SmartHome Components mit microPython (pico2W)
- DeaD_EyE
- User
- Beiträge: 1254
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Es würde helfen, wenn du den Code in Code-Tags packt, da ansonsten Tabulatoren und Leerzeichen entfernt werden, was in jedem Forum gleich ist.
[ code ] code [ /code ]
(ohne Leerzeichen zwischen den Klammern)
Bezüglich der SID könnte man regex nutzen, da Micropython keine xml-Bibliothek hat. Wäre auch viel zu groß.
Das sollte man sich auch durchlesen: https://fritz.com/fileadmin/user_upload ... ion_ID.pdf
Daher habe ich auch den Reply mit der SID. Ich habe keine FritzBox.
[ code ] code [ /code ]
(ohne Leerzeichen zwischen den Klammern)
Bezüglich der SID könnte man regex nutzen, da Micropython keine xml-Bibliothek hat. Wäre auch viel zu groß.
Code: Alles auswählen
import re
RE_SID = re.compile(r"<SID>(\w+)</SID>")
reply = """<SessionInfo>
<SID>ff88e4d39354992f</SID>
<Challenge>ab7190d6</Challenge>
<BlockTime>128</BlockTime>
<Rights>
<Name>BoxAdmin</Name>
<Access>2</Access>
<Name>Phone</Name>
</Access>2</Access>
<Name>NAS></Name>
<Access>2</Access>
</Rights>
</SessionInfo>"""
def get_sid(response):
if match := RE_SID.search(response):
return match.group(1)
return ""
Daher habe ich auch den Reply mit der SID. Ich habe keine FritzBox.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
@SRCH: wenn Du utf-16le implementieren möchtest, dann ist es unsinnig, paarweise \x00\xab zu schreiben, und das erste und letzte Byte gesondert zu behandeln, weil für little-endian die Bytepaare einfach \xab\x00 sind. Statt einer while-Schleife benutzt man for.
Konstanten schreibt man komplett groß und benutzt keine Abkürzungen, also WLAN_PASSWORD statt wlPw. Du hast die Variablen response, respon, resp und resp1, außer an der falschen Schreibweise kann man nicht erkennen, worin sie sich unterscheiden. Für verständlichen Code braucht man verständliche Namen.
`x` wird benutzt aber nirgends definiert.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, und nicht mal 4 und mal 2. Deshalb ist die Einrückung bei Deinem `break` fehlerhaft.
format benutzt man heutzutage nur selten, statt dessen f-Strings.
Das könnte entsprechend dann so aussehen:
Code: Alles auswählen
import struct
def mencodeUTF16_LE(string):
return struct.pack(f"<{len(string)}H", *map(ord, string))
`x` wird benutzt aber nirgends definiert.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, und nicht mal 4 und mal 2. Deshalb ist die Einrückung bei Deinem `break` fehlerhaft.
format benutzt man heutzutage nur selten, statt dessen f-Strings.
Das könnte entsprechend dann so aussehen:
Code: Alles auswählen
LOGIN_URL = "http://192.168.178.1/login_sid.lua"
...
code = mencodeUTF16_LE(f"{challenge}-{password}")
hash = binascii.hexlify(md5(code).digest()).decode()
response = f"{challenge}-{hash}"
login_response = requests.get(f"{LOGIN_URL}?username={username}&response={response}")
response_content = login_response.text