Tapo Kameras: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
| (2 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 76: | Zeile 76: | ||
Man erhält auf diese Weise eine unstrukturierte Liste alle Methode, die von der Kamera akzeptiert werden. | Man erhält auf diese Weise eine unstrukturierte Liste alle Methode, die von der Kamera akzeptiert werden. | ||
=== Kontrollprogramm === | === Kontrollprogramm === | ||
Das zentrale Python-Skript zur Kamerasteuerung liegt in der Datei /opt/ | Das zentrale Python-Skript zur Kamerasteuerung liegt in der Datei /opt/fhem/tapo/tapo_controlpy und hat den Inhalt | ||
<PRE> | <PRE> | ||
#!/opt/fhem/tapo/.venv/bin/python3 | #!/opt/fhem/tapo/.venv/bin/python3 | ||
import sys import json | import sys | ||
import json | |||
from pytapo import Tapo | from pytapo import Tapo | ||
HOST = "<IPKAMERA>" | HOST = "<IPKAMERA>" | ||
| Zeile 132: | Zeile 133: | ||
tapo.moveMotor(0, -STEP) | tapo.moveMotor(0, -STEP) | ||
ok("ok down") | ok("ok down") | ||
elif cmd == "privacy_on": | elif cmd == "privacy_on": | ||
| Zeile 164: | Zeile 161: | ||
status = { | status = { | ||
"privacy": safe_call("privacy", lambda: tapo.getPrivacyMode()), | "privacy": safe_call("privacy", lambda: tapo.getPrivacyMode()), | ||
"alarm": safe_call("alarm", lambda: tapo.getAlarm()), | |||
"audio": safe_call("audio", lambda: tapo.getAudioConfig()), | "audio": safe_call("audio", lambda: tapo.getAudioConfig()), | ||
"floodlight_status": safe_call("floodlight_status", lambda: tapo.getFloodlightStatus()), | "floodlight_status": safe_call("floodlight_status", lambda: tapo.getFloodlightStatus()), | ||
Aktuelle Version vom 18. März 2026, 15:19 Uhr
Verifiziert für Tapo C530WS
Cloud-Installation
Die Kamera zunächst mit der von Tapo angegebenen App installieren und testen. Dafür muss ein Konto angelegt werden, mit Mailadresse und einem Passwort, das im Folgenden als <PWCLOUD> abgekürzt wird.
Die Kamera erhält im internen Netz eine IP-Adresse, die im Folgenden als <IPKAMERA> abgekürzt wird.
Stream und Snapshot
Hierfür muss zunächst ein so genanntes Kamera-Konto auf der Kamera angelegt werden, unter Einstellungen->Erweiterte Einstellungen. Dabei werden ein Username und ein Passwort festgelegt, die im Folgenden als <USERKAMERA> und <PWKAMERA> abgekürzt werden.
Auf dem FHEM-Server (oder einem anderen System zum Testen) muss dann die ffmpeg-Suite installiert werden.
Wenn die Kamera eingeschaltet ist, lässt sich dann der Stream der Kamera abgreifen mit
ffplay rtsp://<USERKAMERA>:<PWKAMERA>@<IPKAMERA>:554/stream1
in voller Auflösung, sowie mit reduzierter Auflösung als
ffplay rtsp://<USERKAMERA>:<PWKAMERA>@<IPKAMERA>:554/stream2
Die Erstellung eines Snapshots wird über ein Shellskript gesteuert, mit folgendem Inhalt
#!/bin/bash OUT="/opt/fhem/www/images/Tapo.jpg" URL="/fhem/images/Tapo.jpg" ffmpeg -rtsp_transport tcp -y \ -i "rtsp://<USERKAMERA>:<PWKAMERA>@<IPKAMERA>:554/stream1" \ -frames:v 1 "$OUT" >/dev/null 2>&1 if [ $? -eq 0 ] && [ -s "$OUT" ]; then echo "$URL" else echo "error creating image" fi
Für das Weitere gehen wir davon aus, dass dieses Shellskript unter /opt/fhem/tapo liegt und durch den FHEM-Prozess ausführbar ist. Wir definieren ein Dummy-Device mit zunächst minimalen Eigenschaften
defmod TapoCam dummy attr TapoCam readingList snapshot attr TapoCam setList takePhoto:noArg
sowie ein DOIF
defmod TapoCam.move.N DOIF ([TapoCam:state] =~ /^takePhoto$/) \
({my $res = qx(/opt/fhem/tapo/tapo_snapshot.sh);;\
chomp($res);;\
fhem("setreading TapoCam snapshot $res");;\
fhem("setreading TapoCam state ready")\
}\
)
mit Attribut
attr TapoCam.N do always
Dann sorgt der FHEM-Befehl
set TapoCam takePhoto
dafür, dass ein Snapshot unter /opt/fhem/www/images gespeichert wird. Im FHEMWEB Frontend ist er dann unter /fhem/images/Tapo.jpg ansehbar
TODO: Komfortabler machen
Kamerasteuerung mit Python
Zur Vorbereitung folgende Schritte ggf. mit root-Rechten unternehmen:
mkdir -p /opt/fhem/tapo cd /opt/fhem/tapo python3 -m venv .venv /opt/fhem/tapo/.venv/bin/pip install --upgrade pip /opt/fhem/tapo/.venv/bin/pip install pytapo chown -R fhem:dialout /opt/fhem/tapo chmod -R u+rwX /opt/fhem/tapo
Dadurch wird im Verzeichnis /opt/fhem/tapo eine virtuelle Umgebung für die TapoCam angelegt. Danach eine Datei /opt/fhem/tapo/tapo_testmethod.py anlegen, mit dem Inhalt
#!/opt/fhem/tapo/.venv/bin/python3
from pytapo import Tapo
tapo = Tapo("<IPKAMERA>", "admin", "<PWCLOUD>")
for m in dir(tapo):
ml = m.lower()
if any(x in ml for x in [
"light", "spot", "privacy", "mask", "alarm", "siren",
"speaker", "micro", "audio", "talk", "voice", "ring"
]):
print(m)
Wichtig: Für die Kamerasteuerung verlangt Tapo inzwischen das Cloud-Passwort und den Usernamen admin. Dieses Python-Skript ausführbar machen und ausführen:
chmod +x tapo_testmethod.py ./tapo_testmethod.py
Man erhält auf diese Weise eine unstrukturierte Liste alle Methode, die von der Kamera akzeptiert werden.
Kontrollprogramm
Das zentrale Python-Skript zur Kamerasteuerung liegt in der Datei /opt/fhem/tapo/tapo_controlpy und hat den Inhalt
#!/opt/fhem/tapo/.venv/bin/python3
import sys
import json
from pytapo import Tapo
HOST = "<IPKAMERA>"
USER = "admin"
PASSWORD = "<PWCLOUD>"
STEP = 10
def out(obj):
if isinstance(obj, (dict, list)):
print(json.dumps(obj, ensure_ascii=False))
else:
print(str(obj))
def ok(msg):
print(msg)
sys.exit(0)
def err(msg):
print(msg)
sys.exit(1)
def safe_call(label, func):
try:def safe_call(label, func):
try:
return func()
except Exception as e:
return f"error: {e}"
try:
tapo = Tapo(HOST, USER, PASSWORD)
except Exception as e:
err(f"login error: {e}")
cmd = sys.argv[1] if len(sys.argv) > 1 else ""
try:
if cmd == "left":
tapo.moveMotor(-STEP, 0)
ok("ok left")
elif cmd == "right":
tapo.moveMotor(STEP, 0)
ok("ok right")
elif cmd == "up":
tapo.moveMotor(0, STEP)
ok("ok up")
elif cmd == "down":
tapo.moveMotor(0, -STEP)
ok("ok down")
elif cmd == "privacy_on":
res = tapo.setPrivacyMode(True)
out(res)
elif cmd == "privacy_off":
res = tapo.setPrivacyMode(False)
out(res)
elif cmd == "alarm_light_enable":
res = tapo.setAlarm(True, soundEnabled=False, lightEnabled=True)
out(res)
elif cmd == "alarm_sound_enable":
res = tapo.setAlarm(True, soundEnabled=True, lightEnabled=False)
out(res)
elif cmd == "alarm_both_enable":
res = tapo.setAlarm(True, soundEnabled=True, lightEnabled=True)
out(res)
elif cmd == "alarm_off":
res = tapo.setAlarm(False)
out(res)
elif cmd == "status":
status = {
"privacy": safe_call("privacy", lambda: tapo.getPrivacyMode()),
"alarm": safe_call("alarm", lambda: tapo.getAlarm()),
"audio": safe_call("audio", lambda: tapo.getAudioConfig()),
"floodlight_status": safe_call("floodlight_status", lambda: tapo.getFloodlightStatus()),
"floodlight_config": safe_call("floodlight_config", lambda: tapo.getFloodlightConfig()),
"floodlight_capability": safe_call("floodlight_capability", lambda: tapo.getFloodlightCapability()),
}
out(status)
else:
err("unknown command")
except Exception as e:
err(f"command error: {e}")