FalkTannhaeuser / python-onvif-zeep

ONVIF Client Implementation in Python 2+3 (using https://github.com/mvantellingen/python-zeep instead of suds as SOAP client)
MIT License
420 stars 137 forks source link

zeep.exceptions.ValidationError: Missing element PTZConfigurationToken (GetConfiguration.PTZConfigurationToken) #81

Open klattimer opened 3 years ago

klattimer commented 3 years ago

Bombs out trying to get the ptz configuration.

EmpireofKings commented 2 years ago

I also had field day getting PTZ to work, the below class should work for you.

Just initialize it by calling the class in a different function, then call absolute move, or relative move.

Let me know if you still have trouble

`

import logging
from onvif import ONVIFCamera

def example_ptz_zoom(ip, user, password):
    ptz_cam = CameraControl(ip, user, password)
    ptz_cam.absolute_move(0.0, 0.0, 1)   ## ( Pan, Tilt, Zoom )

example_ptz_zoom("192.168.1.18", "admin", "admin")

logging.basicConfig(filename='teste-onvif.log', filemode='w', level=logging.DEBUG)
logging.info('Started')

class CameraControl:

def __init__(self, ip, user, password):
    self.__cam_ip = ip
    self.__cam_user = user
    self.__cam_password = password

@staticmethod
def _map_onvif_to_vapix(value, min_onvif, max_onvif, min_vapix, max_vapix):
    return (value - min_onvif) * (max_vapix - min_vapix) / (max_onvif - min_onvif) + min_vapix

@staticmethod
def _map_vapix_to_onvif(value, min_vapix, max_vapix, min_onvif, max_onvif):
    return (value - min_vapix) * (max_onvif - min_onvif) / (max_vapix - min_vapix) + min_onvif

def camera_start(self):
    """
    Creates the connection to the camera using the onvif protocol
    Returns:
        Return the ptz service object and media service object
    """
    mycam = ONVIFCamera(self.__cam_ip, 80, self.__cam_user, self.__cam_password)  ## Some cameras use port 8080
    logging.info('Create media service object')
    media = mycam.create_media_service()
    logging.info('Create ptz service object')
    ptz = mycam.create_ptz_service()
    logging.info('Get target profile')
    media_profile = media.GetProfiles()[0]
    logging.info('Camera working!')

    self.mycam = mycam
    self.camera_ptz = ptz
    self.camera_media_profile = media_profile
    self.camera_media = media

    return self.camera_ptz, self.camera_media_profile

def absolute_move(self, pan: float, tilt: float, zoom: float):
    """
    Operation to move pan, tilt or zoom to a absolute destination.
    Args:
        pan: Pans the device relative to the (0,0) position.
        tilt: Tilts the device relative to the (0,0) position.
        zoom: Zooms the device n steps.
    Returns:
        Return onvif's response
    """
    request = self.camera_ptz.create_type('AbsoluteMove')
    request.ProfileToken = self.camera_media_profile.token
    request.Position = {'PanTilt': {'x': pan, 'y': tilt}, 'Zoom': zoom}
    resp = self.camera_ptz.AbsoluteMove(request)
    logging.info('camera_command( aboslute_move(%f, %f, %f) )', pan, tilt, zoom)
    return resp

def continuous_move(self, pan: float, tilt: float, zoom: float):
    """
    Operation for continuous Pan/Tilt and Zoom movements.
    Args:
        pan: speed of movement of Pan.
        tilt: speed of movement of Tilt.
        zoom: speed of movement of Zoom.
    Returns:
        Return onvif's response.
    """
    request = self.camera_ptz.create_type('ContinuousMove')
    request.ProfileToken = self.camera_media_profile.token
    request.Velocity = {'PanTilt': {'x': pan, 'y': tilt}, 'Zoom': zoom}
    resp = self.camera_ptz.ContinuousMove(request)
    logging.info('camera_command( continuous_move(%f, %f, %f) )', pan, tilt, zoom)
    return resp

def relative_move(self, pan: float, tilt: float, zoom: float):
    """
    Operation for Relative Pan/Tilt and Zoom Move.
    Args:
        pan: A positional Translation relative to the pan current position.
        tilt: A positional Translation relative to the tilt current position.
        zoom:
    Returns:
        Return onvif's response
    """
    request = self.camera_ptz.create_type('RelativeMove')
    request.ProfileToken = self.camera_media_profile.token
    request.Translation = {'PanTilt': {'x': pan, 'y': tilt}, 'Zoom': zoom}
    resp = self.camera_ptz.RelativeMove(request)
    logging.info('camera_command( relative_move(%f, %f, %f) )', pan, tilt, zoom)
    return resp

def stop_move(self):
    """
    Operation to stop ongoing pan, tilt and zoom movements of absolute relative and continuous type.
    Returns:
        Return onvif's response
    """
    request = self.camera_ptz.create_type('Stop')
    request.ProfileToken = self.camera_media_profile.token
    resp = self.camera_ptz.Stop(request)
    logging.info('camera_command( stop_move() )')
    return resp

def set_home_position(self):
    """
    Operation to save current position as the home position.
    Returns:
        Return onvif's response
    """
    request = self.camera_ptz.create_type('SetHomePosition')
    request.ProfileToken = self.camera_media_profile.token
    resp = self.camera_ptz.SetHomePosition(request)
    self.camera_ptz.Stop({'ProfileToken': self.camera_media_profile.token})
    logging.info('camera_command( set_home_position() )')
    return resp

def go_home_position(self):
    """
    Operation to move the PTZ device to it's "home" position.
    Returns:
        Return onvif's response
    """
    request = self.camera_ptz.create_type('GotoHomePosition')
    request.ProfileToken = self.camera_media_profile.token
    resp = self.camera_ptz.GotoHomePosition(request)
    logging.info('camera_command( go_home_position() )')
    return resp

def get_ptz(self):
    """
    Operation to request PTZ status.
    Returns:
        Returns a list with the values ​​of Pan, Tilt and Zoom
    """
    request = self.camera_ptz.create_type('GetStatus')
    request.ProfileToken = self.camera_media_profile.token
    ptz_status = self.camera_ptz.GetStatus(request)
    pan = ptz_status.Position.PanTilt.x
    tilt = ptz_status.Position.PanTilt.y
    zoom = ptz_status.Position.Zoom.x
    ptz_list = (pan, tilt, zoom)
    logging.info('camera_command( get_ptz() )')
    return ptz_list

def set_preset(self, preset_name: str):
    """
    The command saves the current device position parameters.
    Args:
        preset_name: Name for preset.
    Returns:
        Return onvif's response.
    """
    presets = CameraControl.get_preset_complete(self)
    request = self.camera_ptz.create_type('SetPreset')
    request.ProfileToken = self.camera_media_profile.token
    request.PresetName = preset_name
    logging.info('camera_command( set_preset%s) )', preset_name)

    for i, _ in enumerate(presets):
        if str(presets[i].Name) == preset_name:
            logging.warning(
                'Preset (\'%s\') not created. Preset already exists!', preset_name)
            return None

    ptz_set_preset = self.camera_ptz.SetPreset(request)
    logging.info('Preset (\'%s\') created!', preset_name)
    return ptz_set_preset

def get_preset(self):
    """
    Operation to request all PTZ presets.
    Returns:
        Returns a list of tuples with the presets.
    """
    ptz_get_presets = CameraControl.get_preset_complete(self)
    logging.info('camera_command( get_preset() )')

    presets = []
    for i, _ in enumerate(ptz_get_presets):
        presets.append((i, ptz_get_presets[i].Name))
    return presets

def get_preset_complete(self):
    """
    Operation to request all PTZ presets.
    Returns:
        Returns the complete presets Onvif.
    """
    request = self.camera_ptz.create_type('GetPresets')
    request.ProfileToken = self.camera_media_profile.token
    ptz_get_presets = self.camera_ptz.GetPresets(request)
    return ptz_get_presets

def remove_preset(self, preset_name: str):
    """
    Operation to remove a PTZ preset.
    Args:
        preset_name: Preset name.
    Returns:
        Return onvif's response.
    """
    presets = CameraControl.get_preset_complete(self)
    request = self.camera_ptz.create_type('RemovePreset')
    request.ProfileToken = self.camera_media_profile.token
    logging.info('camera_command( remove_preset(%s) )', preset_name)
    for i, _ in enumerate(presets):
        if str(presets[i].Name) == preset_name:
            request.PresetToken = presets[i].token
            ptz_remove_preset = self.camera_ptz.RemovePreset(request)
            logging.info('Preset (\'%s\') removed!', preset_name)
            return ptz_remove_preset
    logging.warning("Preset (\'%s\') not found!", preset_name)
    return None

def go_to_preset(self, preset_position: str):
    """
    Operation to go to a saved preset position.
    Args:
        preset_position: preset name.
    Returns:
        Return onvif's response.
    """
    presets = CameraControl.get_preset_complete(self)
    request = self.camera_ptz.create_type('GotoPreset')
    request.ProfileToken = self.camera_media_profile.token
    logging.info('camera_command( go_to_preset(%s) )', preset_position)
    for i, _ in enumerate(presets):
        str1 = str(presets[i].Name)
        if str1 == preset_position:
            request.PresetToken = presets[i].token
            resp = self.camera_ptz.GotoPreset(request)
            logging.info("Goes to (\'%s\')", preset_position)
            return resp
    logging.warning("Preset (\'%s\') not found!", preset_position)
    return None

`

klattimer commented 2 years ago

Thanks but shouldn't this be a pull request?

EmpireofKings commented 2 years ago

It could be, it would just go to the examples if it were to be one.

Not really changing any low level stuff here, plus the last PR was approved in 2019, not sure if the OG author is still around to approve it.

Medeirox commented 8 months ago

Worked like a charm! Thanks!