Camera Tapo C200 Positions pédéfinies

Bonjour la communité,

Voilà 2 jours et 2 nuits que j’avance à pas de fourmis pour controller les PTZ de ma caméra Tapo C200.
J’ai réussi à controller les mouvements grace à beaucoup de copier/coller et des dixaines d’heures de lecture. En revenche j’essaie de comprendre la logique entre le script à créer et la bibliotheque (si c’est comme ça qu’on dit).

Je tente de déplacer ma camera dans des positions définie sur l’application voila le script que je lance mais qui ne fonctionne pas :

#!/usr/bin/env python3

from pytapo import Tapo
import sys

def setPreset(presetID) :
    user="XXXX"
    password="XXXX"
    host="192.168.1.67"
    tapo2=Tapo(host, user, password)
    res ={}
    try :
        res = tapo2.setPreset(1)
    except Exception :
        print("Oops!  Tu es au bout Jacquie")
        res["error_code"] =-1

    if(res.get("error_code")==0) :
        return 1
    else :
        return -1
#print (goto_preset())
print(sys.argv[1])
goto_preset(sys.argv[1])

Voici l’erreur :

Erreur sur /var/www/html/plugins/script/data/camtestbas.PY move 2>&1 valeur retournée : 1. Détails : move Traceback (most recent call last): File "/var/www/html/plugins/script/data/camtestbas.PY", line 24, in goto_preset(sys.argv[1]) NameError: name 'goto_preset' is not defined

Je précise n’avoir aucune connaissances en codage. Je me suis inspiré du script qui fonctionne pour faire bouger la caméra que voici :

from pytapo import Tapo
import sys

def  move(x) :
    user="xxx"
    password="xxx"
    host="xxx"
    tapo2=Tapo(host, user, password)
    res ={}
    try :
        res = tapo2.moveMotor(x,0)
    except Exception :
        print("Oops!  Tu es au bout Jacquie")
        res["error_code"] =-1

    if(res.get("error_code")==0) :
        return 1
    else :
        return -1

#print (move())
#print(sys.argv[1])
move(sys.argv[1])

et tiré de ce post qui m’à bien aidé :

Merci d’avance

1 « J'aime »

bonsoir,
est tu bien sur que goto_preset existe dans ta librairie ?

Je ne suis pas expert mais il semble que oui.

#
# Author: See contributors at https://github.com/JurajNyiri/pytapo/graphs/contributors
#

import hashlib
import json

import requests
import urllib3

