Erste Fassung
This commit is contained in:
commit
dba0ef4a4e
29
README.md
Normal file
29
README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# fritz_temperatur
|
||||
|
||||
## Allgemein
|
||||
|
||||
Dieses Script fragt die Temperatur eines an die FritzBox angeschlossenen Sensors ab.
|
||||
|
||||
Getestet wurde es mit einer FritzBox 7390 mit FritzOS 6.83 und einem Comet DECT-Heizkörperregler.
|
||||
|
||||
Das Script benötigt folgende Parameter:
|
||||
|
||||
-H Hostname oder IP der FritzBox
|
||||
-U Benutzername zum Einloggen an der FritzBox (z.B. administrator)
|
||||
-P Das Paßwort des eben genannten Benutzers
|
||||
-A Die ID des Sensors.
|
||||
|
||||
Die Sensor-ID kann man über die Web-Oberfläche der FritzBox abfragen:
|
||||
- Menü Heimnetz => Smart Home
|
||||
- Beim gewünschten Sensor auf "Bearbeiten" (Stift-Symbol) klicken
|
||||
- Die "Identifikationsnummer" ist die benötigte ID. Leerzeichen aus der ID entfernen.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
Das Script ist in Python3 geschrieben und benötigt die folgenden Debian-Pakete:
|
||||
|
||||
* python3
|
||||
* python3-urllib
|
||||
|
||||
Getestet wurde mit Debian 8 (Jessie).
|
||||
|
127
fritz_temp
Executable file
127
fritz_temp
Executable file
@ -0,0 +1,127 @@
|
||||
#!/usr/bin/python3
|
||||
# get target temperature from AVM/Comet Dect Heizkoerperregler (Heating Device)
|
||||
# need Fritz!OS 6.50+
|
||||
|
||||
import getopt
|
||||
import re
|
||||
import requests
|
||||
import sys
|
||||
import xml.etree.ElementTree as etree
|
||||
import urllib.parse
|
||||
from hashlib import md5
|
||||
|
||||
DEBUG=False
|
||||
|
||||
def OK(text):
|
||||
print("OK: " + text)
|
||||
sys.exit()
|
||||
|
||||
def Warning(text):
|
||||
print("WARNING: " + text)
|
||||
sys.exit()
|
||||
|
||||
def Critical(text):
|
||||
print("CRITICAL: " + text)
|
||||
sys.exit()
|
||||
|
||||
def OptionsError():
|
||||
Critical("Error: not all required options are given.\n -H <hostname>\n -U <username>\n -P <password>\n -A <ID of device>")
|
||||
|
||||
def debug(text):
|
||||
if DEBUG == True:
|
||||
print("DEBUG: " + text)
|
||||
|
||||
def get_sid(loginurl, username, password):
|
||||
if not username:
|
||||
username=''
|
||||
|
||||
# get challenge string
|
||||
response = requests.get(loginurl)
|
||||
|
||||
if response.status_code == 200:
|
||||
tree = etree.fromstring(response.content)
|
||||
challenge = tree.find("Challenge").text
|
||||
sid = tree.find("SID").text
|
||||
debug("challenge: " + challenge)
|
||||
debug("sid: " + sid)
|
||||
else:
|
||||
Critical("Error: GetSid failed")
|
||||
|
||||
if len(sid) > 0 and re.search("^0+$", sid) and challenge:
|
||||
debug("Get new SID")
|
||||
# sid is null, got challenge
|
||||
sid = ""
|
||||
# build password response
|
||||
pwd = challenge + "-" + password
|
||||
# UTF-16LE encoding as required
|
||||
pwd = pwd.encode("UTF-16LE")
|
||||
# md5hash on top
|
||||
m = md5()
|
||||
m.update(pwd)
|
||||
# final answer string
|
||||
challenge_response = challenge + "-" + m.hexdigest()
|
||||
debug("challenge_response: " + challenge_response)
|
||||
# send to box
|
||||
url = loginurl + "?username=" + username + "&response=" + challenge_response
|
||||
response = requests.get(url)
|
||||
#print(response.content)
|
||||
# check answer
|
||||
tree = etree.fromstring(response.content)
|
||||
sid2 = tree.find("SID").text
|
||||
debug("SID: " + sid2)
|
||||
if (len(sid2) > 0) and not re.search("^0+$", sid2):
|
||||
# is not null, bingo!
|
||||
return sid2
|
||||
else:
|
||||
# use existing sid if sid matches an hex string
|
||||
if (len(sid) > 0) and re.search("^[0-9a-f]+$", sid):
|
||||
return sid
|
||||
|
||||
host = None
|
||||
username = None
|
||||
password = None
|
||||
ain = None
|
||||
|
||||
try:
|
||||
opts, args = getopt.gnu_getopt(sys.argv[1:], 'H:U:P:A:')
|
||||
except getopt.GetoptError as err:
|
||||
OptionsError()
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt == "-H":
|
||||
host = arg
|
||||
elif opt == "-U":
|
||||
username = arg
|
||||
elif opt == "-P":
|
||||
password = arg
|
||||
elif opt == "-A":
|
||||
ain = arg
|
||||
|
||||
if not host or not username or not password or not ain:
|
||||
OptionsError()
|
||||
|
||||
# build urls and login
|
||||
# - login_sid.lua for fritzos 5.50+
|
||||
loginurl = "http://" + host + "/login_sid.lua"
|
||||
ahaurl = "http://" + host + "/webservices/homeautoswitch.lua"
|
||||
sid = get_sid(loginurl, username, password);
|
||||
if not sid:
|
||||
Critical("Error: Login invalid or failed")
|
||||
|
||||
#query actual state
|
||||
rain = urllib.parse.quote(ain)
|
||||
url = ahaurl + '?ain=' + rain + '&sid=' + sid + '&switchcmd=gettemperature';
|
||||
|
||||
http_response = requests.get(url)
|
||||
|
||||
if http_response.status_code == 200:
|
||||
# check answer
|
||||
answer = http_response.content.decode().strip()
|
||||
debug("Antwort: " + answer)
|
||||
temperatur = float(answer) / 10
|
||||
temp_str = "{0:<3.1f}".format(temperatur)
|
||||
OK("Temperatur: " + temp_str + " | temp=" + temp_str)
|
||||
else:
|
||||
Critical("Error: Query failed.")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user