quatanium / python-onvif

ONVIF Client Implementation in Python
MIT License
472 stars 321 forks source link

Access onvif device outside the local network #110

Open AleksErsh opened 2 years ago

AleksErsh commented 2 years ago

I want to be able to control onvif camera from outside the local network as well as from the local network. I forward http port of my camera but when trying to send ptz request to this port, I get the connection timeout error.

If I understand correctly the problem is that specified ip and port for ONVIFCamera() are only used to connect to the camera. Then the addresses of services (Imaging, Media, PTZ, etc.) are updated according to the camera settings. These settings contain different ip address, so I am not able to connect.

I figured out that this code from client.py is responsible for that:

def update_xaddrs(self):
    # Establish devicemgmt service first
    self.dt_diff = None
    self.devicemgmt  = self.create_devicemgmt_service()
    if self.adjust_time :
        cdate = self.devicemgmt.GetSystemDateAndTime().UTCDateTime
        cam_date = dt.datetime(cdate.Date.Year, cdate.Date.Month, cdate.Date.Day, cdate.Time.Hour, cdate.Time.Minute, cdate.Time.Second)
        self.dt_diff = cam_date - dt.datetime.utcnow()
        self.devicemgmt.dt_diff = self.dt_diff
        #self.devicemgmt.set_wsse()
        self.devicemgmt  = self.create_devicemgmt_service()
    # Get XAddr of services on the device
    self.xaddrs = { }
    capabilities = self.devicemgmt.GetCapabilities({'Category': 'All'})
    for name in capabilities:
        capability = capabilities[name]
        try:
            if name.lower() in SERVICES and capability is not None:
                ns = SERVICES[name.lower()]['ns']
                self.xaddrs[ns] = capability['XAddr']
        except Exception:
            logger.exception('Unexpected service type')
    with self.services_lock:
        try:
            self.event = self.create_events_service()
            self.xaddrs['http://www.onvif.org/ver10/events/wsdl/PullPointSubscription'] = self.event.CreatePullPointSubscription().SubscriptionReference.Address._value_1
        except:
            pass

I think this issue can be fixed if self.xaddrs will be defined with self.host and self.port parameters of ONVIFCamera(). Can you advise please?

javiow commented 2 years ago

I met the same situation so i changed upper function as you suggested.

    def update_xaddrs(self):
        # Establish devicemgmt service first
        self.dt_diff = None
        self.devicemgmt  = self.create_devicemgmt_service()
        if self.adjust_time :
            cdate = self.devicemgmt.GetSystemDateAndTime().UTCDateTime
            cam_date = dt.datetime(cdate.Date.Year, cdate.Date.Month, cdate.Date.Day, cdate.Time.Hour, cdate.Time.Minute, cdate.Time.Second)
            self.dt_diff = cam_date - dt.datetime.utcnow()
            self.devicemgmt.dt_diff = self.dt_diff
            #self.devicemgmt.set_wsse()
            self.devicemgmt  = self.create_devicemgmt_service()
        # Get XAddr of services on the device
        self.xaddrs = { }
        capabilities = self.devicemgmt.GetCapabilities({'Category': 'All'})
        for name in capabilities:
            capability = capabilities[name]
            try:
                if name.lower() in SERVICES and capability is not None:
                    ns = SERVICES[name.lower()]['ns']
                    self.xaddrs[ns] = capability['XAddr']
                    received_ip = capability['XAddr'].split("/onvif")[0].split("http://")[1].split(":")[0]
                    received_port = capability['XAddr'].split("/onvif")[0].split("http://")[1].split(":")[1]
                    if (self.host != received_ip) and (self.port != received_port):
                        new_capability_xaddr = "http://" + str(self.host) + ":" + str(self.port) + "/onvif" + capability['XAddr'].split("/onvif")[1]
                        self.xaddrs[ns] = new_capability_xaddr
            except Exception:
                logger.exception('Unexpected service type')

        with self.services_lock:
            try:
                self.event = self.create_events_service()
                self.xaddrs['http://www.onvif.org/ver10/events/wsdl/PullPointSubscription'] = self.event.CreatePullPointSubscription().SubscriptionReference.Address._value_1
            except:
                pass

then it worked for me. Thanks for your suggestion :)

OverthinkingTech commented 1 year ago

changed upper function as you suggested.

Thank you! I ran into this same problem and you saved me the work of coming up with a fix myself.