from .const import ERROR_CODES
from .media_stream.session import HttpMediaSession

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class Tapo:
    def __init__(self, host, user, password, cloudPassword=""):
        self.host = host
        self.user = user
        self.password = password
        self.cloudPassword = cloudPassword
        self.stok = False
        self.userID = False
        self.headers = {
            "Host": self.host,
            "Referer": "https://{host}".format(host=self.host),
            "Accept": "application/json",
            "Accept-Encoding": "gzip, deflate",
            "User-Agent": "Tapo CameraClient Android",
            "Connection": "close",
            "requestByApp": "true",
            "Content-Type": "application/json; charset=UTF-8",
        }
        self.hashedPassword = hashlib.md5(password.encode("utf8")).hexdigest().upper()
        self.hashedCloudPassword = (
            hashlib.md5(cloudPassword.encode("utf8")).hexdigest().upper()
        )

        self.basicInfo = self.getBasicInfo()
        self.presets = self.isSupportingPresets()
        if not self.presets:
            self.presets = {}

    def isSupportingPresets(self):
        try:
            presets = self.getPresets()
            return presets
        except Exception:
            return False

    def getHostURL(self):
        return "https://{host}/stok={stok}/ds".format(host=self.host, stok=self.stok)

    def getStreamURL(self):
        return "{host}:8800".format(host=self.host)

    def ensureAuthenticated(self):
        if not self.stok:
            return self.refreshStok()
        return True

    def refreshStok(self):
        url = "https://{host}".format(host=self.host)
        data = {
            "method": "login",
            "params": {
                "hashed": True,
                "password": self.hashedPassword,
                "username": self.user,
            },
        }
        res = requests.post(
            url, data=json.dumps(data), headers=self.headers, verify=False
        )
        if self.responseIsOK(res):
            self.stok = res.json()["result"]["stok"]
            return self.stok
        raise Exception("Invalid authentication data")

    def responseIsOK(self, res):
        if res.status_code != 200:
            raise Exception(
                "Error communicating with Tapo Camera. Status code: "
                + str(res.status_code)
            )
        try:
            data = res.json()
            return data["error_code"] == 0
        except Exception as e:
            raise Exception("Unexpected response from Tapo Camera: " + str(e))

    def performRequest(self, requestData, loginRetry=False):
        self.ensureAuthenticated()
        url = self.getHostURL()
        res = requests.post(
            url, data=json.dumps(requestData), headers=self.headers, verify=False
        )
        if self.responseIsOK(res):
            return res.json()
        else:
            data = json.loads(res.text)
            #  -40401: Invalid Stok
            if (
                data
                and "error_code" in data
                and data["error_code"] == -40401
                and not loginRetry
            ):
                self.refreshStok()
                return self.performRequest(requestData, True)
            else:
                raise Exception(
                    "Error: "
                    + self.getErrorMessage(data["error_code"])
                    + " Response:"
                    + json.dumps(data)
                )

    def getMediaSession(self):
        return HttpMediaSession(self.host, self.cloudPassword)  # pragma: no cover

    def getOsd(self):
        return self.performRequest(
            {
                "method": "get",
                "OSD": {"name": ["date", "week", "font"], "table": ["label_info"]},
            }
        )

    def setOsd(
        self,
        label,
        dateEnabled=True,
        labelEnabled=False,
        weekEnabled=False,
        dateX=0,
        dateY=0,
        labelX=0,
        labelY=500,
        weekX=0,
        weekY=0,
    ):
        data = {
            "method": "set",
            "OSD": {
                "date": {
                    "enabled": "on" if dateEnabled else "off",
                    "x_coor": dateX,
                    "y_coor": dateY,
                },
                "week": {
                    "enabled": "on" if weekEnabled else "off",
                    "x_coor": weekX,
                    "y_coor": weekY,
                },
                "font": {
                    "color": "white",
                    "color_type": "auto",
                    "display": "ntnb",
                    "size": "auto",
                },
                "label_info_1": {
                    "enabled": "on" if labelEnabled else "off",
                    "x_coor": labelX,
                    "y_coor": labelY,
                },
            },
        }

        if len(label) >= 16:
            raise Exception("Error: Label cannot be longer than 16 characters")
        elif len(label) == 0:
            data["OSD"]["label_info_1"]["enabled"] = "off"
        else:
            data["OSD"]["label_info_1"]["text"] = label
        if (
            dateX > 10000
            or dateX < 0
            or labelX > 10000
            or labelX < 0
            or weekX > 10000
            or weekX < 0
            or dateY > 10000
            or dateY < 0
            or labelY > 10000
            or labelY < 0
            or weekY > 10000
            or weekY < 0
        ):
            raise Exception("Error: Incorrect corrdinates, must be between 0 and 10000")

        return self.performRequest(data)

    def getModuleSpec(self):
        return self.performRequest(
            {"method": "get", "function": {"name": ["module_spec"]}}
        )

    def getPrivacyMode(self):
        data = {"method": "get", "lens_mask": {"name": ["lens_mask_info"]}}
        return self.performRequest(data)["lens_mask"]["lens_mask_info"]

    def getMotionDetection(self):
        data = {"method": "get", "motion_detection": {"name": ["motion_det"]}}
        return self.performRequest(data)["motion_detection"]["motion_det"]

    def getAlarm(self):
        data = {"method": "get", "msg_alarm": {"name": ["chn1_msg_alarm_info"]}}
        return self.performRequest(data)["msg_alarm"]["chn1_msg_alarm_info"]

    def getLED(self):
        data = {"method": "get", "led": {"name": ["config"]}}
        return self.performRequest(data)["led"]["config"]

    def getAutoTrackTarget(self):
        data = {"method": "get", "target_track": {"name": ["target_track_info"]}}
        return self.performRequest(data)["target_track"]["target_track_info"]

    def getAudioSpec(self):
        return self.performRequest(
            {
                "method": "get",
                "audio_capability": {"name": ["device_speaker", "device_microphone"]},
            }
        )

    def getVhttpd(self):
        return self.performRequest({"method": "get", "cet": {"name": ["vhttpd"]}})

    def getBasicInfo(self):
        return self.performRequest(
            {"method": "get", "device_info": {"name": ["basic_info"]}}
        )

    def getTime(self):
        return self.performRequest(
            {"method": "get", "system": {"name": ["clock_status"]}}
        )

    def getMotorCapability(self):
        return self.performRequest({"method": "get", "motor": {"name": ["capability"]}})

    def setPrivacyMode(self, enabled):
        return self.performRequest(
            {
                "method": "set",
                "lens_mask": {
                    "lens_mask_info": {"enabled": "on" if enabled else "off"}
                },
            }
        )

    def setAlarm(self, enabled, soundEnabled=True, lightEnabled=True):
        alarm_mode = []

        if not soundEnabled and not lightEnabled:
            raise Exception("You need to use at least sound or light for alarm")

        if soundEnabled:
            alarm_mode.append("sound")
        if lightEnabled:
            alarm_mode.append("light")

        data = {
            "method": "set",
            "msg_alarm": {
                "chn1_msg_alarm_info": {
                    "alarm_type": "0",
                    "enabled": "on" if enabled else "off",
                    "light_type": "0",
                    "alarm_mode": alarm_mode,
                }
            },
        }

        return self.performRequest(data)

    def moveMotor(self, x, y):
        return self.performRequest(
            {"method": "do", "motor": {"move": {"x_coord": str(x), "y_coord": str(y)}}}
        )

    def moveMotorStep(self, angle):
        if not (0 <= angle < 360):
            raise Exception("Angle must be in a range 0 <= angle < 360")

        return self.performRequest(
            {"method": "do", "motor": {"movestep": {"direction": str(angle)}}}
        )

    def calibrateMotor(self):
        return self.performRequest({"method": "do", "motor": {"manual_cali": ""}})

    def format(self):
        return self.performRequest(
            {"method": "do", "harddisk_manage": {"format_hd": "1"}}
        )  # pragma: no cover

    def setLEDEnabled(self, enabled):
        return self.performRequest(
            {
                "method": "set",
                "led": {"config": {"enabled": "on" if enabled else "off"}},
            }
        )

    def setDayNightMode(self, inf_type):
        if inf_type not in ["off", "on", "auto"]:
            raise Exception("Invalid inf_type, can be off, on or auto")
        return self.performRequest(
            {"method": "set", "image": {"common": {"inf_type": inf_type}}}
        )

    def getUserID(self):
        if not self.userID:
            self.userID = self.performRequest(
                {
                    "method": "multipleRequest",
                    "params": {
                        "requests": [
                            {
                                "method": "getUserID",
                                "params": {"system": {"get_user_id": "null"}},
                            }
                        ]
                    },
                }
            )["result"]["responses"][0]["result"]["user_id"]
        return self.userID

    def getRecordings(self, date):
        return self.performRequest(
            {
                "method": "multipleRequest",
                "params": {
                    "requests": [
                        {
                            "method": "searchVideoOfDay",
                            "params": {
                                "playback": {
                                    "search_video_utility": {
                                        "channel": 0,
                                        "date": date,
                                        "end_index": 99,
                                        "id": self.getUserID(),
                                        "start_index": 0,
                                    }
                                }
                            },
                        }
                    ]
                },
            }
        )["result"]["responses"][0]["result"]["playback"]["search_video_results"]

    def getCommonImage(self):
        return self.performRequest({"method": "get", "image": {"name": "common"}})

    def setMotionDetection(self, enabled, sensitivity=False):
        data = {
            "method": "set",
            "motion_detection": {"motion_det": {"enabled": "on" if enabled else "off"}},
        }
        if sensitivity:
            if sensitivity == "high":
                data["motion_detection"]["motion_det"]["digital_sensitivity"] = "80"
            elif sensitivity == "normal":
                data["motion_detection"]["motion_det"]["digital_sensitivity"] = "50"
            elif sensitivity == "low":
                data["motion_detection"]["motion_det"]["digital_sensitivity"] = "20"
            else:
                raise Exception("Invalid sensitivity, can be low, normal or high")

        return self.performRequest(data)

    def setAutoTrackTarget(self, enabled):
        return self.performRequest(
            {
                "method": "set",
                "target_track": {
                    "target_track_info": {"enabled": "on" if enabled else "off"}
                },
            }
        )

    def reboot(self):
        return self.performRequest({"method": "do", "system": {"reboot": "null"}})

    def getPresets(self):
        data = self.performRequest({"method": "get", "preset": {"name": ["preset"]}})
        self.presets = {
            id: data["preset"]["preset"]["name"][key]
            for key, id in enumerate(data["preset"]["preset"]["id"])
        }
        return self.presets

    def savePreset(self, name):
        self.performRequest(
            {
                "method": "do",
                "preset": {"set_preset": {"name": str(name), "save_ptz": "1"}},
            }
        )
        self.getPresets()
        return True

    def deletePreset(self, presetID):
        if not str(presetID) in self.presets:
            raise Exception("Preset " + str(presetID) + " is not set in the app")

        self.performRequest(
            {"method": "do", "preset": {"remove_preset": {"id": [presetID]}}}
        )
        self.getPresets()
        return True

    def setPreset(self, presetID):
        if not str(presetID) in self.presets:
            raise Exception("Preset " + str(presetID) + " is not set in the app")
        return self.performRequest(
            {"method": "do", "preset": {"goto_preset": {"id": str(presetID)}}}
        )

    def getLensDistortionCorrection(self):
        data = self.performRequest({"method": "get", "image": {"name": ["switch"]}})
        return data["image"]["switch"]["ldc"] == "on"

    def setLensDistortionCorrection(self, enable):
        return self.performRequest(
            {"method": "set", "image": {"switch": {"ldc": "on" if enable else "off"}}}
        )

    def getImageFlipVertical(self):
        data = self.performRequest({"method": "get", "image": {"name": ["switch"]}})
        return data["image"]["switch"]["flip_type"] == "center"

    def setImageFlipVertical(self, enable):
        return self.performRequest(
            {
                "method": "set",
                "image": {"switch": {"flip_type": "center" if enable else "off"}},
            }
        )

    def setLightFrequencyMode(self, mode):
        allowed_modes = ["auto", "50", "60"]
        if mode not in allowed_modes:
            raise Exception(
                "Light frequency mode must be one of {}".format(allowed_modes)
            )

        return self.performRequest(
            {"method": "set", "image": {"common": {"light_freq_mode": mode}}}
        )

    @staticmethod
    def getErrorMessage(errorCode):
        if str(errorCode) in ERROR_CODES:
            return str(ERROR_CODES[str(errorCode)])
        else:
            return str(errorCode)
