Zigbee2MQTT startet nicht – CC2531: Failed to connect to the adapter

In Kombination mit dem Zigbee USB-Stick CC2531 und dem Dienst Zigbee2MQTT kann es hin und wieder zu dieser Fehlermeldung kommen:

Zigbee2MQTT:error#033[39m 2020-10-02 23:08:59: Failed to start zigbee
Zigbee2MQTT:error#033[39m 2020-10-02 23:08:59: Exiting...
Zigbee2MQTT:error#033[39m 2020-10-02 23:08:59: Error: Failed to connect to the adapter (Error: SRSP - SYS - ping after 6000ms)
npm[51940]:     at ZStackAdapter.<anonymous> (/opt/zigbee2mqtt/node_modules/zigbee-herdsman/dist/adapter/z-stack/adapter/zStackAdapter.js:92:31)
npm[51940]:     at Generator.throw (<anonymous>)
npm[51940]:     at rejected (/opt/zigbee2mqtt/node_modules/zigbee-herdsman/dist/adapter/z-stack/adapter/zStackAdapter.js:25:65)

Spannend ist hierbei die Meldung „Failed to connect to the adapter“ und einem offenbaren Timeout.

Seitens Maintainer gibt es scheinbar hierfür keine wirkliche Lösung, außer man betätigt nach einem Neustart des Zigbee2MQTT-Dienst den Reset-Button. Für ein Remote-Setup ist dieser Workaround natürlich inakzeptabel. Abhilfe schafft hier auch ein USB-Reset über den Linux-Kernel (USBDEVFS_RESET).

Also brauchen wir folgendes C-Programm, um den Kernel-Reset gegen das USB-Device zu initiieren, bevor der Zigbee2MQTT-Dienst gestartet wird:

/* usbreset -- send a USB port reset to a USB device */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>

#include <linux/usbdevice_fs.h>


int main(int argc, char **argv)
{
    const char *filename;
    int fd;
    int rc;

    if (argc != 2) {
        fprintf(stderr, "Usage: usbreset device-filename\n");
        return 1;
    }
    filename = argv[1];

    fd = open(filename, O_WRONLY);
    if (fd < 0) {
        perror("Error opening output file");
        return 1;
    }

    printf("Resetting USB device %s\n", filename);
    rc = ioctl(fd, USBDEVFS_RESET, 0);
    if (rc < 0) {
        perror("Error in ioctl");
        return 1;
    }
    printf("Reset successful\n");

    close(fd);
    return 0;
}

Dazu müssen wir den C-Code noch kompilieren und das Binary ablegen:

cc -o usbreset usbreset.c
mv usbreset /usr/local/src/

Nun muss nur für die entsprechende Systemd-Service Beschreibung das ExecStartPre vor dem ExecStart eingefügt werden.

ExecStartPre=/usr/local/bin/usbreset-zigbee.sh
ExecStart=/usr/bin/npm start

Das Script wird benötigt, damit nach dem Reset der Stick Zeit hat zum Starten, bevor der eigentliche Dienst gestartet wird. Das Bash-Script usbreset-zigbee.sh sieht lediglich so aus:

#!/bin/bash
usbreset /dev/bus/usb/002/024
sleep 10

/dev/bus/usb/002/024 ist das eigentliche USB-Device und kann mit Hilfe von ‚lsusb‘ ermittelt werden. 10 Sekunden haben sich bei mir bewährt, damit der Zigbee2MQTT-Dienst zuverlässig starten kann.

Credits: usbreset.c: https://gist.github.com/jahil

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert