@perryflynn wrote:
Hi,
I am working on a reliable connection of my Zigbee Dongle (Conbee II) to Home Assistant Core which is running as Docker Container. I am using
usbip
to bring the Zigbee Dongle from a Raspberry Pi to my Docker Server.On the Raspberry Pi I have already a reboot-safe and hotplug-stable solution. Here the implementation steps as Ansible Playbook:
--- # root@dashboard:/etc/systemd/system# lsusb -d 1cf1:0030 -v # Bus 001 Device 011: ID 1cf1:0030 Dresden Elektronik # Device Descriptor: # bLength 18 # bDescriptorType 1 # bcdUSB 2.01 # bDeviceClass 2 Communications # bDeviceSubClass 0 # bDeviceProtocol 0 # bMaxPacketSize0 64 # idVendor 0x1cf1 Dresden Elektronik # idProduct 0x0030 # bcdDevice 1.00 # iManufacturer 1 dresden elektronik ingenieurtechnik GmbH # iProduct 2 ConBee II # iSerial 3 DE2154525 # bNumConfigurations 1 # # -> Zigbee Host # - name: Setup usbip on Zigbee Stick Host hosts: - dashboard vars: usbvendorid: "1cf1" usbproductid: "0030" tasks: - name: Install usbip package: name: usbip state: present - name: Load kernel modules at boot copy: dest: /etc/modules-load.d/usbipd.conf owner: root group: root mode: u=rw,go=r content: | # load kernel modules needed for usbip daemon # this file is managed by ansible usbip_host - name: Load kernel modules now modprobe: name: usbip_host state: present - name: "Create vendor:product bind script for usbip" copy: dest: /usr/sbin/usbip-bind-vendorproduct owner: root group: root mode: u=rwx,go=r content: | #!/bin/bash VENDORPRODUCT=$(echo "$1" | sed 's/-/:/g') MODE=$2 BUSID=$(usbip list -l | grep -oP "busid\s+([0-9\-\.]+)\s+\(${VENDORPRODUCT}\)" | head -n 1 | awk '{print $2}') USBIPACTIVE=$(pidof usbipd 2>&1 > /dev/null; echo $?) if [ $USBIPACTIVE -ne 0 ]; then echo "usbip daemon is not running" exit 1 fi if [ "$MODE" == "bind" ]; then /usr/sbin/usbip bind -b $BUSID elif [ "$MODE" == "unbind" ]; then /usr/sbin/usbip unbind -b $BUSID else echo "Unknown Mode" exit 1 fi - name: Create systemd unit for the zigbee stick copy: dest: /etc/systemd/system/usbip-device@.service owner: root group: root mode: u=rw,go=r content: | [Unit] Description=USB/IP Binding on %I After=network-online.target usbipd.service Wants=network-online.target Requires=usbipd.service [Service] Type=simple ExecStart=/usr/sbin/usbip-bind-vendorproduct %i bind RemainAfterExit=yes ExecStop=/usr/sbin/usbip-bind-vendorproduct %i unbind Restart=on-failure [Install] WantedBy=multi-user.target - name: Create systemd unit for usbip copy: dest: /etc/systemd/system/usbipd.service owner: root group: root mode: u=rw,go=r content: | [Unit] Description=USB/IP server After=network.target [Service] ExecStart=/usr/sbin/usbipd [Install] WantedBy=multi-user.target - name: Enable and start usbip dongle systemd: daemon_reload: yes enabled: yes name: "usbip-device@{{usbvendorid}}-{{usbproductid}}" - name: Enable and start usbipd service systemd: daemon_reload: yes enabled: yes name: usbipd state: started - name: Create udev hotplug trigger script copy: dest: /usr/sbin/usbip-hotplug-trigger owner: root group: root mode: u=rwx,go=r content: | #!/bin/bash /usr/sbin/usbip-bind-vendorproduct ${ID_VENDOR_ID}:${ID_MODEL_ID} bind - name: Create udev rule for hotplug dongle copy: dest: /etc/udev/rules.d/usbip.rules owner: root group: root mode: u=rw,go=r content: | ACTION=="add", ATTR{idVendor}=="{{usbvendorid}}", ATTR{idProduct}=="{{usbproductid}}", RUN+="/usr/sbin/usbip-hotplug-trigger" register: dongleudevrule - name: Restart udev service: name: udev state: restarted when: dongleudevrule.changed
Now the problem: The implementation of the communication between the usb device and hass is not reconnect-safe. If there is any issue with the communication between, the container needs to be restarted.
I am able to bring the usb device into the container with cgroup rules, so that I can hotplug:
docker create \ --init \ --name "hass" \ --hostname hass \ --network hassinternal \ --device-cgroup-rule='c 166:0 rmw' \ -v /containerdata/homeassistant:/config \ -v /etc/localtime:/etc/localtime:ro \ homeassistant/home-assistant:latest
Now I can start the container and add the device right afterwards. (If this works without any issues, I would create an extension of the container image and to the creation of the usb device via startup script.)
usbip attach -r dashboard -b 1-1.4 docker start hass docker exec hass mknod /dev/ttyACM0 c 166 0
Until this point, it works without any problems. But if I detach the device or if there is a network issue, hass throws an exception and the implementation is broken until I restart the container:
2020-04-05 09:58:14 WARNING (MainThread) [zigpy_deconz.api] No response to 'Command.write_parameter' command 2020-04-05 09:58:14 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved Traceback (most recent call last): File "/usr/local/lib/python3.7/site-packages/zigpy_deconz/zigbee/application.py", line 36, in _reset_watchdog await self._api.write_parameter(NetworkParameter.watchdog_ttl, 3600) File "/usr/local/lib/python3.7/site-packages/zigpy_deconz/api.py", line 210, in _command return await asyncio.wait_for(fut, timeout=COMMAND_TIMEOUT) File "/usr/local/lib/python3.7/asyncio/tasks.py", line 449, in wait_for raise futures.TimeoutError() concurrent.futures._base.TimeoutError 2020-04-05 09:58:49 WARNING (MainThread) [zigpy_deconz.api] No response to 'Command.aps_data_request' command
Is there any way to make this more stable?
It would be awesome to have an reconnect mechanism in hass. I’ve already looked into the code, but my python skills are not strong enough.
Kind Regards
Christian
Posts: 1
Participants: 1