def setPreset(self, presetID):
        if not str(presetID) in self.presets:
            raise Exception("Preset " + str(presetID) + " is not set in the app")
        return self.performRequest(
            {"method": "do", "preset": {"goto_preset": {"id": str(presetID)}}}
        )

J’aimerais vraiment arriver à comprendre comment interagir avec cette librairie, j’ai vu beaucoup de choses qui serait bien utile comme le reboot

Bonsoir

La librairie crée une classe Tapo dans laquelle setPreset est définie. goto_preset n’est pas définie.
Vous avez créé une instance tapo2 de la classe Tapo.
tapo2=Tapo(host, user, password)

Il faut alors appeler la fonction avec tapo2.setPreset(sys.argv[1]) comme ça a été fait pour moveMotor
res = tapo2.moveMotor(x,0)

Je précise que je n’y connais rien en Python.

1 « J'aime »

Merci infiniment de votre aide, j’ai modifié mon script selon ce que j’ai plus ou moins compris de vos conseilles :

#!/usr/bin/env python3

from pytapo import Tapo
import sys

def setPreset(1) :
    user="camtest"
    password="camtest"
    host="192.168.1.67"
    tapo2=Tapo(host, user, password)
    res ={}
    try :
        tapo2.setPreset(sys.argv[1])
    except Exception :
        print("Oops!  Tu es au bout Jacquie")
        res["error_code"] =-1

    if(res.get("error_code")==0) :
        return 1
    else :
        return -1
#print (goto_preset())
print(sys.argv[1])
goto_preset(sys.argv[1])

Ca ne fonctionne toujours pas, j’ai cette erreur :

Erreur sur /var/www/html/plugins/script/data/camtestbas.PY move 2>&1 valeur retournée : 1. Détails : File "/var/www/html/plugins/script/data/camtestbas.PY", line 6 def setPreset(1) : ^ SyntaxError: invalid syntax

Comment dois-je definir le preset autre que la position 1 que j’ai définie sur l’appli ?

Je viens de relire votre 1er post. Vous définissez setPreset et vous appelez goto_preset à la fin qui n’est pas défini.

Pour le dernier post, Pour être utilisable, l’argument dans la définition de la fonction doit obligatoirement être une variable et pas une valeur fixe.

def setPreset(x) :

Et utiliser la variable dans la fonction

tapo2.setPreset(x)

A la fin, il faut appeler setPreset à la place de goto_preset

Franchement j’avoue ne pas trop comprendre le language de code :

J’ai donc encore une foie tatonner le script :

#!/usr/bin/env python3

from pytapo import Tapo
import sys

def setPreset() :
    user="camtest"
    password="camtest"
    host="192.168.1.67"
    tapo2=Tapo(host, user, password)
    res ={}
    try :
        tapo2.setPreset(sys.argv[1])
    except Exception :
        print("Oops!  Tu es au bout Jacquie")
        res["error_code"] =-1

    if(res.get("error_code")==0) :
        return 1
    else :
        return -1
