Skip to content

Instantly share code, notes, and snippets.

@su-ex
Last active February 11, 2024 09:36
Show Gist options
  • Save su-ex/4b7a338a25b9dad72075fca3e4cc5b98 to your computer and use it in GitHub Desktop.
Save su-ex/4b7a338a25b9dad72075fca3e4cc5b98 to your computer and use it in GitHub Desktop.
(Re-)attach kvm+qemu usb devices for home assistant (haos in vm)
SUBSYSTEM=="usb", ATTR{idVendor}=="1915", ATTR{idProduct}=="0000", RUN+="/usr/sbin/hoas-usb-reattach.sh"
SUBSYSTEM=="usb", ATTR{idVendor}=="2341", ATTR{idProduct}=="0042", RUN+="/usr/sbin/hoas-usb-reattach.sh"

This is intended to fix the issue of kvm+qemu not having an usb device reappear inside the vm if the usb bus or device number changes on the host (e.g. due to replugging or a faulty controller) and thus home assistant running inside the vm looses connection to otbr-rcp, rflink, zigbee, ...

  1. Place the udev rule, e.g. as /etc/udev/rules.d/50-home-assistant.rules, and add all the relevant usb dongles with its vendor and device id (get the right ones with lsusb).
  2. Place the script, e.g. as /usr/sbin/hoas-usb-reattach.sh. Make sure to have the right path to the script in the udev rules file.
  3. chmod +x /usr/sbin/hoas-usb-reattach.sh
  4. udevadm control --reload-rules && udevadm trigger

Also make sure the usb devices have been added "normally" to the virsh config before, e.g. through virsh edit ... or graphically through virt-manager (to be entirely safe while the machine is off). They will look something like this:

<hostdev mode="subsystem" type="usb" managed="yes">
  <source>
    <vendor id="0x2341"/>
    <product id="0x0042"/>
  </source>
  <address type="usb" bus="0" port="5"/>
</hostdev>

Also make sure to remove old definitions like these:

<serial type='dev'>
  <source path='/dev/serial/by-id/usb-Arduino__www.arduino.cc__0042_2433331393035111F092-if00'/>
  <target type='usb-serial' port='5'>
    <model name='usb-serial'/>
  </target>
  <address type='usb' bus='0' port='5'/>
</serial>

The advantage of using the former over the latter is also that inside the vm devices will appear with some sensical name like /dev/serial/by-id/usb-Arduino__www.arduino.cc__0042_2433331393035111F092-if00 instead of some cryptic kvm generated non-useful name (so exactly the same name as on the host).

#!/bin/bash
# see: https://github.com/home-assistant/operating-system/issues/2756
# see: https://www.baeldung.com/linux/shell-run-script-usb-plugged
# see: https://stackoverflow.com/questions/10982911/creating-temporary-files-in-bash
# see: https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console
LOG_FILE="/var/log/hoas-usb-reattach.txt"
VIRSH_DOMAIN="home-assistant"
TMP_FILE=$(mktemp)
exec 3>&1 1>>${LOG_FILE} 2>&1
#echo "Full list of environment variables:"
#printenv
cat > "${TMP_FILE}" << EOL
<hostdev mode='subsystem' type='usb' managed='yes'>
<source>
<vendor id='0x${ID_VENDOR_ID}' />
<product id='0x${ID_MODEL_ID}' />
</source>
</hostdev>
EOL
echo "$(date): (Re-)attaching ${ID_USB_SERIAL} (${ID_VENDOR_ID}:${ID_MODEL_ID}) ..."
virsh detach-device "${VIRSH_DOMAIN}" "${TMP_FILE}" || true
virsh attach-device "${VIRSH_DOMAIN}" "${TMP_FILE}"
rm "${TMP_FILE}"
# This is where you might want to restart the home assistant integrations or addons, if necessary
# (filter for ${ID_VENDOR_ID} and ${ID_MODEL_ID} to get the right one).
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment