quatanium / python-onvif

ONVIF Client Implementation in Python
MIT License
470 stars 315 forks source link

Can use only one ONVIFCamera instance at a time #11

Open elsampsa opened 9 years ago

elsampsa commented 9 years ago

Hi,

Thanks for the nice module. It works like charm .. .. except when one is trying to connect to several (2+) cameras simultaneously.

The included python code demonstrates the problem.. just change the ip addresses in the main method's cams list.

When there is only one camera in the list it works ok (tried with both cameras individually), however, when there are two cameras in the list, it gives

(400, u'Bad Request')

while trying to get the media profiles for the second camera in the list.

The only way I can make two cameras work with this onvif module simultaneously, is to start them as individual processes (i.e. using python's multiprocessing module).

I'd please like to know why such behaviour and if it could be easily fixed.

Kind Regards,

Sampsa

import onvif
import sys

def run(ip, user, passwd, interactive=True, launchcam=False):

  dx=0.1
  dy=0.1
  dz=0.1

  print
  print "Patience.. this will take a while.."
  print

  mycam = onvif.ONVIFCamera(ip, 80, user, passwd) 

  ptz=mycam.create_ptz_service()
  med=mycam.create_media_service() # the output of this can be found in "media_service.txt"
  # .. from the media service, we need a thing called "ProfileToken"

  # """
  pro=med.GetProfiles()[0] # in fact, there are three profiles.. for main stream, sub stream and third stream
  profiletoken=pro._token
  # """

  nodes=ptz.GetNodes()
  nodetoken=nodes[0]._token
  node=nodes[0]

  # lets check if this camera can do all required ptzs
  ok=True
  if (not hasattr(node,"SupportedPTZSpaces")): ok=False
  if (ok and (not hasattr(node.SupportedPTZSpaces,"RelativeZoomTranslationSpace"))): ok=False
  if (ok and (not hasattr(node.SupportedPTZSpaces,"RelativePanTiltTranslationSpace"))): ok=False

  if not ok:
    print "woops.. some relative movement possibilities are absent from this crappy camera"
    raise(Exception,"CrappyCam")

  print "Testing presets.."
  print
  gp=ptz.create_type('GetPresets')
  gp.ProfileToken=profiletoken
  presets=ptz.GetPresets(gp)
  c=1
  for preset in presets:
    if (hasattr(preset,"Name")): 
      name=preset.Name
    else:
      name=""
    print "preset>",name
    c+=1
  print
  print ".. presets ok"

  print "Relative zoom min and max values:",node.SupportedPTZSpaces.RelativeZoomTranslationSpace[0].XRange.Min,node.SupportedPTZSpaces.RelativeZoomTranslationSpace[0].XRange.Max
  print "Relative pan/tilt min and max values, x:",node.SupportedPTZSpaces.RelativePanTiltTranslationSpace[0].XRange.Min,node.SupportedPTZSpaces.RelativePanTiltTranslationSpace[0].XRange.Max
  print "Relative pan/tilt min and max values, y:",node.SupportedPTZSpaces.RelativePanTiltTranslationSpace[0].YRange.Min,node.SupportedPTZSpaces.RelativePanTiltTranslationSpace[0].YRange.Max
  print
  print "Controls: arrows keys, +/- for zooming.  Enter exits. Have fun!"
  print

  # lets prepare the relativemove object ..
  rm=ptz.create_type('RelativeMove')
  rm.ProfileToken=profiletoken

  if (interactive):
    if (launchcam):
      st="vlc rtsp://"+user+":"+passwd+"@"+ip
      p=subprocess.Popen(st,shell=True)
    # *** Lets prepare stdin ***
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    tty.setraw(sys.stdin.fileno())

    # *** The main loop ***
    ok=True
    while ok:
      com=""
      inp=sys.stdin.read(1)
      if (ord(inp)==27):
        inp=sys.stdin.read(1)
        if (ord(inp)==91):
          # so this is an arrow key ..
          inp=sys.stdin.read(1)
          code=ord(inp)
          if (code==68):
            com="left"
          elif (code==65):
            com="up"
          elif (code==67):
            com="right"
          elif (code==66):
            com="down"
      else:
        code=ord(inp)
        if (code==43):
          com="in"
        elif (code==45):
          com="out"
        elif (code==13):
          com="exit"

      # print "com>",com  

      if (com!="" and com!="exit"):
        rm.Translation.PanTilt._x="0.0"
        rm.Translation.PanTilt._y="0.0"
        rm.Translation.Zoom._x="0.0"

      if (com=="exit"): 
        ok=False
      elif (com=="left"):
        print "left\n"
        rm.Translation.PanTilt._x=str(-dx)
      elif (com=="up"):
        print "up\n"
        rm.Translation.PanTilt._y=str(dy)
      elif (com=="right"):
        print "right\n"
        rm.Translation.PanTilt._x=str(dx)
      elif (com=="down"):  
        print "down\n"
        rm.Translation.PanTilt._y=str(-dy)
      elif (com=="in"):  
        print "zoom in\n"
        rm.Translation.Zoom._x=str(dz)
      elif (com=="out"): 
        print "zoom out\n"
        rm.Translation.Zoom._x=str(-dz)

      if (com!="" and com!="exit"):
        try:
          ptz.RelativeMove(rm)
        except:
          print "woops.. something went wrong!"
          ok=False
        print "\n"

      time.sleep(0.1)

    # recover terminal ..
    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    if (launchcam): p.terminate()

  else: # not interactive ..
    return mycam, profiletoken, ptz

if (__name__=="__main__"):
  cams=[
      ["192.168.1.151","admin","12345"],
      ["192.168.1.156","admin","12345"]
    ]
  for cam in cams:
    run(cam[0], cam[1], cam[2], interactive=False, launchcam=False)
sinchb commented 9 years ago

Sorry for my late response. I'm in vacation... Thanks for your report :) I haven't run more than one instance in single process, but I think there is something wrong with suds cache. you can set the on_cache to True and try again:

 mycam = onvif.ONVIFCamera(ip, 80, user, passwd, on_cache=True) 
ZaphodBox commented 7 years ago

did you find a permanent solution ? I have similar sort of issue. I have Panasonic BL-VT164W & APKLINK HI3518e. Let's call them cam1 & cam2 I first tried using single ONVIFCamera instance & send their details (i.e ip,port, username & password) one by one. If I created cam1's instance & then cam2 -> it's OK But if I created cam2's instance & then tried for cam1, it would show error

  File "C:\Python27\lib\site-packages\onvif-0.1.3-py2.7.egg\onvif\client.py", line 257, in __init__

  File "C:\Python27\lib\site-packages\onvif-0.1.3-py2.7.egg\onvif\client.py", line 273, in update_xaddrs
    capabilities = self.devicemgmt.GetCapabilities({'Category': 'All'})
  File "C:\Python27\lib\site-packages\onvif-0.1.3-py2.7.egg\onvif\client.py", line 32, in wrapped
    raise ONVIFError(err)
onvif.exceptions.ONVIFError: Sender not Authorized
[Finished in 4.5s]

Then I tried using 2 instances of ONVIFCamera class, Still the camera creation order matters,& shows gives me same error as above

fengzie commented 6 years ago

I also meet 2 cameras problem when creating pullpoint.

The code is like below:

cam_list = {
    "192.168.1.218" : CamInfo("192.168.1.218", "admin", "12345"),
    "192.168.1.126" : CamInfo("192.168.1.126", "admin", "12345")
}

for cam in cam_list.values():
    logger.info("Init ONVIF Camera, ip: {}, user: {}, password: {}".format(cam.ip, cam.user, cam.password))
    cam.onvifCam = ONVIFCamera(cam.ip, 80, cam.user, cam.password, no_cache=True)
    cam.pullpoint = cam.onvifCam.create_pullpoint_service()

When ran 2 camera instances, it would show error

Traceback (most recent call last): File "client.py", line 4, in from audio_play_service import AudioService File "/home/pi/elevator_client/audio_play_service.py", line 1, in import cam_info File "/home/pi/elevator_client/cam_info.py", line 38, in cam.pullpoint = cam.onvifCam.create_pullpoint_service() File "/usr/local/lib/python2.7/dist-packages/onvif-0.2.0-py2.7.egg/onvif/client.py", line 425, in create_pullpoint_service return self.create_onvif_service('pullpoint', from_template, portType='PullPointSubscription') File "/usr/local/lib/python2.7/dist-packages/onvif-0.2.0-py2.7.egg/onvif/client.py", line 364, in create_onvif_service xaddr, wsdl_file = self.get_definition(name) File "/usr/local/lib/python2.7/dist-packages/onvif-0.2.0-py2.7.egg/onvif/client.py", line 356, in get_definition raise ONVIFError('Device doesnt support service: %s' % name) onvif.exceptions.ONVIFError: Unknown error: Device doesnt support service: pullpoint

There is no problem to run one camera. Is there some fix for the code?