├── .gitignore ├── CHANGES.txt ├── LICENSE ├── MANIFEST.in ├── README.rst ├── examples ├── continuous_move.py ├── events.py ├── rotate_image.py └── streaming.py ├── onvif ├── __init__.py ├── cli.py ├── client.py ├── definition.py ├── exceptions.py └── version.txt ├── setup.cfg ├── setup.py ├── tests └── test.py └── wsdl ├── accesscontrol.wsdl ├── actionengine.wsdl ├── addressing ├── advancedsecurity.wsdl ├── analytics.wsdl ├── analyticsdevice.wsdl ├── b-2.xsd ├── bf-2.xsd ├── bw-2.wsdl ├── deviceio.wsdl ├── devicemgmt.wsdl ├── display.wsdl ├── doorcontrol.wsdl ├── envelope ├── events.wsdl ├── imaging.wsdl ├── include ├── media.wsdl ├── onvif.xsd ├── ptz.wsdl ├── r-2.xsd ├── receiver.wsdl ├── recording.wsdl ├── remotediscovery.wsdl ├── replay.wsdl ├── rw-2.wsdl ├── search.wsdl ├── t-1.xsd ├── types.xsd ├── ws-addr.xsd ├── ws-discovery.xsd ├── xml.xsd └── xmlmime /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quatanium/python-onvif/09ffc65b8cd9d141b6a386804e7af7028755034e/CHANGES.txt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Quatanium Co., Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include onvif/version.txt 2 | include CHANGES.txt 3 | include LICENSE 4 | include README. 5 | include wsdl/* 6 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | python-onvif 2 | ============ 3 | 4 | ONVIF Client Implementation in Python 5 | 6 | Dependencies 7 | ------------ 8 | `Python 2.x` (For a Python 3 compatible fork, see https://github.com/FalkTannhaeuser/python-onvif-zeep) 9 | 10 | `suds `_ >= 0.4 11 | 12 | `suds-passworddigest `_ 13 | 14 | Install python-onvif 15 | -------------------- 16 | **From Source** 17 | 18 | You should clone this repository and run setup.py:: 19 | 20 | cd python-onvif && python setup.py install 21 | 22 | **From PyPI** 23 | 24 | :: 25 | 26 | pip install onvif 27 | 28 | Getting Started 29 | --------------- 30 | 31 | Initialize an ONVIFCamera instance 32 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 33 | 34 | :: 35 | 36 | from onvif import ONVIFCamera 37 | mycam = ONVIFCamera('192.168.0.2', 80, 'user', 'passwd', '/etc/onvif/wsdl/') 38 | 39 | Now, an ONVIFCamera instance is available. By default, a devicemgmt service is also available if everything is OK. 40 | 41 | So, all operations defined in the WSDL document:: 42 | 43 | /etc/onvif/wsdl/devicemgmt.wsdl 44 | 45 | are available. 46 | 47 | Get information from your camera 48 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 49 | :: 50 | 51 | # Get Hostname 52 | resp = mycam.devicemgmt.GetHostname() 53 | print 'My camera`s hostname: ' + str(resp.Name) 54 | 55 | # Get system date and time 56 | dt = mycam.devicemgmt.GetSystemDateAndTime() 57 | tz = dt.TimeZone 58 | year = dt.UTCDateTime.Date.Year 59 | hour = dt.UTCDateTime.Time.Hour 60 | 61 | Configure (Control) your camera 62 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 63 | 64 | To configure your camera, there are two ways to pass parameters to service methods. 65 | 66 | **Dict** 67 | 68 | This is the simpler way:: 69 | 70 | params = {'Name': 'NewHostName'} 71 | device_service.SetHostname(params) 72 | 73 | **Type Instance** 74 | 75 | This is the recommended way. Type instance will raise an 76 | exception if you set an invalid (or non-existent) parameter. 77 | 78 | :: 79 | 80 | params = mycam.devicemgmt.create_type('SetHostname') 81 | params.Hostname = 'NewHostName' 82 | mycam.devicemgmt.SetHostname(params) 83 | 84 | time_params = mycam.devicemgmt.create_type('SetSystemDateAndTime') 85 | time_params.DateTimeType = 'Manual' 86 | time_params.DaylightSavings = True 87 | time_params.TimeZone.TZ = 'CST-8:00:00' 88 | time_params.UTCDateTime.Date.Year = 2014 89 | time_params.UTCDateTime.Date.Month = 12 90 | time_params.UTCDateTime.Date.Day = 3 91 | time_params.UTCDateTime.Time.Hour = 9 92 | time_params.UTCDateTime.Time.Minute = 36 93 | time_params.UTCDateTime.Time.Second = 11 94 | mycam.devicemgmt.SetSystemDateAndTime(time_params) 95 | 96 | Use other services 97 | ~~~~~~~~~~~~~~~~~~ 98 | ONVIF protocol has defined many services. 99 | You can find all the services and operations `here `_. 100 | ONVIFCamera has support methods to create new services:: 101 | 102 | # Create ptz service 103 | ptz_service = mycam.create_ptz_service() 104 | # Get ptz configuration 105 | mycam.ptz.GetConfiguration() 106 | # Another way 107 | # ptz_service.GetConfiguration() 108 | 109 | Or create an unofficial service:: 110 | 111 | xaddr = 'http://192.168.0.3:8888/onvif/yourservice' 112 | yourservice = mycam.create_onvif_service('service.wsdl', xaddr, 'yourservice') 113 | yourservice.SomeOperation() 114 | # Another way 115 | # mycam.yourservice.SomeOperation() 116 | 117 | ONVIF CLI 118 | --------- 119 | python-onvif also provides a command line interactive interface: onvif-cli. 120 | onvif-cli is installed automatically. 121 | 122 | Single command example 123 | ~~~~~~~~~~~~~~~~~~~~~~ 124 | 125 | :: 126 | 127 | $ onvif-cli devicemgmt GetHostname --user 'admin' --password '12345' --host '192.168.0.112' --port 80 128 | True: {'FromDHCP': True, 'Name': hision} 129 | $ onvif-cli devicemgmt SetHostname "{'Name': 'NewerHostname'}" --user 'admin' --password '12345' --host '192.168.0.112' --port 80 130 | True: {} 131 | 132 | Interactive mode 133 | ~~~~~~~~~~~~~~~~ 134 | 135 | :: 136 | 137 | $ onvif-cli -u 'admin' -a '12345' --host '192.168.0.112' --port 80 --wsdl /etc/onvif/wsdl/ 138 | ONVIF >>> cmd 139 | analytics devicemgmt events imaging media ptz 140 | ONVIF >>> cmd devicemgmt GetWsdlUrl 141 | True: http://www.onvif.org/ 142 | ONVIF >>> cmd devicemgmt SetHostname {'Name': 'NewHostname'} 143 | ONVIF >>> cmd devicemgmt GetHostname 144 | True: {'Name': 'NewHostName'} 145 | ONVIF >>> cmd devicemgmt SomeOperation 146 | False: No Operation: SomeOperation 147 | 148 | NOTE: Tab completion is supported for interactive mode. 149 | 150 | Batch mode 151 | ~~~~~~~~~~ 152 | 153 | :: 154 | 155 | $ vim batchcmds 156 | $ cat batchcmds 157 | cmd devicemgmt GetWsdlUrl 158 | cmd devicemgmt SetHostname {'Name': 'NewHostname', 'FromDHCP': True} 159 | cmd devicemgmt GetHostname 160 | $ onvif-cli --host 192.168.0.112 -u admin -a 12345 -w /etc/onvif/wsdl/ < batchcmds 161 | ONVIF >>> True: http://www.onvif.org/ 162 | ONVIF >>> True: {} 163 | ONVIF >>> True: {'FromDHCP': False, 'Name': NewHostname} 164 | 165 | References 166 | ---------- 167 | 168 | * `ONVIF Offical Website `_ 169 | 170 | * `Operations Index `_ 171 | 172 | * `ONVIF Develop Documents `_ 173 | 174 | * `Foscam Python Lib `_ 175 | -------------------------------------------------------------------------------- /examples/continuous_move.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | from onvif import ONVIFCamera 4 | 5 | XMAX = 1 6 | XMIN = -1 7 | YMAX = 1 8 | YMIN = -1 9 | 10 | def perform_move(ptz, request, timeout): 11 | # Start continuous move 12 | ptz.ContinuousMove(request) 13 | # Wait a certain time 14 | sleep(timeout) 15 | # Stop continuous move 16 | ptz.Stop({'ProfileToken': request.ProfileToken}) 17 | 18 | def move_up(ptz, request, timeout=1): 19 | print 'move up...' 20 | request.Velocity.PanTilt._x = 0 21 | request.Velocity.PanTilt._y = YMAX 22 | perform_move(ptz, request, timeout) 23 | 24 | def move_down(ptz, request, timeout=1): 25 | print 'move down...' 26 | request.Velocity.PanTilt._x = 0 27 | request.Velocity.PanTilt._y = YMIN 28 | perform_move(ptz, request, timeout) 29 | 30 | def move_right(ptz, request, timeout=1): 31 | print 'move right...' 32 | request.Velocity.PanTilt._x = XMAX 33 | request.Velocity.PanTilt._y = 0 34 | perform_move(ptz, request, timeout) 35 | 36 | def move_left(ptz, request, timeout=1): 37 | print 'move left...' 38 | request.Velocity.PanTilt._x = XMIN 39 | request.Velocity.PanTilt._y = 0 40 | perform_move(ptz, request, timeout) 41 | 42 | def continuous_move(): 43 | mycam = ONVIFCamera('192.168.0.112', 80, 'admin', '12345') 44 | # Create media service object 45 | media = mycam.create_media_service() 46 | # Create ptz service object 47 | ptz = mycam.create_ptz_service() 48 | 49 | # Get target profile 50 | media_profile = media.GetProfiles()[0]; 51 | 52 | # Get PTZ configuration options for getting continuous move range 53 | request = ptz.create_type('GetConfigurationOptions') 54 | request.ConfigurationToken = media_profile.PTZConfiguration._token 55 | ptz_configuration_options = ptz.GetConfigurationOptions(request) 56 | 57 | request = ptz.create_type('ContinuousMove') 58 | request.ProfileToken = media_profile._token 59 | 60 | ptz.Stop({'ProfileToken': media_profile._token}) 61 | 62 | # Get range of pan and tilt 63 | # NOTE: X and Y are velocity vector 64 | global XMAX, XMIN, YMAX, YMIN 65 | XMAX = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Max 66 | XMIN = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Min 67 | YMAX = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Max 68 | YMIN = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Min 69 | 70 | # move right 71 | move_right(ptz, request) 72 | 73 | # move left 74 | move_left(ptz, request) 75 | 76 | # Move up 77 | move_up(ptz, request) 78 | 79 | # move down 80 | move_down(ptz, request) 81 | 82 | if __name__ == '__main__': 83 | continuous_move() 84 | -------------------------------------------------------------------------------- /examples/events.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from onvif import ONVIFCamera 3 | __author__ = 'vahid' 4 | 5 | 6 | if __name__ == '__main__': 7 | mycam = ONVIFCamera('192.168.1.10', 8899, 'admin', 'admin') #, no_cache=True) 8 | event_service = mycam.create_events_service() 9 | print(event_service.GetEventProperties()) 10 | 11 | pullpoint = mycam.create_pullpoint_service() 12 | req = pullpoint.create_type('PullMessages') 13 | req.MessageLimit=100 14 | print(pullpoint.PullMessages(req)) 15 | -------------------------------------------------------------------------------- /examples/rotate_image.py: -------------------------------------------------------------------------------- 1 | from onvif import ONVIFCamera 2 | 3 | def rotate_image_180(): 4 | ''' Rotate the image ''' 5 | 6 | # Create the media service 7 | mycam = ONVIFCamera('192.168.0.112', 80, 'admin', '12345') 8 | media_service = mycam.create_media_service() 9 | 10 | profiles = media_service.GetProfiles() 11 | 12 | # Use the first profile and Profiles have at least one 13 | token = profiles[0]._token 14 | 15 | # Get all video source configurations 16 | configurations_list = media_service.GetVideoSourceConfigurations() 17 | 18 | # Use the first profile and Profiles have at least one 19 | video_source_configuration = configurations_list[0] 20 | 21 | # Enable rotate 22 | video_source_configuration.Extension[0].Rotate[0].Mode[0] = 'OFF' 23 | 24 | # Create request type instance 25 | request = media_service.create_type('SetVideoSourceConfiguration') 26 | request.Configuration = video_source_configuration 27 | 28 | # ForcePersistence is obsolete and should always be assumed to be True 29 | request.ForcePersistence = True 30 | 31 | # Set the video source configuration 32 | media_service.SetVideoSourceConfiguration(request) 33 | 34 | if __name__ == '__main__': 35 | rotate_image_180() 36 | -------------------------------------------------------------------------------- /examples/streaming.py: -------------------------------------------------------------------------------- 1 | from onvif import ONVIFCamera 2 | 3 | def media_profile_configuration(): 4 | ''' 5 | A media profile consists of configuration entities such as video/audio 6 | source configuration, video/audio encoder configuration, 7 | or PTZ configuration. This use case describes how to change one 8 | configuration entity which has been already added to the media profile. 9 | ''' 10 | 11 | # Create the media service 12 | mycam = ONVIFCamera('192.168.0.112', 80, 'admin', '12345') 13 | media_service = mycam.create_media_service() 14 | 15 | profiles = media_service.GetProfiles() 16 | 17 | # Use the first profile and Profiles have at least one 18 | token = profiles[0]._token 19 | 20 | # Get all video encoder configurations 21 | configurations_list = media_service.GetVideoEncoderConfigurations() 22 | 23 | # Use the first profile and Profiles have at least one 24 | video_encoder_configuration = configurations_list[0] 25 | 26 | # Get video encoder configuration options 27 | options = media_service.GetVideoEncoderConfigurationOptions({'ProfileToken':token}) 28 | 29 | # Setup stream configuration 30 | video_encoder_configuration.Encoding = 'H264' 31 | # Setup Resolution 32 | video_encoder_configuration.Resolution.Width = \ 33 | options.H264.ResolutionsAvailable[0].Width 34 | video_encoder_configuration.Resolution.Height = \ 35 | options.H264.ResolutionsAvailable[0].Height 36 | # Setup Quality 37 | video_encoder_configuration.Quality = options.QualityRange.Min 38 | # Setup FramRate 39 | video_encoder_configuration.RateControl.FrameRateLimit = \ 40 | options.H264.FrameRateRange.Min 41 | # Setup EncodingInterval 42 | video_encoder_configuration.RateControl.EncodingInterval = \ 43 | options.H264.EncodingIntervalRange.Min 44 | # Setup Bitrate 45 | video_encoder_configuration.RateControl.BitrateLimit = \ 46 | options.Extension.H264[0].BitrateRange[0].Min[0] 47 | 48 | # Create request type instance 49 | request = media_service.create_type('SetVideoEncoderConfiguration') 50 | request.Configuration = video_encoder_configuration 51 | # ForcePersistence is obsolete and should always be assumed to be True 52 | request.ForcePersistence = True 53 | 54 | # Set the video encoder configuration 55 | media_service.SetVideoEncoderConfiguration(request) 56 | 57 | if __name__ == '__main__': 58 | media_profile_configuration() 59 | -------------------------------------------------------------------------------- /onvif/__init__.py: -------------------------------------------------------------------------------- 1 | from onvif.client import ONVIFService, ONVIFCamera, SERVICES 2 | from onvif.exceptions import ONVIFError, ERR_ONVIF_UNKNOWN, \ 3 | ERR_ONVIF_PROTOCOL, ERR_ONVIF_WSDL, ERR_ONVIF_BUILD 4 | from onvif import cli 5 | 6 | __all__ = ( 'ONVIFService', 'ONVIFCamera', 'ONVIFError', 7 | 'ERR_ONVIF_UNKNOWN', 'ERR_ONVIF_PROTOCOL', 8 | 'ERR_ONVIF_WSDL', 'ERR_ONVIF_BUILD', 9 | 'SERVICES', 'cli' 10 | ) 11 | -------------------------------------------------------------------------------- /onvif/cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | '''ONVIF Client Command Line Interface''' 3 | 4 | import re 5 | from cmd import Cmd 6 | from ast import literal_eval 7 | from json import dumps 8 | from argparse import ArgumentParser, ArgumentError, REMAINDER 9 | 10 | from suds import MethodNotFound 11 | from suds.sax.text import Text 12 | from onvif import ONVIFCamera, ONVIFService, ONVIFError 13 | from definition import SERVICES 14 | import os.path 15 | 16 | SUPPORTED_SERVICES = SERVICES.keys() 17 | 18 | class ThrowingArgumentParser(ArgumentParser): 19 | def error(self, message): 20 | usage = self.format_usage() 21 | raise ValueError("%s\n%s" % (message, usage)) 22 | 23 | def success(message): 24 | print 'True: ' + str(message) 25 | 26 | def error(message): 27 | print 'False: ' + str(message) 28 | 29 | class ONVIFCLI(Cmd): 30 | prompt = 'ONVIF >>> ' 31 | client = None 32 | cmd_parser = None 33 | 34 | def setup(self, args): 35 | ''' `args`: Instance of `argparse.ArgumentParser` ''' 36 | # Create onvif camera client 37 | self.client = ONVIFCamera(args.host, args.port, 38 | args.user, args.password, 39 | args.wsdl, encrypt=args.encrypt) 40 | 41 | 42 | # Create cmd argument parser 43 | self.create_cmd_parser() 44 | 45 | def create_cmd_parser(self): 46 | # Create parser to parse CMD, `params` is optional. 47 | cmd_parser = ThrowingArgumentParser(prog='ONVIF CMD', 48 | usage='CMD service operation [params]') 49 | cmd_parser.add_argument('service') 50 | cmd_parser.add_argument('operation') 51 | cmd_parser.add_argument('params', default='{}', nargs=REMAINDER) 52 | self.cmd_parser = cmd_parser 53 | 54 | def do_cmd(self, line): 55 | '''Usage: CMD service operation [parameters]''' 56 | try: 57 | args = self.cmd_parser.parse_args(line.split()) 58 | except ValueError as err: 59 | return error(err) 60 | 61 | # Check if args.service is valid 62 | if args.service not in SUPPORTED_SERVICES: 63 | return error('No Service: ' + args.service) 64 | 65 | args.params = ''.join(args.params) 66 | # params is optional 67 | if not args.params.strip(): 68 | args.params = '{}' 69 | 70 | # params must be a dictionary format string 71 | match = re.match(r"^.*?(\{.*\}).*$", args.params) 72 | if not match: 73 | return error('Invalid params') 74 | 75 | try: 76 | args.params = dict(literal_eval(match.group(1))) 77 | except ValueError as err: 78 | return error('Invalid params') 79 | 80 | try: 81 | # Get ONVIF service 82 | service = self.client.get_service(args.service) 83 | # Actually execute the command and get the response 84 | response = getattr(service, args.operation)(args.params) 85 | except MethodNotFound as err: 86 | return error('No Operation: %s' % args.operation) 87 | except Exception as err: 88 | return error(err) 89 | 90 | if isinstance(response, (Text, bool)): 91 | return success(response) 92 | # Try to convert instance to dictionary 93 | try: 94 | success(ONVIFService.to_dict(response)) 95 | except ONVIFError: 96 | error({}) 97 | 98 | def complete_cmd(self, text, line, begidx, endidx): 99 | # TODO: complete service operations 100 | # service.ws_client.service._ServiceSelector__services[0].ports[0].methods.keys() 101 | if not text: 102 | completions = SUPPORTED_SERVICES[:] 103 | else: 104 | completions = [ key for key in SUPPORTED_SERVICES 105 | if key.startswith(text) ] 106 | return completions 107 | 108 | def emptyline(self): 109 | return '' 110 | 111 | def do_EOF(self, line): 112 | return True 113 | 114 | def create_parser(): 115 | parser = ThrowingArgumentParser(description=__doc__) 116 | # Dealwith dependency for service, operation and params 117 | parser.add_argument('service', nargs='?', 118 | help='Service defined by ONVIF WSDL document') 119 | parser.add_argument('operation', nargs='?', default='', 120 | help='Operation to be execute defined' 121 | ' by ONVIF WSDL document') 122 | parser.add_argument('params', default='', nargs='?', 123 | help='JSON format params passed to the operation.' 124 | 'E.g., "{"Name": "NewHostName"}"') 125 | parser.add_argument('--host', required=True, 126 | help='ONVIF camera host, e.g. 192.168.2.123, ' 127 | 'www.example.com') 128 | parser.add_argument('--port', default=80, type=int, help='Port number for camera, default: 80') 129 | parser.add_argument('-u', '--user', required=True, 130 | help='Username for authentication') 131 | parser.add_argument('-a', '--password', required=True, 132 | help='Password for authentication') 133 | parser.add_argument('-w', '--wsdl', default=os.path.join(os.path.dirname(os.path.dirname(__file__)), "wsdl"), 134 | help='directory to store ONVIF WSDL documents') 135 | parser.add_argument('-e', '--encrypt', default='False', 136 | help='Encrypt password or not') 137 | parser.add_argument('-v', '--verbose', action='store_true', 138 | help='increase output verbosity') 139 | parser.add_argument('--cache-location', dest='cache_location', default='/tmp/onvif/', 140 | help='location to cache suds objects, default to /tmp/onvif/') 141 | parser.add_argument('--cache-duration', dest='cache_duration', 142 | help='how long will the cache be exist') 143 | 144 | return parser 145 | 146 | def main(): 147 | INTRO = __doc__ 148 | 149 | # Create argument parser 150 | parser = create_parser() 151 | try: 152 | args = parser.parse_args() 153 | except ValueError as err: 154 | print str(err) 155 | return 156 | # Also need parse configuration file. 157 | 158 | # Interactive command loop 159 | cli = ONVIFCLI(stdin=input) 160 | cli.setup(args) 161 | if args.service: 162 | cmd = ' '.join(['cmd', args.service, args.operation, args.params]) 163 | cli.onecmd(cmd) 164 | # Execute command specified and exit 165 | else: 166 | cli.cmdloop() 167 | 168 | if __name__ == '__main__': 169 | main() 170 | -------------------------------------------------------------------------------- /onvif/client.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.0.1' 2 | 3 | import os.path 4 | import urlparse 5 | import urllib 6 | from threading import Thread, RLock 7 | 8 | import logging 9 | logger = logging.getLogger('onvif') 10 | logging.basicConfig(level=logging.INFO) 11 | logging.getLogger('suds.client').setLevel(logging.CRITICAL) 12 | 13 | import suds.sudsobject 14 | from suds.client import Client 15 | from suds.wsse import Security, UsernameToken 16 | from suds.cache import ObjectCache, NoCache 17 | from suds_passworddigest.token import UsernameDigestToken 18 | from suds.bindings import binding 19 | binding.envns = ('SOAP-ENV', 'http://www.w3.org/2003/05/soap-envelope') 20 | 21 | from onvif.exceptions import ONVIFError 22 | from definition import SERVICES, NSMAP 23 | from suds.sax.date import UTC 24 | import datetime as dt 25 | # Ensure methods to raise an ONVIFError Exception 26 | # when some thing was wrong 27 | def safe_func(func): 28 | def wrapped(*args, **kwargs): 29 | try: 30 | return func(*args, **kwargs) 31 | except Exception as err: 32 | raise ONVIFError(err) 33 | return wrapped 34 | 35 | 36 | class UsernameDigestTokenDtDiff(UsernameDigestToken): 37 | ''' 38 | UsernameDigestToken class, with a time offset parameter that can be adjusted; 39 | This allows authentication on cameras without being time synchronized. 40 | Please note that using NTP on both end is the recommended solution, 41 | this should only be used in "safe" environements. 42 | ''' 43 | def __init__(self, user, passw, dt_diff=None) : 44 | # Old Style class ... sigh ... 45 | UsernameDigestToken.__init__(self, user, passw) 46 | self.dt_diff = dt_diff 47 | 48 | def setcreated(self, *args, **kwargs): 49 | dt_adjusted = None 50 | if self.dt_diff : 51 | dt_adjusted = (self.dt_diff + dt.datetime.utcnow()) 52 | UsernameToken.setcreated(self, dt=dt_adjusted, *args, **kwargs) 53 | self.created = str(UTC(self.created)) 54 | 55 | 56 | class ONVIFService(object): 57 | ''' 58 | Python Implemention for ONVIF Service. 59 | Services List: 60 | DeviceMgmt DeviceIO Event AnalyticsDevice Display Imaging Media 61 | PTZ Receiver RemoteDiscovery Recording Replay Search Extension 62 | 63 | >>> from onvif import ONVIFService 64 | >>> device_service = ONVIFService('http://192.168.0.112/onvif/device_service', 65 | ... 'admin', 'foscam', 66 | ... '/etc/onvif/wsdl/devicemgmt.wsdl') 67 | >>> ret = device_service.GetHostname() 68 | >>> print ret.FromDHCP 69 | >>> print ret.Name 70 | >>> device_service.SetHostname(dict(Name='newhostname')) 71 | >>> ret = device_service.GetSystemDateAndTime() 72 | >>> print ret.DaylightSavings 73 | >>> print ret.TimeZone 74 | >>> dict_ret = device_service.to_dict(ret) 75 | >>> print dict_ret['TimeZone'] 76 | 77 | There are two ways to pass parameter to services methods 78 | 1. Dict 79 | params = {'Name': 'NewHostName'} 80 | device_service.SetHostname(params) 81 | 2. Type Instance 82 | params = device_service.create_type('SetHostname') 83 | params.Hostname = 'NewHostName' 84 | device_service.SetHostname(params) 85 | ''' 86 | 87 | @safe_func 88 | def __init__(self, xaddr, user, passwd, url, 89 | cache_location='/tmp/suds', cache_duration=None, 90 | encrypt=True, daemon=False, ws_client=None, no_cache=False, portType=None, dt_diff = None): 91 | 92 | if not os.path.isfile(url): 93 | raise ONVIFError('%s doesn`t exist!' % url) 94 | 95 | if no_cache: 96 | cache = NoCache() 97 | else: 98 | # Create cache object 99 | # NOTE: if cache_location is specified, 100 | # onvif must has the permission to access it. 101 | cache = ObjectCache(location=cache_location) 102 | # cache_duration: cache will expire in `cache_duration` days 103 | if cache_duration is not None: 104 | cache.setduration(days=cache_duration) 105 | 106 | 107 | # Convert pathname to url 108 | self.url = urlparse.urljoin('file:', urllib.pathname2url(url)) 109 | self.xaddr = xaddr 110 | # Create soap client 111 | if not ws_client: 112 | self.ws_client = Client(url=self.url, 113 | location=self.xaddr, 114 | cache=cache, 115 | port=portType, 116 | headers={'Content-Type': 'application/soap+xml'}) 117 | else: 118 | self.ws_client = ws_client 119 | self.ws_client.set_options(location=self.xaddr) 120 | 121 | # Set soap header for authentication 122 | self.user = user 123 | self.passwd = passwd 124 | # Indicate wether password digest is needed 125 | self.encrypt = encrypt 126 | 127 | self.daemon = daemon 128 | 129 | self.dt_diff = dt_diff 130 | 131 | if self.user is not None and self.passwd is not None: 132 | self.set_wsse() 133 | 134 | # Method to create type instance of service method defined in WSDL 135 | self.create_type = self.ws_client.factory.create 136 | 137 | @safe_func 138 | def set_wsse(self, user=None, passwd=None): 139 | ''' Basic ws-security auth ''' 140 | if user: 141 | self.user = user 142 | if passwd: 143 | self.passwd = passwd 144 | 145 | security = Security() 146 | 147 | if self.encrypt: 148 | token = UsernameDigestTokenDtDiff(self.user, self.passwd, dt_diff=self.dt_diff) 149 | else: 150 | token = UsernameToken(self.user, self.passwd) 151 | token.setnonce() 152 | token.setcreated() 153 | 154 | security.tokens.append(token) 155 | self.ws_client.set_options(wsse=security) 156 | 157 | @classmethod 158 | @safe_func 159 | def clone(cls, service, *args, **kwargs): 160 | clone_service = service.ws_client.clone() 161 | kwargs['ws_client'] = clone_service 162 | return ONVIFService(*args, **kwargs) 163 | 164 | @staticmethod 165 | @safe_func 166 | def to_dict(sudsobject): 167 | # Convert a WSDL Type instance into a dictionary 168 | if sudsobject is None: 169 | return { } 170 | elif isinstance(sudsobject, list): 171 | ret = [ ] 172 | for item in sudsobject: 173 | ret.append(Client.dict(item)) 174 | return ret 175 | return Client.dict(sudsobject) 176 | 177 | def service_wrapper(self, func): 178 | @safe_func 179 | def wrapped(params=None, callback=None): 180 | def call(params=None, callback=None): 181 | # No params 182 | # print(params.__class__.__mro__) 183 | if params is None: 184 | params = {} 185 | elif isinstance(params, suds.sudsobject.Object): 186 | params = ONVIFService.to_dict(params) 187 | ret = func(**params) 188 | if callable(callback): 189 | callback(ret) 190 | return ret 191 | 192 | if self.daemon: 193 | th = Thread(target=call, args=(params, callback)) 194 | th.daemon = True 195 | th.start() 196 | else: 197 | return call(params, callback) 198 | return wrapped 199 | 200 | 201 | def __getattr__(self, name): 202 | ''' 203 | Call the real onvif Service operations, 204 | See the offical wsdl definition for the 205 | APIs detail(API name, request parameters, 206 | response parameters, parameter types, etc...) 207 | ''' 208 | builtin = name.startswith('__') and name.endswith('__') 209 | if builtin: 210 | return self.__dict__[name] 211 | else: 212 | return self.service_wrapper(getattr(self.ws_client.service, name)) 213 | 214 | class ONVIFCamera(object): 215 | ''' 216 | Python Implemention ONVIF compliant device 217 | This class integrates onvif services 218 | 219 | adjust_time parameter allows authentication on cameras without being time synchronized. 220 | Please note that using NTP on both end is the recommended solution, 221 | this should only be used in "safe" environements. 222 | Also, this cannot be used on AXIS camera, as every request is authenticated, contrary to ONVIF standard 223 | 224 | >>> from onvif import ONVIFCamera 225 | >>> mycam = ONVIFCamera('192.168.0.112', 80, 'admin', '12345') 226 | >>> mycam.devicemgmt.GetServices(False) 227 | >>> media_service = mycam.create_media_service() 228 | >>> ptz_service = mycam.create_ptz_service() 229 | # Get PTZ Configuration: 230 | >>> mycam.ptz.GetConfiguration() 231 | # Another way: 232 | >>> ptz_service.GetConfiguration() 233 | ''' 234 | 235 | def __init__(self, host, port ,user, passwd, wsdl_dir=os.path.join(os.path.dirname(os.path.dirname(__file__)), "wsdl"), 236 | cache_location=None, cache_duration=None, 237 | encrypt=True, daemon=False, no_cache=False, adjust_time=False): 238 | self.services_template = {'devicemgmt': None, 'ptz': None, 'media': None, 239 | 'imaging': None, 'events': None, 'analytics': None } 240 | self.use_services_template = {'devicemgmt': True, 'ptz': True, 'media': True, 241 | 'imaging': True, 'events': True, 'analytics': True } 242 | self.host = host 243 | self.port = int(port) 244 | self.user = user 245 | self.passwd = passwd 246 | self.wsdl_dir = wsdl_dir 247 | self.cache_location = cache_location 248 | self.cache_duration = cache_duration 249 | self.encrypt = encrypt 250 | self.daemon = daemon 251 | self.no_cache = no_cache 252 | self.adjust_time = adjust_time 253 | 254 | # Active service client container 255 | self.services = { } 256 | self.services_lock = RLock() 257 | 258 | # Set xaddrs 259 | self.update_xaddrs() 260 | 261 | self.to_dict = ONVIFService.to_dict 262 | 263 | def update_xaddrs(self): 264 | # Establish devicemgmt service first 265 | self.dt_diff = None 266 | self.devicemgmt = self.create_devicemgmt_service() 267 | if self.adjust_time : 268 | cdate = self.devicemgmt.GetSystemDateAndTime().UTCDateTime 269 | cam_date = dt.datetime(cdate.Date.Year, cdate.Date.Month, cdate.Date.Day, cdate.Time.Hour, cdate.Time.Minute, cdate.Time.Second) 270 | self.dt_diff = cam_date - dt.datetime.utcnow() 271 | self.devicemgmt.dt_diff = self.dt_diff 272 | self.devicemgmt.set_wsse() 273 | # Get XAddr of services on the device 274 | self.xaddrs = { } 275 | capabilities = self.devicemgmt.GetCapabilities({'Category': 'All'}) 276 | for name, capability in capabilities: 277 | try: 278 | if name.lower() in SERVICES: 279 | ns = SERVICES[name.lower()]['ns'] 280 | self.xaddrs[ns] = capability['XAddr'] 281 | except Exception: 282 | logger.exception('Unexcept service type') 283 | 284 | with self.services_lock: 285 | try: 286 | self.event = self.create_events_service() 287 | self.xaddrs['http://www.onvif.org/ver10/events/wsdl/PullPointSubscription'] = self.event.CreatePullPointSubscription().SubscriptionReference.Address 288 | except: 289 | pass 290 | 291 | 292 | def update_url(self, host=None, port=None): 293 | changed = False 294 | if host and self.host != host: 295 | changed = True 296 | self.host = host 297 | if port and self.port != port: 298 | changed = True 299 | self.port = port 300 | 301 | if not changed: 302 | return 303 | 304 | self.devicemgmt = self.create_devicemgmt_service() 305 | self.capabilities = self.devicemgmt.GetCapabilities() 306 | 307 | with self.services_lock: 308 | for sname in self.services.keys(): 309 | xaddr = getattr(self.capabilities, sname.capitalize).XAddr 310 | self.services[sname].ws_client.set_options(location=xaddr) 311 | 312 | def update_auth(self, user=None, passwd=None): 313 | changed = False 314 | if user and user != self.user: 315 | changed = True 316 | self.user = user 317 | if passwd and passwd != self.passwd: 318 | changed = True 319 | self.passwd = passwd 320 | 321 | if not changed: 322 | return 323 | 324 | with self.services_lock: 325 | for service in self.services.keys(): 326 | self.services[service].set_wsse(user, passwd) 327 | 328 | def get_service(self, name, create=True): 329 | service = None 330 | service = getattr(self, name.lower(), None) 331 | if not service and create: 332 | return getattr(self, 'create_%s_service' % name.lower())() 333 | return service 334 | 335 | def get_definition(self, name): 336 | '''Returns xaddr and wsdl of specified service''' 337 | # Check if the service is supported 338 | if name not in SERVICES: 339 | raise ONVIFError('Unknown service %s' % name) 340 | wsdl_file = SERVICES[name]['wsdl'] 341 | ns = SERVICES[name]['ns'] 342 | 343 | wsdlpath = os.path.join(self.wsdl_dir, wsdl_file) 344 | if not os.path.isfile(wsdlpath): 345 | raise ONVIFError('No such file: %s' % wsdlpath) 346 | 347 | # XAddr for devicemgmt is fixed: 348 | if name == 'devicemgmt': 349 | xaddr = 'http://%s:%s/onvif/device_service' % (self.host, self.port) 350 | return xaddr, wsdlpath 351 | 352 | # Get other XAddr 353 | xaddr = self.xaddrs.get(ns) 354 | if not xaddr: 355 | raise ONVIFError('Device doesn`t support service: %s' % name) 356 | 357 | return xaddr, wsdlpath 358 | 359 | def create_onvif_service(self, name, from_template=True, portType=None): 360 | '''Create ONVIF service client''' 361 | 362 | name = name.lower() 363 | xaddr, wsdl_file = self.get_definition(name) 364 | 365 | with self.services_lock: 366 | svt = self.services_template.get(name) 367 | # Has a template, clone from it. Faster. 368 | if svt and from_template and self.use_services_template.get(name): 369 | service = ONVIFService.clone(svt, xaddr, self.user, 370 | self.passwd, wsdl_file, 371 | self.cache_location, 372 | self.cache_duration, 373 | self.encrypt, 374 | self.daemon, 375 | no_cache=self.no_cache, portType=portType, dt_diff=self.dt_diff) 376 | # No template, create new service from wsdl document. 377 | # A little time-comsuming 378 | else: 379 | service = ONVIFService(xaddr, self.user, self.passwd, 380 | wsdl_file, self.cache_location, 381 | self.cache_duration, self.encrypt, 382 | self.daemon, no_cache=self.no_cache, portType=portType, dt_diff=self.dt_diff) 383 | 384 | self.services[name] = service 385 | 386 | setattr(self, name, service) 387 | if not self.services_template.get(name): 388 | self.services_template[name] = service 389 | 390 | return service 391 | 392 | def create_devicemgmt_service(self, from_template=True): 393 | # The entry point for devicemgmt service is fixed. 394 | return self.create_onvif_service('devicemgmt', from_template) 395 | 396 | def create_media_service(self, from_template=True): 397 | return self.create_onvif_service('media', from_template) 398 | 399 | def create_ptz_service(self, from_template=True): 400 | return self.create_onvif_service('ptz', from_template) 401 | 402 | def create_imaging_service(self, from_template=True): 403 | return self.create_onvif_service('imaging', from_template) 404 | 405 | def create_deviceio_service(self, from_template=True): 406 | return self.create_onvif_service('deviceio', from_template) 407 | 408 | def create_events_service(self, from_template=True): 409 | return self.create_onvif_service('events', from_template) 410 | 411 | def create_analytics_service(self, from_template=True): 412 | return self.create_onvif_service('analytics', from_template) 413 | 414 | def create_recording_service(self, from_template=True): 415 | return self.create_onvif_service('recording', from_template) 416 | 417 | def create_search_service(self, from_template=True): 418 | return self.create_onvif_service('search', from_template) 419 | 420 | def create_replay_service(self, from_template=True): 421 | return self.create_onvif_service('replay', from_template) 422 | 423 | def create_pullpoint_service(self, from_template=True): 424 | return self.create_onvif_service('pullpoint', from_template, portType='PullPointSubscription') 425 | 426 | def create_receiver_service(self, from_template=True): 427 | return self.create_onvif_service('receiver', from_template) 428 | -------------------------------------------------------------------------------- /onvif/definition.py: -------------------------------------------------------------------------------- 1 | SERVICES = { 2 | # Name namespace wsdl file 3 | 'devicemgmt': {'ns': 'http://www.onvif.org/ver10/device/wsdl', 'wsdl': 'devicemgmt.wsdl'}, 4 | 'media' : {'ns': 'http://www.onvif.org/ver10/media/wsdl', 'wsdl': 'media.wsdl' }, 5 | 'ptz' : {'ns': 'http://www.onvif.org/ver20/ptz/wsdl', 'wsdl': 'ptz.wsdl'}, 6 | 'imaging' : {'ns': 'http://www.onvif.org/ver20/imaging/wsdl', 'wsdl': 'imaging.wsdl'}, 7 | 'deviceio' : {'ns': 'http://www.onvif.org/ver10/deviceIO/wsdl', 'wsdl': 'deviceio.wsdl'}, 8 | 'events' : {'ns': 'http://www.onvif.org/ver10/events/wsdl', 'wsdl': 'events.wsdl'}, 9 | 'pullpoint' : {'ns': 'http://www.onvif.org/ver10/events/wsdl/PullPointSubscription', 'wsdl': 'events.wsdl'}, 10 | 'analytics' : {'ns': 'http://www.onvif.org/ver20/analytics/wsdl', 'wsdl': 'analytics.wsdl'}, 11 | 'recording' : {'ns': 'http://www.onvif.org/ver10/recording/wsdl', 'wsdl': 'recording.wsdl'}, 12 | 'search' : {'ns': 'http://www.onvif.org/ver10/search/wsdl', 'wsdl': 'search.wsdl'}, 13 | 'replay' : {'ns': 'http://www.onvif.org/ver10/replay/wsdl', 'wsdl': 'replay.wsdl'}, 14 | 'receiver' : {'ns': 'http://www.onvif.org/ver10/receiver/wsdl', 'wsdl': 'receiver.wsdl'}, 15 | } 16 | 17 | 18 | NSMAP = { } 19 | for name, item in SERVICES.items(): 20 | NSMAP[item['ns']] = name 21 | -------------------------------------------------------------------------------- /onvif/exceptions.py: -------------------------------------------------------------------------------- 1 | ''' Core exceptions raised by the ONVIF Client ''' 2 | 3 | from suds import WebFault, MethodNotFound, PortNotFound, \ 4 | ServiceNotFound, TypeNotFound, BuildError 5 | 6 | # Some version dont have this 7 | try: 8 | from suds import SoapHeadersNotPermitted 9 | with_soap_exc = True 10 | except ImportError: 11 | with_soap_exc = False 12 | 13 | # Error codes setting 14 | # Error unknown, e.g, HTTP errors 15 | ERR_ONVIF_UNKNOWN = 1 16 | # Protocol error returned by WebService, 17 | # e.g:DataEncodingUnknown, MissingAttr, InvalidArgs, ... 18 | ERR_ONVIF_PROTOCOL = 2 19 | # Error about WSDL instance 20 | ERR_ONVIF_WSDL = 3 21 | # Error about Build 22 | ERR_ONVIF_BUILD = 4 23 | 24 | 25 | class ONVIFError(Exception): 26 | def __init__(self, err): 27 | if isinstance(err, (WebFault, SoapHeadersNotPermitted) if with_soap_exc else WebFault): 28 | self.reason = err.fault.Reason.Text 29 | self.fault = err.fault 30 | self.code = ERR_ONVIF_PROTOCOL 31 | elif isinstance(err, (ServiceNotFound, PortNotFound, 32 | MethodNotFound, TypeNotFound)): 33 | self.reason = str(err) 34 | self.code = ERR_ONVIF_PROTOCOL 35 | elif isinstance(err, BuildError): 36 | self.reason = str(err) 37 | self.code = ERR_ONVIF_BUILD 38 | else: 39 | self.reason = 'Unknown error: ' + str(err) 40 | self.code = ERR_ONVIF_UNKNOWN 41 | 42 | def __str__(self): 43 | return self.reason 44 | -------------------------------------------------------------------------------- /onvif/version.txt: -------------------------------------------------------------------------------- 1 | 0.2.0 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.rst 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | 4 | here = os.path.abspath(os.path.dirname(__file__)) 5 | version_path = os.path.join(here, 'onvif/version.txt') 6 | version = open(version_path).read().strip() 7 | 8 | requires = [ 'suds >= 0.4', 'suds-passworddigest' ] 9 | 10 | CLASSIFIERS = [ 11 | 'Development Status :: 3 - Alpha', 12 | 'Environment :: Console', 13 | 'Intended Audience :: Customer Service', 14 | 'Intended Audience :: Developers', 15 | 'Intended Audience :: Education', 16 | 'Intended Audience :: Science/Research', 17 | 'Intended Audience :: Telecommunications Industry', 18 | 'Natural Language :: English', 19 | 'Operating System :: POSIX', 20 | 'Topic :: Software Development :: Libraries :: Python Modules', 21 | 'Topic :: Multimedia :: Sound/Audio', 22 | 'Topic :: Utilities', 23 | "Programming Language :: Python", 24 | "Programming Language :: Python :: 2", 25 | "Programming Language :: Python :: 2.6", 26 | "Programming Language :: Python :: 2.7", 27 | ] 28 | 29 | wsdl_files = [ 'wsdl/' + item for item in os.listdir('wsdl') ] 30 | 31 | setup( 32 | name='onvif', 33 | version=version, 34 | description='Python Client for ONVIF Camera', 35 | long_description=open('README.rst', 'r').read(), 36 | author='Cherish Chen', 37 | author_email='sinchb128@gmail.com', 38 | maintainer='sinchb', 39 | maintainer_email='sinchb128@gmail.com', 40 | license='MIT', 41 | keywords=['ONVIF', 'Camera', 'IPC'], 42 | url='http://github.com/quatanium/python-onvif', 43 | zip_safe=False, 44 | packages=find_packages(exclude=['docs', 'examples', 'tests']), 45 | install_requires=requires, 46 | include_package_data=True, 47 | data_files=[('wsdl', wsdl_files)], 48 | entry_points={ 49 | 'console_scripts': ['onvif-cli = onvif.cli:main'] 50 | } 51 | ) 52 | 53 | 54 | -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #-*-coding=utf-8 3 | 4 | import unittest 5 | 6 | from suds import WebFault 7 | 8 | from onvif import ONVIFCamera, ONVIFError 9 | 10 | CAM_HOST = '192.168.0.112' 11 | CAM_PORT = 80 12 | CAM_USER = 'admin' 13 | CAM_PASS = '12345' 14 | 15 | DEBUG = False 16 | 17 | def log(ret): 18 | if DEBUG: 19 | print ret 20 | 21 | class TestDevice(unittest.TestCase): 22 | 23 | # Class level cam. Run this test more efficiently.. 24 | cam = ONVIFCamera(CAM_HOST, CAM_PORT, CAM_USER, CAM_PASS) 25 | 26 | # ***************** Test Capabilities *************************** 27 | def test_GetWsdlUrl(self): 28 | ret = self.cam.devicemgmt.GetWsdlUrl() 29 | 30 | def test_GetServices(self): 31 | ''' 32 | Returns a cllection of the devices 33 | services and possibly their available capabilities 34 | ''' 35 | params = {'IncludeCapability': True } 36 | ret = self.cam.devicemgmt.GetServices(params) 37 | params = self.cam.devicemgmt.create_type('GetServices') 38 | params.IncludeCapability=False 39 | ret = self.cam.devicemgmt.GetServices(params) 40 | 41 | def test_GetServiceCapabilities(self): 42 | '''Returns the capabilities of the devce service.''' 43 | ret = self.cam.devicemgmt.GetServiceCapabilities() 44 | ret.Network._IPFilter 45 | 46 | def test_GetCapabilities(self): 47 | ''' 48 | Probides a backward compatible interface for the base capabilities. 49 | ''' 50 | categorys = ['PTZ', 'Media', 'Imaging', 51 | 'Device', 'Analytics', 'Events'] 52 | ret = self.cam.devicemgmt.GetCapabilities() 53 | for category in categorys: 54 | ret = self.cam.devicemgmt.GetCapabilities({'Category': category}) 55 | 56 | with self.assertRaises(ONVIFError): 57 | self.cam.devicemgmt.GetCapabilities({'Category': 'unknown'}) 58 | 59 | # *************** Test Network ********************************* 60 | def test_GetHostname(self): 61 | ''' Get the hostname from a device ''' 62 | self.cam.devicemgmt.GetHostname() 63 | 64 | def test_SetHostname(self): 65 | ''' 66 | Set the hostname on a device 67 | A device shall accept strings formated according to 68 | RFC 1123 section 2.1 or alternatively to RFC 952, 69 | other string shall be considered as invalid strings 70 | ''' 71 | pre_host_name = self.cam.devicemgmt.GetHostname() 72 | 73 | self.cam.devicemgmt.SetHostname({'Name':'testHostName'}) 74 | self.assertEqual(self.cam.devicemgmt.GetHostname().Name, 'testHostName') 75 | 76 | self.cam.devicemgmt.SetHostname(pre_host_name) 77 | 78 | def test_SetHostnameFromDHCP(self): 79 | ''' Controls whether the hostname shall be retrieved from DHCP ''' 80 | ret = self.cam.devicemgmt.SetHostnameFromDHCP(dict(FromDHCP=False)) 81 | self.assertTrue(isinstance(ret, bool)) 82 | 83 | def test_GetDNS(self): 84 | ''' Gets the DNS setting from a device ''' 85 | ret = self.cam.devicemgmt.GetDNS() 86 | self.assertTrue(hasattr(ret, 'FromDHCP')) 87 | if ret.FromDHCP == False: 88 | log(ret.DNSManual[0].Type) 89 | log(ret.DNSManual[0].IPv4Address) 90 | 91 | def test_SetDNS(self): 92 | ''' Set the DNS settings on a device ''' 93 | ret = self.cam.devicemgmt.SetDNS(dict(FromDHCP=False)) 94 | 95 | def test_GetNTP(self): 96 | ''' Get the NTP settings from a device ''' 97 | ret = self.cam.devicemgmt.GetNTP() 98 | if ret.FromDHCP == False: 99 | self.assertTrue(hasattr(ret, 'NTPManual')) 100 | log(ret.NTPManual) 101 | 102 | def test_SetNTP(self): 103 | '''Set the NTP setting''' 104 | ret = self.cam.devicemgmt.SetNTP(dict(FromDHCP=False)) 105 | 106 | def test_GetDynamicDNS(self): 107 | '''Get the dynamic DNS setting''' 108 | ret = self.cam.devicemgmt.GetDynamicDNS() 109 | log(ret) 110 | 111 | def test_SetDynamicDNS(self): 112 | ''' Set the dynamic DNS settings on a device ''' 113 | ret = self.cam.devicemgmt.GetDynamicDNS() 114 | ret = self.cam.devicemgmt.SetDynamicDNS(dict(Type=ret.Type, Name="random")) 115 | 116 | if __name__ == '__main__': 117 | unittest.main() 118 | -------------------------------------------------------------------------------- /wsdl/addressing: -------------------------------------------------------------------------------- 1 |  2 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | If "Policy" elements from namespace "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, they must appear first (before any extensibility elements). 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /wsdl/b-2.xsd: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 26 | 27 | 28 | 29 | 32 | 33 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 80 | 82 | 84 | 86 | 87 | 88 | 89 | 90 | 91 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 104 | 106 | 108 | 110 | 111 | 112 | 113 | 114 | 115 | 117 | 119 | 121 | 122 | 123 | 124 | 125 | 127 | 129 | 131 | 132 | 133 | 134 | 136 | 137 | 138 | 139 | 140 | 141 | 143 | 144 | 145 | 146 | 147 | 148 | 150 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 166 | 167 | 169 | 170 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 181 | 184 | 188 | 190 | 191 | 192 | 194 | 195 | 196 | 197 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 209 | 211 | 213 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 224 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 246 | 247 | 248 | 249 | 250 | 251 | 253 | 254 | 255 | 256 | 257 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 307 | 308 | 309 | 310 | 311 | 312 | 314 | 315 | 316 | 317 | 318 | 320 | 321 | 322 | 323 | 324 | 325 | 327 | 328 | 329 | 330 | 331 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 349 | 350 | 351 | 352 | 353 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 363 | 364 | 365 | 366 | 367 | 368 | 371 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 383 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 427 | 428 | 429 | 430 | 431 | 432 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 444 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 458 | 459 | 460 | 461 | 462 | 463 | 467 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 478 | 480 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 493 | 494 | 495 | 496 | 497 | 499 | 500 | 501 | 502 | 503 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 579 | 580 | 581 | -------------------------------------------------------------------------------- /wsdl/bf-2.xsd: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 26 | 29 | 31 | 32 | 33 | Get access to the xml: attribute groups for xml:lang as declared on 'schema' 34 | and 'documentation' below 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 48 | 50 | 52 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /wsdl/bw-2.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 17 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 47 | 48 | 49 | 50 | 51 | 57 | 58 | 60 | 61 | 62 | 63 | 65 | 66 | 67 | 68 | 70 | 71 | 72 | 73 | 75 | 76 | 77 | 78 | 80 | 81 | 82 | 83 | 85 | 86 | 87 | 88 | 90 | 91 | 92 | 93 | 95 | 96 | 97 | 98 | 100 | 101 | 102 | 103 | 105 | 106 | 107 | 108 | 110 | 111 | 112 | 116 | 117 | 119 | 120 | 121 | 122 | 124 | 125 | 126 | 127 | 129 | 130 | 131 | 132 | 134 | 135 | 136 | 137 | 139 | 140 | 141 | 142 | 144 | 145 | 146 | 150 | 151 | 153 | 154 | 155 | 156 | 158 | 159 | 160 | 161 | 163 | 164 | 165 | 166 | 170 | 171 | 173 | 174 | 175 | 176 | 178 | 179 | 180 | 181 | 183 | 184 | 185 | 189 | 190 | 192 | 193 | 194 | 195 | 197 | 198 | 199 | 200 | 202 | 203 | 204 | 208 | 209 | 211 | 212 | 213 | 214 | 216 | 217 | 218 | 219 | 221 | 222 | 223 | 227 | 228 | 230 | 231 | 232 | 233 | 235 | 236 | 237 | 238 | 240 | 241 | 242 | 246 | 247 | 249 | 250 | 251 | 252 | 254 | 255 | 256 | 257 | 259 | 260 | 261 | 265 | 266 | 268 | 269 | 270 | 271 | 273 | 274 | 275 | 276 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 295 | 297 | 299 | 301 | 303 | 305 | 307 | 309 | 311 | 313 | 315 | 317 | 318 | 319 | 320 | 321 | 322 | 324 | 326 | 328 | 330 | 332 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 342 | 344 | 346 | 348 | 349 | 350 | 351 | 353 | 355 | 357 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 371 | 373 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 383 | 385 | 387 | 390 | 391 | 392 | 394 | 396 | 398 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 410 | 412 | 414 | 417 | 418 | 419 | 421 | 423 | 425 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 436 | 438 | 439 | 440 | 441 | 442 | 444 | 446 | 447 | 448 | 449 | -------------------------------------------------------------------------------- /wsdl/envelope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Prose in the spec does not specify that attributes are allowed on the Body element 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | Fault reporting structure 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /wsdl/imaging.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | The capabilities for the imaging service is returned in the Capabilities element. 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Indicates whether or not Image Stabilization feature is supported. 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Reference token to the VideoSource for which the ImagingSettings. 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | ImagingSettings for the VideoSource that was requested. 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Reference token to the VideoSource for which the imaging parameter options are requested. 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | Valid ranges for the imaging parameters that are categorized as device specific. 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | Reference to the VideoSource for the requested move (focus) operation. 121 | 122 | 123 | 124 | 125 | 126 | 127 | Content of the requested move (focus) operation. 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | Reference token to the VideoSource for the requested move options. 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | Valid ranges for the focus lens move options. 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | Reference token to the VideoSource where the focus movement should be stopped. 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | Reference token to the VideoSource where the imaging status should be requested. 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | Requested imaging status. 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | Returns the capabilities of the imaging service. The result is returned in a typed answer. 267 | 268 | 269 | 270 | 271 | Get the ImagingConfiguration for the requested VideoSource. 272 | 273 | 274 | 275 | 276 | Set the ImagingConfiguration for the requested VideoSource. 277 | 278 | 279 | 280 | 281 | This operation gets the valid ranges for the imaging parameters that have device specific ranges. 282 | This command is mandatory for all device implementing the imaging service. The command returns all supported parameters and their ranges 283 | such that these can be applied to the SetImagingSettings command.
284 | For read-only parameters which cannot be modified via the SetImagingSettings command only a single option or identical Min and Max values 285 | is provided.
286 | 287 | 288 |
289 | 290 | The Move command moves the focus lens in an absolute, a relative or in a continuous manner from its current position. 291 | The speed argument is optional for absolute and relative control, but required for continuous. If no speed argument is used, the default speed is used. 292 | Focus adjustments through this operation will turn off the autofocus. A device with support for remote focus control should support absolute, 293 | relative or continuous control through the Move operation. The supported MoveOpions are signalled via the GetMoveOptions command. 294 | At least one focus control capability is required for this operation to be functional.
295 | The move operation contains the following commands:
296 | Absolute – Requires position parameter and optionally takes a speed argument. A unitless type is used by default for focus positioning and speed. Optionally, if supported, the position may be requested in m-1 units.
297 | Relative – Requires distance parameter and optionally takes a speed argument. Negative distance means negative direction. 298 | Continuous – Requires a speed argument. Negative speed argument means negative direction. 299 |
300 | 301 | 302 |
303 | 304 | Imaging move operation options supported for the Video source. 305 | 306 | 307 | 308 | 309 | The Stop command stops all ongoing focus movements of the lense. A device with support for remote focus control as signalled via 310 | the GetMoveOptions supports this command.
The operation will not affect ongoing autofocus operation.
311 | 312 | 313 |
314 | 315 | Via this command the current status of the Move operation can be requested. Supported for this command is available if the support for the Move operation is signalled via GetMoveOptions. 316 | 317 | 318 | 319 |
320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 |
401 | -------------------------------------------------------------------------------- /wsdl/include: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /wsdl/r-2.xsd: -------------------------------------------------------------------------------- 1 | 2 | 17 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /wsdl/receiver.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | The capabilities for the receiver service is returned in the Capabilities element. 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Indicates that the device can receive RTP multicast streams. 41 | 42 | 43 | 44 | 45 | Indicates that the device can receive RTP/TCP streams 46 | 47 | 48 | 49 | 50 | Indicates that the device can receive RTP/RTSP/TCP streams. 51 | 52 | 53 | 54 | 55 | The maximum number of receivers supported by the device. 56 | 57 | 58 | 59 | 60 | The maximum allowed length for RTSP URIs (Minimum and default value is 128 octet). 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | A list of all receivers that currently exist on the device. 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | The token of the receiver to be retrieved. 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | The details of the receiver. 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | The initial configuration for the new receiver. 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | The details of the receiver that was created. 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | The token of the receiver to be deleted. 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | The token of the receiver to be configured. 151 | 152 | 153 | 154 | 155 | The new configuration for the receiver. 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | The token of the receiver to be changed. 173 | 174 | 175 | 176 | 177 | The new receiver mode. Options available are: 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | The token of the receiver to be queried. 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | Description of the current receiver state. 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | Returns the capabilities of the receiver service. The result is returned in a typed answer. 264 | 265 | 266 | 267 | 268 | 269 | Lists all receivers currently present on a device. This operation is mandatory. 270 | 271 | 272 | 273 | 274 | 275 | 276 | Retrieves the details of a specific receiver. This operation is mandatory. 277 | 278 | 279 | 280 | 281 | 282 | 283 | Creates a new receiver. This operation is mandatory, although the service may 284 | raise a fault if the receiver cannot be created. 285 | 286 | 287 | 288 | 289 | 290 | 291 | Deletes an existing receiver. A receiver may be deleted only if it is not 292 | currently in use; otherwise a fault shall be raised. 293 | This operation is mandatory. 294 | 295 | 296 | 297 | 298 | 299 | 300 | Configures an existing receiver. This operation is mandatory. 301 | 302 | 303 | 304 | 305 | 306 | 307 | Sets the mode of the receiver without affecting the rest of its configuration. 308 | This operation is mandatory. 309 | 310 | 311 | 312 | 313 | 314 | 315 | Determines whether the receiver is currently disconnected, connected or 316 | attempting to connect. 317 | This operation is mandatory. 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | -------------------------------------------------------------------------------- /wsdl/remotediscovery.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /wsdl/replay.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | The capabilities for the replay service is returned in the Capabilities element. 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Indicator that the Device supports reverse playback as defined in the ONVIF Streaming Specification. 41 | 42 | 43 | 44 | 45 | The list contains two elements defining the minimum and maximum valid values supported as session timeout in seconds. 46 | 47 | 48 | 49 | 50 | Indicates support for RTP/RTSP/TCP. 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Specifies the connection parameters to be used for the stream. The URI that is returned may depend on these parameters. 63 | 64 | 65 | 66 | 67 | The identifier of the recording to be streamed. 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | The URI to which the client should connect in order to stream the recording. 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | Description of the new replay configuration parameters. 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | The current replay configuration parameters. 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | Returns the capabilities of the replay service. The result is returned in a typed answer. 147 | 148 | 149 | 150 | 151 | 152 | Requests a URI that can be used to initiate playback of a recorded stream 153 | using RTSP as the control protocol. The URI is valid only as it is 154 | specified in the response. 155 | This operation is mandatory. 156 | 157 | 158 | 159 | 160 | 161 | 162 | Returns the current configuration of the replay service. 163 | This operation is mandatory. 164 | 165 | 166 | 167 | 168 | 169 | 170 | Changes the current configuration of the replay service. 171 | This operation is mandatory. 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /wsdl/rw-2.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 25 | 26 | 27 | 28 | 33 | 34 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /wsdl/t-1.xsd: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 67 | 68 | 69 | 71 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 97 | 99 | 100 | 101 | 102 | 103 | 104 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | TopicPathExpression ::= TopicPath ( '|' TopicPath )* 143 | TopicPath ::= RootTopic ChildTopicExpression* 144 | RootTopic ::= NamespacePrefix? ('//')? (NCName | '*') 145 | NamespacePrefix ::= NCName ':' 146 | ChildTopicExpression ::= '/' '/'? (QName | NCName | '*'| '.') 147 | 148 | 149 | 150 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | The pattern allows strings matching the following EBNF: 161 | ConcreteTopicPath ::= RootTopic ChildTopic* 162 | RootTopic ::= QName 163 | ChildTopic ::= '/' (QName | NCName) 164 | 165 | 166 | 167 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | The pattern allows strings matching the following EBNF: 178 | RootTopic ::= QName 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /wsdl/types.xsd: -------------------------------------------------------------------------------- 1 | 2 | 28 | 33 | 34 | 35 | 36 | 37 | Type used to reference logical and physical entities. 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | General datastructure referenced by a token. 49 | Should be used as extension base. 50 | 51 | 52 | 53 | 54 | A service-unique identifier of the item. 55 | 56 | 57 | 58 | 59 | 60 | 61 | Type used for names of logical and physical entities. 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Description is optional and the maximum length is device specific. 73 | If the length is more than maximum length, it is silently chopped to the maximum length 74 | supported by the device/service (which may be 0). 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /wsdl/ws-addr.xsd: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /wsdl/ws-discovery.xsd: -------------------------------------------------------------------------------- 1 | 2 | 53 | 60 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 129 | 130 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 170 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 263 | 264 | 267 | 268 | 269 | 270 | 271 | 272 | -------------------------------------------------------------------------------- /wsdl/xml.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 |
11 |

About the XML namespace

12 | 13 |
14 |

15 | This schema document describes the XML namespace, in a form 16 | suitable for import by other schema documents. 17 |

18 |

19 | See 20 | http://www.w3.org/XML/1998/namespace.html and 21 | 22 | http://www.w3.org/TR/REC-xml for information 23 | about this namespace. 24 |

25 |

26 | Note that local names in this namespace are intended to be 27 | defined only by the World Wide Web Consortium or its subgroups. 28 | The names currently defined in this namespace are listed below. 29 | They should not be used with conflicting semantics by any Working 30 | Group, specification, or document instance. 31 |

32 |

33 | See further below in this document for more information about how to refer to this schema document from your own 35 | XSD schema documents and about the 36 | namespace-versioning policy governing this schema document. 37 |

38 |
39 |
40 |
41 |
42 | 43 | 44 | 45 | 46 |
47 | 48 |

lang (as an attribute name)

49 |

50 | denotes an attribute whose value 51 | is a language code for the natural language of the content of 52 | any element; its value is inherited. This name is reserved 53 | by virtue of its definition in the XML specification.

54 | 55 |
56 |
57 |

Notes

58 |

59 | Attempting to install the relevant ISO 2- and 3-letter 60 | codes as the enumerated possible values is probably never 61 | going to be a realistic possibility. 62 |

63 |

64 | See BCP 47 at 65 | http://www.rfc-editor.org/rfc/bcp/bcp47.txt 66 | and the IANA language subtag registry at 67 | 68 | http://www.iana.org/assignments/language-subtag-registry 69 | for further information. 70 |

71 |

72 | The union allows for the 'un-declaration' of xml:lang with 73 | the empty string. 74 |

75 |
76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |
88 | 89 | 90 | 91 | 92 |
93 | 94 |

space (as an attribute name)

95 |

96 | denotes an attribute whose 97 | value is a keyword indicating what whitespace processing 98 | discipline is intended for the content of the element; its 99 | value is inherited. This name is reserved by virtue of its 100 | definition in the XML specification.

101 | 102 |
103 |
104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 |
116 | 117 |

base (as an attribute name)

118 |

119 | denotes an attribute whose value 120 | provides a URI to be used as the base for interpreting any 121 | relative URIs in the scope of the element on which it 122 | appears; its value is inherited. This name is reserved 123 | by virtue of its definition in the XML Base specification.

124 | 125 |

126 | See http://www.w3.org/TR/xmlbase/ 128 | for information about this attribute. 129 |

130 |
131 |
132 |
133 |
134 | 135 | 136 | 137 | 138 |
139 | 140 |

id (as an attribute name)

141 |

142 | denotes an attribute whose value 143 | should be interpreted as if declared to be of type ID. 144 | This name is reserved by virtue of its definition in the 145 | xml:id specification.

146 | 147 |

148 | See http://www.w3.org/TR/xml-id/ 150 | for information about this attribute. 151 |

152 |
153 |
154 |
155 |
156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 |
167 | 168 |

Father (in any context at all)

169 | 170 |
171 |

172 | denotes Jon Bosak, the chair of 173 | the original XML Working Group. This name is reserved by 174 | the following decision of the W3C XML Plenary and 175 | XML Coordination groups: 176 |

177 |
178 |

179 | In appreciation for his vision, leadership and 180 | dedication the W3C XML Plenary on this 10th day of 181 | February, 2000, reserves for Jon Bosak in perpetuity 182 | the XML name "xml:Father". 183 |

184 |
185 |
186 |
187 |
188 |
189 | 190 | 191 | 192 |
193 |

About this schema document

194 | 195 |
196 |

197 | This schema defines attributes and an attribute group suitable 198 | for use by schemas wishing to allow xml:base, 199 | xml:lang, xml:space or 200 | xml:id attributes on elements they define. 201 |

202 |

203 | To enable this, such a schema must import this schema for 204 | the XML namespace, e.g. as follows: 205 |

206 |
207 |           <schema . . .>
208 |            . . .
209 |            <import namespace="http://www.w3.org/XML/1998/namespace"
210 |                       schemaLocation="http://www.w3.org/2001/xml.xsd"/>
211 |      
212 |

213 | or 214 |

215 |
216 |            <import namespace="http://www.w3.org/XML/1998/namespace"
217 |                       schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
218 |      
219 |

220 | Subsequently, qualified reference to any of the attributes or the 221 | group defined below will have the desired effect, e.g. 222 |

223 |
224 |           <type . . .>
225 |            . . .
226 |            <attributeGroup ref="xml:specialAttrs"/>
227 |      
228 |

229 | will define a type which will schema-validate an instance element 230 | with any of those attributes. 231 |

232 |
233 |
234 |
235 |
236 | 237 | 238 | 239 |
240 |

Versioning policy for this schema document

241 |
242 |

243 | In keeping with the XML Schema WG's standard versioning 244 | policy, this schema document will persist at 245 | 246 | http://www.w3.org/2009/01/xml.xsd. 247 |

248 |

249 | At the date of issue it can also be found at 250 | 251 | http://www.w3.org/2001/xml.xsd. 252 |

253 |

254 | The schema document at that URI may however change in the future, 255 | in order to remain compatible with the latest version of XML 256 | Schema itself, or with the XML namespace itself. In other words, 257 | if the XML Schema or XML namespaces change, the version of this 258 | document at 259 | http://www.w3.org/2001/xml.xsd 260 | 261 | will change accordingly; the version at 262 | 263 | http://www.w3.org/2009/01/xml.xsd 264 | 265 | will not change. 266 |

267 |

268 | Previous dated (and unchanging) versions of this schema 269 | document are at: 270 |

271 | 281 |
282 |
283 |
284 |
285 | 286 |
287 | 288 | -------------------------------------------------------------------------------- /wsdl/xmlmime: -------------------------------------------------------------------------------- 1 | 2 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | --------------------------------------------------------------------------------