Solving immediate disconnect of AI-Thinker ESP32 Cam

Who knows it was also a braille reader?

esp32esp32-camai-thinkerembeddedbrailleudevlinux

April 30, 2022

Problem

So I recently bought an AI-Thinker ESP32-Cam. Excitedly I plugged it into my Linux Machine and started coding right away. Typically it should be at /dev/ttyUSB0:

$ ls -l /dev/ttyUSB0
ls: cannot access '/dev/ttyUSB0': No such file or directory

Fine, I knew it wouldn’t be this easy. So after:

$ sudo dmesg | less

and some scrolling:

[20374.922353] usb 3-1: new full-speed USB device number 5 using xhci_hcd
[20375.076362] usb 3-1: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice=81.32
[20375.076368] usb 3-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[20375.076370] usb 3-1: Product: USB Serial
[20375.081400] ch341 3-1:1.0: ch341-uart converter detected
[20375.095414] usb 3-1: ch341-uart converter now attached to ttyUSB0
[20375.136468] audit: type=1130 audit(1651301626.547:332): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=brltt
y-device@sys-devices-pci0000:00-0000:00:08.1-0000:08:00.3-usb3-3\x2d1 comm="systemd" exe="/usr/lib/systemd/systemd" h
ostname=? addr=? terminal=? res=success'
[20375.164942] audit: type=1130 audit(1651301626.573:333): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=brltt
y@-sys-devices-pci0000:00-0000:00:08.1-0000:08:00.3-usb3-3\x2d1 comm="systemd" exe="/usr/lib/systemd/systemd" hostnam
e=? addr=? terminal=? res=success'
[20375.171343] usb 3-1: usbfs: interface 0 claimed by ch341 while 'brltty' sets config #1
[20375.174426] ch341-uart ttyUSB0: ch341-uart converter now disconnected from ttyUSB0
[20375.174438] ch341 3-1:1.0: device disconnected

Solution (Dirty fix)

It turned out brltty grabbed my ESP32. Hmmmm? what is brltty? A quick search gave me:

BRLTTY is a background process (daemon) which provides access to the Linux/Unix console (when in text mode) for a blind person using a refreshable braille display.

Luckily, so far my glasses still manage to negate my myopia. Let’s figure out where brltty comes from and just disable it.

Since from dmesg it looked like brltty is configured with systemd:

$ systemctl list-unit-files brl*
UNIT FILE              STATE    VENDOR PRESET
brltty.path            disabled disabled
brltty@.path           disabled disabled
brltty-device@.service static
brltty@.service        static

Let’s mask them:

$ sudo systemctl mask 'brltty@'
$ sudo systemctl mask 'brltty-device@'
$ sudo dmesg -w

and reattach esp32-cam:

[22494.348107] usb 3-1: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice=81.32
[22494.348114] usb 3-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[22494.348117] usb 3-1: Product: USB Serial
[22494.353150] ch341 3-1:1.0: ch341-uart converter detected
[22494.367150] usb 3-1: ch341-uart converter now attached to ttyUSB0
$ ls -l /dev/ttyUSB*
crw-rw---- 1 root uucp 188, 0 Apr 30 15:29 /dev/ttyUSB0

Great. Problem solved! Or… was it?

Solution (real)

The solution was quick and easy - if I was not visually challenged. What if I had to use brltty?

First thought: blacklist esp32-cam’s vendor + product id.

But how? Another search gave me this archlinux post:

https://bbs.archlinux.org/viewtopic.php?pid=2002314#p2002314

Take a note of the ID and then open the brltty rules file: "sudo nano /usr/lib/udev/rules.d/90-brltty-device.rules"

Search through the file until you find the entry for your ID:

# Device: 1A86:7523
# Baum [NLS eReader Zoomax (20 cells)]
ENV{PRODUCT}=="1a86/7523/\*", ENV{BRLTTY_BRAILLE_DRIVER}="bm", GOTO="brltty_usb_run"

Now comment out the line:

# Device: 1A86:7523
# Baum [NLS eReader Zoomax (20 cells)]
# ENV{PRODUCT}=="1a86/7523/*", ENV{BRLTTY_BRAILLE_DRIVER}="bm", GOTO="brltty_usb_run"

Save and close the file then reboot.

So if you recalled from the dirty solution:

[22494.348107] usb 3-1: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice=81.32

Vendor id and product id happened to be the same as the BBS thread’s. Note that it might be different so it is important to check the actual ones with dmesg.

So in /usr/lib/udev/rules.d/90-brltty-device.rules with vendor id 1A86 and product id 7523:

# Device: 1A86:7523
# Baum [NLS eReader Zoomax (20 cells)]
# Commented out! Uncomment if you have to use this
# ENV{PRODUCT}=="1a86/7523/*", ENV{BRLTTY_BRAILLE_DRIVER}="bm", GOTO="brltty_usb_run"

I was able to avoid a reboot by:

$ sudo udevadm control --reload-rules && sudo udevadm trigger

Using with Braille Reader with the same vendor and product ID

It this case usually the reader is only one device, it is a good idea to instead specify the USB port this device is now plugged into:

First find out where the reader is plugged into:

$ lsusb -t -v

In my case, it gave me this for the esp32-cam. For braille reader users, you should be looking for your braille device.

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 26, If 0, Class=Vendor Specific Class, Driver=ch341, 12M
        ID 1a86:7523 QinHeng Electronics CH340 serial converter

Take note of Bus’s and Port’s values. Then construct it into a part of a udev rule:

# format: <Bus>-<Port>
KERNELS=="3-1"

(note this might be longer if you plugged it into a USB hub - it might take the form something like KERNELS=="3-1.2.1" instead.)

and append it to the end of brltty device udev rule (remember to uncomment if you’ve previously commented the device):

# Device: 1A86:7523
# Baum [NLS eReader Zoomax (20 cells)]
ENV{PRODUCT}=="1a86/7523/*", ENV{BRLTTY_BRAILLE_DRIVER}="bm", GOTO="brltty_usb_run", KERNELS=="3-1"

then of course reload and trigger:

$ sudo udevadm control --reload-rules && sudo udevadm trigger

I do not own a braille reader so I was not able to verify this solution but my esp32-cam did get caught by brltty only if I plugged it into this USB port. Contact me if I was wrong!

End

That’s it :) Have a good day!