11from __future__ import print_function , division
22__version__ = '0.0.1'
3+ import datetime as dt
4+ import logging
35import os .path
46from threading import Thread , RLock
57
6- import logging
7- logger = logging .getLogger ('onvif' )
8- logging .basicConfig (level = logging .INFO )
9- logging .getLogger ('zeep.client' ).setLevel (logging .CRITICAL )
10-
118from zeep .client import Client , CachingClient , Settings
129from zeep .wsse .username import UsernameToken
1310import zeep .helpers
1411
1512from onvif .exceptions import ONVIFError
1613from onvif .definition import SERVICES
17- import datetime as dt
14+
15+ logger = logging .getLogger ('onvif' )
16+ logging .basicConfig (level = logging .INFO )
17+ logging .getLogger ('zeep.client' ).setLevel (logging .CRITICAL )
18+
19+
1820# Ensure methods to raise an ONVIFError Exception
1921# when some thing was wrong
2022def safe_func (func ):
2123 def wrapped (* args , ** kwargs ):
2224 try :
2325 return func (* args , ** kwargs )
2426 except Exception as err :
25- #print('Ouuups: err =', err, ', func =', func, ', args =', args, ', kwargs =', kwargs)
2627 raise ONVIFError (err )
2728 return wrapped
2829
2930
3031class UsernameDigestTokenDtDiff (UsernameToken ):
31- '''
32+ """
3233 UsernameDigestToken class, with a time offset parameter that can be adjusted;
3334 This allows authentication on cameras without being time synchronized.
3435 Please note that using NTP on both end is the recommended solution,
3536 this should only be used in "safe" environments.
36- '''
37+ """
3738 def __init__ (self , user , passw , dt_diff = None , ** kwargs ):
3839 super ().__init__ (user , passw , ** kwargs )
3940 self .dt_diff = dt_diff # Date/time difference in datetime.timedelta
@@ -42,17 +43,15 @@ def apply(self, envelope, headers):
4243 old_created = self .created
4344 if self .created is None :
4445 self .created = dt .datetime .utcnow ()
45- #print('UsernameDigestTokenDtDiff.created: old = %s (type = %s), dt_diff = %s (type = %s)' % (self.created, type(self.created), self.dt_diff, type(self.dt_diff)), end='')
4646 if self .dt_diff is not None :
4747 self .created += self .dt_diff
48- #print(' new = %s' % self.created)
4948 result = super ().apply (envelope , headers )
5049 self .created = old_created
5150 return result
5251
5352
5453class ONVIFService (object ):
55- '''
54+ """
5655 Python Implemention for ONVIF Service.
5756 Services List:
5857 DeviceMgmt DeviceIO Event AnalyticsDevice Display Imaging Media
@@ -80,12 +79,12 @@ class ONVIFService(object):
8079 params = device_service.create_type('SetHostname')
8180 params.Hostname = 'NewHostName'
8281 device_service.SetHostname(params)
83- '''
82+ """
8483
8584 @safe_func
8685 def __init__ (self , xaddr , user , passwd , url ,
8786 encrypt = True , daemon = False , zeep_client = None , no_cache = False ,
88- portType = None , dt_diff = None , binding_name = '' , transport = None ):
87+ dt_diff = None , binding_name = '' , transport = None ):
8988 if not os .path .isfile (url ):
9089 raise ONVIFError ('%s doesn`t exist!' % url )
9190
@@ -94,7 +93,6 @@ def __init__(self, xaddr, user, passwd, url,
9493 wsse = UsernameDigestTokenDtDiff (user , passwd , dt_diff = dt_diff , use_digest = encrypt )
9594 # Create soap client
9695 if not zeep_client :
97- #print(self.url, self.xaddr)
9896 ClientType = Client if no_cache else CachingClient
9997 settings = Settings ()
10098 settings .strict = False
@@ -139,7 +137,6 @@ def call(params=None, callback=None):
139137 try :
140138 ret = func (** params )
141139 except TypeError :
142- #print('### func =', func, '### params =', params, '### type(params) =', type(params))
143140 ret = func (params )
144141 if callable (callback ):
145142 callback (ret )
@@ -154,23 +151,23 @@ def call(params=None, callback=None):
154151 return wrapped
155152
156153 def __getattr__ (self , name ):
157- '''
154+ """
158155 Call the real onvif Service operations,
159156 See the official wsdl definition for the
160157 APIs detail(API name, request parameters,
161158 response parameters, parameter types, etc...)
162- '''
163- builtin = name .startswith ('__' ) and name .endswith ('__' )
159+ """
160+ builtin = name .startswith ('__' ) and name .endswith ('__' )
164161 if builtin :
165162 return self .__dict__ [name ]
166163 else :
167164 return self .service_wrapper (getattr (self .ws_client , name ))
168165
169166
170167class ONVIFCamera (object ):
171- '''
172- Python Implemention ONVIF compliant device
173- This class integrates onvif services
168+ """
169+ Python Implementation of an ONVIF compliant device.
170+ This class integrates ONVIF services
174171
175172 adjust_time parameter allows authentication on cameras without being time synchronized.
176173 Please note that using NTP on both end is the recommended solution,
@@ -183,18 +180,20 @@ class ONVIFCamera(object):
183180 >>> media_service = mycam.create_media_service()
184181 >>> ptz_service = mycam.create_ptz_service()
185182 # Get PTZ Configuration:
186- >>> mycam.ptz.GetConfiguration()
187- # Another way:
188183 >>> ptz_service.GetConfiguration()
189- '''
184+ """
190185
191186 # Class-level variables
192187 services_template = {'devicemgmt' : None , 'ptz' : None , 'media' : None ,
193- 'imaging' : None , 'events' : None , 'analytics' : None }
188+ 'imaging' : None , 'events' : None , 'analytics' : None }
194189 use_services_template = {'devicemgmt' : True , 'ptz' : True , 'media' : True ,
195- 'imaging' : True , 'events' : True , 'analytics' : True }
196- def __init__ (self , host , port ,user , passwd , wsdl_dir = os .path .join (os .path .dirname (os .path .dirname (__file__ )), "wsdl" ),
197- encrypt = True , daemon = False , no_cache = False , adjust_time = False , transport = None ):
190+ 'imaging' : True , 'events' : True , 'analytics' : True }
191+
192+ def __init__ (self , host , port , user , passwd ,
193+ wsdl_dir = os .path .join (os .path .dirname (os .path .dirname (__file__ )),
194+ "wsdl" ),
195+ encrypt = True , daemon = False , no_cache = False , adjust_time = False ,
196+ transport = None ):
198197 os .environ .pop ('http_proxy' , None )
199198 os .environ .pop ('https_proxy' , None )
200199 self .host = host
@@ -209,7 +208,7 @@ def __init__(self, host, port ,user, passwd, wsdl_dir=os.path.join(os.path.dirna
209208 self .transport = transport
210209
211210 # Active service client container
212- self .services = { }
211+ self .services = {}
213212 self .services_lock = RLock ()
214213
215214 # Set xaddrs
@@ -220,16 +219,16 @@ def __init__(self, host, port ,user, passwd, wsdl_dir=os.path.join(os.path.dirna
220219 def update_xaddrs (self ):
221220 # Establish devicemgmt service first
222221 self .dt_diff = None
223- self .devicemgmt = self .create_devicemgmt_service ()
224- if self .adjust_time :
222+ self .devicemgmt = self .create_devicemgmt_service ()
223+ if self .adjust_time :
225224 cdate = self .devicemgmt .GetSystemDateAndTime ().UTCDateTime
226- cam_date = dt .datetime (cdate .Date .Year , cdate .Date .Month , cdate .Date .Day , cdate .Time .Hour , cdate .Time .Minute , cdate .Time .Second )
225+ cam_date = dt .datetime (cdate .Date .Year , cdate .Date .Month , cdate .Date .Day ,
226+ cdate .Time .Hour , cdate .Time .Minute , cdate .Time .Second )
227227 self .dt_diff = cam_date - dt .datetime .utcnow ()
228228 self .devicemgmt .dt_diff = self .dt_diff
229- #self.devicemgmt.set_wsse()
230- self .devicemgmt = self .create_devicemgmt_service ()
229+ self .devicemgmt = self .create_devicemgmt_service ()
231230 # Get XAddr of services on the device
232- self .xaddrs = { }
231+ self .xaddrs = {}
233232 capabilities = self .devicemgmt .GetCapabilities ({'Category' : 'All' })
234233 for name in capabilities :
235234 capability = capabilities [name ]
@@ -243,8 +242,9 @@ def update_xaddrs(self):
243242 with self .services_lock :
244243 try :
245244 self .event = self .create_events_service ()
246- self .xaddrs ['http://www.onvif.org/ver10/events/wsdl/PullPointSubscription' ] = self .event .CreatePullPointSubscription ().SubscriptionReference .Address ._value_1
247- except :
245+ self .xaddrs ['http://www.onvif.org/ver10/events/wsdl/PullPointSubscription' ] = \
246+ self .event .CreatePullPointSubscription ().SubscriptionReference .Address ._value_1
247+ except Exception :
248248 pass
249249
250250 def update_url (self , host = None , port = None ):
@@ -268,14 +268,13 @@ def update_url(self, host=None, port=None):
268268 self .services [sname ].ws_client .set_options (location = xaddr )
269269
270270 def get_service (self , name , create = True ):
271- service = None
272271 service = getattr (self , name .lower (), None )
273272 if not service and create :
274273 return getattr (self , 'create_%s_service' % name .lower ())()
275274 return service
276275
277276 def get_definition (self , name , portType = None ):
278- ''' Returns xaddr and wsdl of specified service'''
277+ """ Returns xaddr and wsdl of specified service"""
279278 # Check if the service is supported
280279 if name not in SERVICES :
281280 raise ONVIFError ('Unknown service %s' % name )
@@ -301,12 +300,21 @@ def get_definition(self, name, portType=None):
301300 # Get other XAddr
302301 xaddr = self .xaddrs .get (ns )
303302 if not xaddr :
304- raise ONVIFError (' Device doesn` t support service: %s' % name )
303+ raise ONVIFError (" Device doesn' t support service: %s" % name )
305304
306305 return xaddr , wsdlpath , binding_name
307306
308- def create_onvif_service (self , name , from_template = True , portType = None , transport = None ):
309- '''Create ONVIF service client'''
307+ def create_onvif_service (self , name , portType = None , transport = None ):
308+ """
309+ Create ONVIF service client.
310+
311+ :param name: service name, should be present as a key within
312+ the `SERVICES` dictionary declared within the `onvif.definition` module
313+ :param portType:
314+ :param transport:
315+ :return:
316+ """
317+ """Create ONVIF service client"""
310318
311319 name = name .lower ()
312320 xaddr , wsdl_file , binding_name = self .get_definition (name , portType )
@@ -318,7 +326,6 @@ def create_onvif_service(self, name, from_template=True, portType=None, transpor
318326 service = ONVIFService (xaddr , self .user , self .passwd ,
319327 wsdl_file , self .encrypt ,
320328 self .daemon , no_cache = self .no_cache ,
321- portType = portType ,
322329 dt_diff = self .dt_diff ,
323330 binding_name = binding_name ,
324331 transport = transport )
@@ -331,41 +338,47 @@ def create_onvif_service(self, name, from_template=True, portType=None, transpor
331338
332339 return service
333340
334- def create_devicemgmt_service (self , from_template = True , transport = None ):
341+ def create_devicemgmt_service (self , transport = None ):
335342 # The entry point for devicemgmt service is fixed.
336- return self .create_onvif_service ('devicemgmt' , from_template , transport = transport )
343+ return self .create_onvif_service ('devicemgmt' , transport = transport )
344+
345+ def create_media_service (self , transport = None ):
346+ return self .create_onvif_service ('media' , transport = transport )
347+
348+ def create_ptz_service (self , transport = None ):
349+ return self .create_onvif_service ('ptz' , transport = transport )
337350
338- def create_media_service (self , from_template = True , transport = None ):
339- return self .create_onvif_service ('media' , from_template , transport = transport )
351+ def create_imaging_service (self , transport = None ):
352+ return self .create_onvif_service ('imaging' , transport = transport )
340353
341- def create_ptz_service (self , from_template = True , transport = None ):
342- return self .create_onvif_service ('ptz' , from_template , transport = transport )
354+ def create_deviceio_service (self , transport = None ):
355+ return self .create_onvif_service ('deviceio' , transport = transport )
343356
344- def create_imaging_service (self , from_template = True , transport = None ):
345- return self .create_onvif_service ('imaging' , from_template , transport = transport )
357+ def create_events_service (self , transport = None ):
358+ return self .create_onvif_service ('events' , transport = transport )
346359
347- def create_deviceio_service (self , from_template = True , transport = None ):
348- return self .create_onvif_service ('deviceio' , from_template , transport = transport )
360+ def create_analytics_service (self , transport = None ):
361+ return self .create_onvif_service ('analytics' , transport = transport )
349362
350- def create_events_service (self , from_template = True , transport = None ):
351- return self .create_onvif_service ('events' , from_template , transport = transport )
363+ def create_recording_service (self , transport = None ):
364+ return self .create_onvif_service ('recording' , transport = transport )
352365
353- def create_analytics_service (self , from_template = True , transport = None ):
354- return self .create_onvif_service ('analytics' , from_template , transport = transport )
366+ def create_search_service (self , transport = None ):
367+ return self .create_onvif_service ('search' , transport = transport )
355368
356- def create_recording_service (self , from_template = True , transport = None ):
357- return self .create_onvif_service ('recording' , from_template , transport = transport )
369+ def create_replay_service (self , transport = None ):
370+ return self .create_onvif_service ('replay' , transport = transport )
358371
359- def create_search_service (self , from_template = True , transport = None ):
360- return self .create_onvif_service ('search' , from_template , transport = transport )
372+ def create_pullpoint_service (self , transport = None ):
373+ return self .create_onvif_service ('pullpoint' ,
374+ portType = 'PullPointSubscription' ,
375+ transport = transport )
361376
362- def create_replay_service (self , from_template = True , transport = None ):
363- return self .create_onvif_service ('replay' , from_template , transport = transport )
377+ def create_receiver_service (self , transport = None ):
378+ return self .create_onvif_service ('receiver' , transport = transport )
364379
365- def create_pullpoint_service (self , from_template = True , transport = None ):
366- return self .create_onvif_service ('pullpoint' , from_template ,
367- portType = 'PullPointSubscription' ,
368- transport = transport )
380+ def create_notification_service (self , transport = None ):
381+ return self .create_onvif_service ('notification' , transport = transport )
369382
370- def create_receiver_service (self , from_template = True , transport = None ):
371- return self .create_onvif_service ('receiver' , from_template , transport = transport )
383+ def create_subscription_service (self , transport = None ):
384+ return self .create_onvif_service ('subscription' , transport = transport )
0 commit comments