Zum Inhalt springen

Tapo Kameras: Unterschied zwischen den Versionen

Aus FHEMWiki
Pahenning (Diskussion | Beiträge)
Die Seite wurde neu angelegt: „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 ang…“
 
Pahenning (Diskussion | Beiträge)
Keine Bearbeitungszusammenfassung
Zeile 75: Zeile 75:
  ./tapo_testmethod.py
  ./tapo_testmethod.py
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 ===
Das zentrale Python-Skript zur Kamerasteuerung liegt in der Datei /opt/fhem7tapo/tapo_controlpy und hat den Inhalt
<PRE>
#!/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":
        return func()
    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}")
</PRE>

Version vom 18. März 2026, 15:16 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/fhem7tapo/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":

        return func()

    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}")