#print (goto_preset())
print(sys.argv[1])
setPreset(sys.argv[1])

Pour en arriver a ce resultat :

Erreur sur /var/www/html/plugins/script/data/camtestbas.PY move 2>&1 valeur retournée : 1. Détails : move Traceback (most recent call last): File "/var/www/html/plugins/script/data/camtestbas.PY", line 24, in setPreset(sys.argv[1]) TypeError: setPreset() takes 0 positional arguments but 1 was given

Donc si je comprend bien ce script (si toute foie il marche un jour) me servira à enregister la position ? Comment ensuite aller à cette position ?

Vous avez défini la fonction sans argument:

def setPreset() :

et vous l’appelez avec une argument

setPreset(sys.argv[1])

C’est l’erreur qu’il vous signale.

Relisez mon post juste au dessus du votre.

Bon, je n’ai plus d’erreur avec ça :

#!/usr/bin/env python3

from pytapo import Tapo
import sys

def setPreset(x) :
    user="camtest"
    password="camtest"
    host="192.168.1.67"
    tapo2=Tapo(host, user, password)
    res ={}
    try :
        tapo2.tapo2.setPreset(x)
    except Exception :
        print("Oops!  Tu es au bout Jacquie")
        res["error_code"] =-1

    if(res.get("error_code")==0) :
        return 1
    else :
        return -1
#print (goto_preset())
print(sys.argv[1])
setPreset(sys.argv[1])

Par contre cela n’à pas l’aire de fonctionner, rien ne se passe au niveau de la caméra quand je l’execute.

Peut etres ai-je loupé un truc, ne serais-ce pas pour appeler le script ? Moi je le lance en ajoutant move à la fin

/var/www/html/plugins/script/data/camtestbas.PY move

Suppositions:
Le message dans la fonction setPreset de la classe Tapo indique qu’il va faire un goto_preset.
Pour la définition des positions, il faut peut etre le faire avec l’appli de la camera

Il faut une autre argument au lancement de

/var/www/html/plugins/script/data/camtestbas.PY move

le nom/numéro de la position de la cam que vous voulez obtenir.
Il faut relire la classe Tapo. Il me semble avoir lu une fonction getPresets

Y a t-il une orthographe particulière ? Ma commande ne marche pas et portant « Position test » est difinie telle quelle dans l’appli

/var/www/html/plugins/script/data/camtestbas.PY getPresets Position test

Bonjour,

J’étais dans le même cas et grâce à votre post, des recherches un peu partout sur le net et différents tests, j’ai réussi à appeler mes préposition grâce à ce script.

#!/usr/bin/env python3

from pytapo import Tapo

user = «  » # user you set in Advanced Settings → Camera Account
password = «  » # password you set in Advanced Settings → Camera Account
host = «  » # ip of the camera, example: 192.168.1.52

tapo = Tapo(host, user, password)

res=tapo.setPreset(‹ 1 ›) # ID de la préposition voulue

J’avais aussi une erreur de permission sur mes fichier pour résoudre ça j’ai trouvé l’info dans un autre post du forum.
Si vous rencontrer le même soucis, il faut aller dans
Réglages → Système → Configuration → _OS/DB
Et vérifier Rétablissement des droits des dossiers et fichiers

Bonjour à tous,
Je tente de faire tourné ma caméra Tapo et j’ai suis les indications dans le dernier message. Mais j’ai toujours un message d’erreur :

Erreur exécution de la commande [Aucun][Caméra 1 vue 1][Vue 1] : Erreur sur sudo chmod +x /var/www/html/plugins/script/data/posSelect1.PY 2>/dev/null;/var/www/html/plugins/script/data/posSelect1.PY 2>&1 valeur retournée : 1. Détails : File "/var/www/html/plugins/script/data/posSelect1.PY", line 11 res=tapo.setPreset(‹ 1 ›) # ID de la préposition voulue ^ SyntaxError: invalid character '‹' (U+2039)

Donc j’ai enlevé <> mais j’ai un autre message :

Erreur exécution de la commande [Aucun][Caméra 1 vue 1][Vue 1] : Erreur sur sudo chmod +x /var/www/html/plugins/script/data/posSelect1.PY 2>/dev/null;/var/www/html/plugins/script/data/posSelect1.PY 2>&1 valeur retournée : 1. Détails : Traceback (most recent call last): File "/var/www/html/plugins/script/data/posSelect1.PY", line 9, in tapo = Tapo(host, user, password) File "/usr/local/lib/python3.9/dist-packages/pytapo/__init__.py", line 86, in __init__ self.basicInfo = self.getBasicInfo() File "/usr/local/lib/python3.9/dist-packages/pytapo/__init__.py", line 1009, in getBasicInfo return self.executeFunction( File "/usr/local/lib/python3.9/dist-packages/pytapo/__init__.py", line 491, in executeFunction data = self.performRequest( File "/usr/local/lib/python3.9/dist-packages/pytapo/__init__.py", line 530, in performRequest self.ensureAuthenticated() File "/usr/local/lib/python3.9/dist-packages/pytapo/__init__.py", line 108, in ensureAuthenticated return self.refreshStok() File "/usr/local/lib/python3.9/dist-packages/pytapo/__init__.py", line 400, in refreshStok raise Exception("Invalid authentication data") Exception: Invalid authentication data

Donc j’utilise bien Scripte et j’ai créer le fichier correspondant :


Sans titre1

Avez-vous une idée ?

Plus personne pour ce sujet là ?