0

I'm having trouble with an app I'm writing for a monitoring device. I've got a RaspberryPi4 that runs a python script with three threads. One of these threads manages a camera for recording video. When I startup the pi with the camera attached, it works just fine. However, when I startup the device without this USB camera attached my program fails to find the camera.

As is, the program looks for a valid video device under the /dev folder of the raspberrypi. I've noticed that when I disconnect the camera or reconnect it, these video devices will appear and disappear under the /def folder. However, my python program fails to detect these changes. It's like it has one chance to detect if the camera is attached at boot and then cannot detect it after.

What's interesting is that if it starts with the camera attached, I can disconnect and reconnect the camera without issue. Has anyone else run into an issue like this? Here is the part of my code that is meant to try and connect to the camera.

def cameraConnect(self,device):
    # Clear the cache
    os.sync()
    # try connecting to camera
    self.cap = cv2.VideoCapture(-1)
    #Find the camera devices
    devices = []
    files = os.listdir('/dev/')
    print(files)
    for file in files:
        if file.startswith('video'):
            devices.append(os.path.join('/dev', file))
    print("Devices found: ", devices)
    #Check if the camera is attached
    
   
    if len(devices) < 1:
        print("No devices found, trying defaults")
        devices = ['/dev/video0', '/dev/video1', '/dev/video2', '/dev/video3', '/dev/video4','-1']
    for dev in devices:
        print("Connecting to ", dev)
        self.cap = cv2.VideoCapture(dev)
        if self.cap.isOpened():
            print(f"Successfully opened {dev}")
            device = dev
            self.is_camera_attached = True 
            break
        else:
            print(f"Failed to open {dev}")

Using os.listdir and os.scandir I try and find these video devices under /dev. Those being video0 through video3 which the code will then try to connect to each of them. This program will loop, trying to connect to either the default or found video devices under /dev but the devices are either found when the program starts or not at all. That is dependent on whether or not the camera is connected. I thought maybe it was a caching issue, but I believe os.sync should prove that is not the case. I'm uncertain if this is a python or a raspberrypi issue?

Any help would be greatly appreciated, thanks.

Edited for more detail.

  • Your question would be better placed on the [Raspberry Pi stack](https://raspberrypi.stackexchange.com/) – DrBwts May 05 '23 at 16:08
  • @Bib, RPI has two camera interfaces. The OP is talking about the USB-type camera. All USB devices in fact are hot pluggable. You might be referring to the RPi Cam Web Interface (not USB) which may not be hot pluggable, not sure, but irrelevant to this issue. – Velimir Mlaker May 05 '23 at 16:30
  • @VelimirMlaker Oh B@ll@cks! – Bib May 05 '23 at 20:11

1 Answers1

1

Instead of using /dev/video* paths in your code, install the v4l-utils Apt package, and then use the explicit ID paths that become visible under directories /dev/v4l/by-id/ or /dev/v4l/by-path/.

The enumerations of paths /dev/video* may change boot-to-boot or even during continuous uptime when hot-unplugging/replugging a USB camera, or even as power and bandwidth limits toggle a connected USB camera ON/OFF, with the camera acquiring a different number each time (often incrementing).

The way to assure getting a consistent path to your USB camera device, use instead paths visible in the /dev/v4l/ directory. These remain the same, even when a device toggles OFF and back ON intermittently.

For example, my system shows:

$ ls -la /dev/video*
crw-rw----+ 1 root video 81, 0 Apr 26 17:06 /dev/video0
crw-rw----+ 1 root video 81, 1 Apr 26 17:06 /dev/video1
$
$
$ tree /dev/v4l/
/dev/v4l/
├── by-id
│   ├── usb-046d_0809_440639A4-video-index0 -> ../../video0
│   └── usb-046d_0809_440639A4-video-index1 -> ../../video1
└── by-path
    ├── pci-0000:00:14.0-usb-0:9:1.0-video-index0 -> ../../video0
    └── pci-0000:00:14.0-usb-0:9:1.0-video-index1 -> ../../video1

With the example above, instead of using,

/dev/video0

I would prefer to use,

/dev/v4l/by-id/usb-046d_0809_440639A4-video-index0

While /dev/video0 may change to a different enumeration over time, the specific ID path will always point to originally-intended device since it is identified by a unique manufacturer-assigned ID.

Velimir Mlaker
  • 10,664
  • 4
  • 46
  • 58
  • Thanks for your reply, this solved one issue but confirmed another. In this way, when the video* devices under /dev change between hot-swaps this gets around that problem. But there is still a problem with my program where it seems to get one shot at detecting what is under the /dev folder. If I start the program without a usb camera, I can see in my printouts that there are no video devices nor a v4l folder under /dev. If I later connect a camera to my pi I can see through the Pi that the video* and v4l folder appear, but my program doesn't pickup this change still. Progress though! – mal_function May 05 '23 at 18:04
  • Now that you have a static path to the camera, you'll have to add the connection-retry logic to your code made of 1) detecting when a camera disconnects, and then 2) connecting to camera (probably some kind of a continuous loop). – Velimir Mlaker May 06 '23 at 11:10