USB-Reset - Brauche Unterstützung für skript

Begonnen von Homalix99, 08 Mai 2019, 22:36:31

Vorheriges Thema - Nächstes Thema

Homalix99

Hallo,
bei mir hängt ein Jee-Link mit einem 5 M USB Kabel am RPi (geht nicht kürzer, wegen Empfang von der WS1600 (Wetterstation).
Hin und wieder hängt sich die Kommunikation auf USB auf und es hilft ein automatischer USB reset.
Das Problem war die fehlende Unterscheidung zwischen den einzelnen USB-Devices. (siehe hier:)

pi@RPI_FHEM:/opt/fhem/log $ lsusb
Bus 001 Device 009: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 001 Device 008: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 001 Device 007: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 001 Device 006: ID 2a03:0043 dog hunter AG Arduino Uno Rev3
Bus 001 Device 005: ID 05e3:0610 Genesys Logic, Inc. 4-port hub
Bus 001 Device 004: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub


Für den USB Reset benötige ich die Devicenummer, aber welche der drei mit der ID 0403:6001 ist es?
Dummerweise sind das alles USB-Teile mit dem gleichen 232 UART chipsatz.
Ein ls -la auf /dev/serial/by-id zeigt den Jee-Link an:

pi@RPI_FHEM:/opt/fhem/log $ ls -la /dev/serial/by-id/
total 0
drwxr-xr-x 2 root root 140 May  8 19:43 .
drwxr-xr-x 4 root root  80 May  8 19:43 ..
lrwxrwxrwx 1 root root  13 May  8 19:43 usb-1a86_USB2.0-Serial-if00-port0 -> ../../ttyUSB3
lrwxrwxrwx 1 root root  13 May  8 19:43 usb-Arduino_Srl_Arduino_Uno_8543130363635110E0D2-if00 -> ../../ttyACM0
lrwxrwxrwx 1 root root  13 May  8 19:43 usb-FTDI_FT232R_USB_UART_AH065FCR-if00-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root  13 May  8 19:43 usb-FTDI_FT232R_USB_UART_AI04PGKK-if00-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root  13 May  8 19:43 usb-FTDI_FT232R_USB_UART_DAE06aa8-if00-port0 -> ../../ttyUSB2

Es ist der mit dem Devicenamen AI04PGKK, jedoch fehlt die Zuordnung zum Devicenamen.
Eine Abfrage mit
sudo cat /sys/kernel/debug/usb/devices | grep -E "^([TS]:.*|)$"
wirft folgende Liste aus, in der die Verknüpfung zu finden ist:

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=480  MxCh= 1
S:  Manufacturer=Linux 4.14.79-v7+ dwc_otg_hcd
S:  Product=DWC OTG Controller
S:  SerialNumber=3f980000.usb

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=480  MxCh= 5

T:  Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=480  MxCh= 0

T:  Bus=01 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12   MxCh= 0
S:  Manufacturer=FTDI
S:  Product=FT232R USB UART
S:  SerialNumber=AI04PGKK

T:  Bus=01 Lev=02 Prnt=02 Port=04 Cnt=03 Dev#=  5 Spd=480  MxCh= 4
S:  Manufacturer=GenesysLogic
S:  Product=USB2.0 Hub

T:  Bus=01 Lev=03 Prnt=05 Port=00 Cnt=01 Dev#=  6 Spd=12   MxCh= 0
S:  Manufacturer=Arduino Srl
S:  Product=Arduino Uno
S:  SerialNumber=8543130363635110E0D2

T:  Bus=01 Lev=03 Prnt=05 Port=01 Cnt=02 Dev#=  7 Spd=12   MxCh= 0
S:  Manufacturer=FTDI
S:  Product=FT232R USB UART
S:  SerialNumber=AH065FCR

T:  Bus=01 Lev=03 Prnt=05 Port=02 Cnt=03 Dev#=  8 Spd=12   MxCh= 0
S:  Manufacturer=FTDI
S:  Product=FT232R USB UART
S:  SerialNumber=DAE06aa8

T:  Bus=01 Lev=03 Prnt=05 Port=03 Cnt=04 Dev#=  9 Spd=12   MxCh= 0
S:  Product=USB2.0-Serial

Es ist das Device Nummer 4:
T:  Bus=01 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12   MxCh= 0
S:  Manufacturer=FTDI
S:  Product=FT232R USB UART
S:  SerialNumber=AI04PGKK.
So, nach jedem reboot des Pis ändert sich die Devicenummer.
Ich möchte daher vor einem automatischen reboot des USB-Ports (an dem der Jee-Link hängt) die korrekte Nummer ermitteln und bräuchte eine Hilfestellung.
Das skript müsste alle Zeilen der o. g. Datei (geht nur mit root) absuchen, bis der Suchbegriff "AI04PGKK" auftaucht, dann die Zeile, welche 3 Zeilen oberhalb ist einlesen und den Wert bei Dev#= isolieren und zurückliefern. Habe es schon mit RegEx uber mehrere Zeilen versucht, komme aber nicht weiter.
Ist bestimmt hilfreich, da unter linux das mapping nur sehr kompliziert zu erreichen scheint.
Kann da jemand helfen?
Vielen dank im voraus

VG

Alex
- RPI 4 fhem in Docker, 2 x Arduino Uno, HM-GW, HM-Dev. (Fensterkontakte, HK-Thermostate, div. Aktoren), JeeLink,
- GPIOs, HM-LAN, ESPs (MQTT2)
-Überwachung Fenster/Türen/Licht, HK-Thermostatregelung, Rollosteuerung, Überw. Betriebstemperaturen Heizung, Erfassung Gas/Wasser, PV-Anl., Wetter (WS1600)

KölnSolar

Hi Alex,
das serial/by-id reicht nicht ?
Wie sähe der Reset-Befehl konkret aus ?
Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

mumpitzstuff

/Dev#=\s*(\d+).*(?:\r\n|\r|\n).*(?:\r\n|\r|\n).*(?:\r\n|\r|\n).*AI04PGKK/m

Nicht schön aber selten...

Wernieman

Kleine Frage .. wie Resettest Du denn "eine" Device?
- Bitte um Input für Output
- When there is a Shell, there is a Way
- Wann war Dein letztes Backup?

Wie man Fragen stellt: https://tty1.net/smart-questions_de.html

Homalix99

Hallo,

@mumpitzstuff: Danke für die Regex: Frage: Wie bau ich die in ein script (perl oder bash ?) ein?
Hatte bislang für die RegEx nur auf shell-Ebene experimentiert, also:
cat <dateipfad/dateiname> | grep -E "RegEx"
und die Ausgabe erstmal im Terminalfenster verfolgt, weiter bin ich nicht gekommen.

@KölnSolar + Wernieman:
Der USB-Reset erfolgt durch ein kompiliertes c-Prg. , welches folgenden  Sourcecode hat:

/* 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;
}

Es wird als Argument die Devicenummer übergeben.
Funktioniert einwandfrei, nur ich muss bisher nach einem RPi Restart immer die entsprechende Devicenummer händisch ermitteln und in die Aufruf-Sequenz (via watchdog getriggert eintragen. Und genau das soll automatisch erfolgen.

VG

Alex
- RPI 4 fhem in Docker, 2 x Arduino Uno, HM-GW, HM-Dev. (Fensterkontakte, HK-Thermostate, div. Aktoren), JeeLink,
- GPIOs, HM-LAN, ESPs (MQTT2)
-Überwachung Fenster/Türen/Licht, HK-Thermostatregelung, Rollosteuerung, Überw. Betriebstemperaturen Heizung, Erfassung Gas/Wasser, PV-Anl., Wetter (WS1600)

KölnSolar

Interessant. So etwas suchte ich auch immer mal.

Basiert auf libusb. Die gibt es mittlerweile auch für Perl USB::LibUSB mit Funktion reset_device(). Lief mir schon mal in FHEM über die Füße...hier.

Das müsste sich doch glatt in ein Modul packen lassen.  :-\
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

Wernieman

@Köln-Solar:
Dafür  ;D

(Sorry fürs OT werden ...)
- Bitte um Input für Output
- When there is a Shell, there is a Way
- Wann war Dein letztes Backup?

Wie man Fragen stellt: https://tty1.net/smart-questions_de.html

KölnSolar

#7
Du überforderst mich. Verstehe nicht, was Du meinst.  :-[

Ich hab mir mal mit CPAN das Paket installiert. Dann das attachte Skript zusammengeschustert: Scheint zu klappen. Zumindest steht im Kernellog, dass der USB-Stick resettet wurde. Im laufenden Betrieb von FHEM keine Auffälligkeiten mit dem device.  8)
Edit: Attachement wg. neuerer Version(s.u.) gelöscht.
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

Wernieman

Meine Antwort bezog sich auf:
ZitatDas müsste sich doch glatt in ein Modul packen lassen.  :-\

Das Script sieht interessant aus .. muß ich mir mal übers Wochenende ansehen ...
- Bitte um Input für Output
- When there is a Shell, there is a Way
- Wann war Dein letztes Backup?

Wie man Fragen stellt: https://tty1.net/smart-questions_de.html

KölnSolar

Ah. Dann war es doch gar nicht so OT.  ;)

Das Skript ist eigentlich sehr simpel. Nur die Vendor- und Product-Id eintragen. Wenn es mehrere devices zu der Kombination gibt, auch noch die Serialno.(sofern es die gibt). Dann aber den Zugriff ...vid_pid_serial aktivieren und vid_pid deaktivieren. Scheinbar muss bei "eingebundenen" devices mit sudo gestartet werden.

So sieht das dann beispielhaft bei meinem RFXTRX aus:
pi@raspberrypi:/opt $ sudo perl testUSBreset.pl
USBResetUSB : device vendor 1027 and product 24577 opened
USBResetUSB : device vendor 1027 and product 24577 resetted

im FHEM-Log:2019.05.10 09:47:12 1: /dev/serial/by-id/usb-RFXCOM_RFXtrx433_02VEJQFT-if00-port0 disconnected, waiting to reappear (TRXUSB)
2019.05.10 09:47:13 3: Setting TRXUSB serial parameters to 38400,8,N,1
2019.05.10 09:47:16 1: TRX: Init OK
2019.05.10 09:47:16 1: TRX: Init status: 'RFXrec433 433.92MHz transceiver, hardware=1.0, output power=10dBm, firmware=1025, protocols enabled: Lighting4,RSL,Hideki/TFA/Cresta/UPM,AC,ARC,Oregon,'
2019.05.10 09:47:16 1: /dev/serial/by-id/usb-RFXCOM_RFXtrx433_02VEJQFT-if00-port0 reappeared (TRXUSB)

und PI-Log[ 3302.924423] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
[ 3302.924468] ftdi_sio 1-1.4.1:1.0: device disconnected
[ 3303.021274] usb 1-1.4.1: reset full-speed USB device number 7 using dwc_otg
[ 3303.164863] ftdi_sio 1-1.4.1:1.0: FTDI USB Serial Device converter detected
[ 3303.164973] usb 1-1.4.1: Detected FT232RL
[ 3303.165822] usb 1-1.4.1: FTDI USB Serial Device converter now attached to ttyUSB0


Scheint also zu machen, was es soll. So richtig kann ich es dann erst testen, wenn ich mal wieder einen "Hänger" an einem der USB-devices habe.

Attached eine etwas erweiterte Version.

Ein Modul wäre vielleicht etwas oversized, aber als Funktion ließe es sich ja in der myUtils nutzen.

RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

Homalix99

Also ich hab zwischenzeitlich etwas gebastelt, was funktioniert.
Ich verwende weiterhin das kompiliete c-Script.
Also bei mir geht es wie erwähnt um den Reset der Wetterdaten Schnittstelle (Jee-Link)
Wenn also mehr als 30 Min. keine Änderung der Daten erfolgt, wird der watchdog aktiv und

(WS_1600) 00:30 SAME {
  Log3sub("JeeLinkDown_watchdog","JeeLinkDown","WS_1600 empfängt keine Daten mehr");
  my $res = Jee_Link_Reset(); # USB-Reset
  fhem("trigger JeeLinkDown .");
  if($res) {
     mailout("FHEM-Service","JeeLink Ausfall\nReset wurde durch USB-Reset behoben");
  }
  else {
     mailout("FHEM-Service","JeeLink Ausfall\nReset konnte durch USB-Reset nicht behoben werden");
  }
}

ruft folgende Routine in der 99_myUtils.pm auf:

sub USB_Reset($)
{
  my ($usbdevnr) = @_;
  my $name ="USB_Reset";
  my $cmd = sprintf("sudo /opt/fhem/scripts/usbreset/usbreset /dev/bus/usb/001/%s",$usbdevnr);
  system("$cmd");
  #Log3 undef, 3,"$name: String: $cmd wurde ausgeführt";
  return;
} # End USB_Reset()


sub Jee_Link_Reset() {
my $name = "Jee_Link_Reset"; # name of sub
my $file = "/opt/fhem/log/usblist.txt"; # define File for pre-filtered USB device list
my $USB_devno; # USB device number
system("/opt/fhem/scripts/usblist/usblist.scr $file"); # generate this list via shellscript into log dir
open(my $fh, '<', $file) or die "Can't open '$file' for read: $!"; # open the USB device list
  my @lines;
  while (my $line = <$fh>) {
      push (@lines, $line);    # line by line into array
  }
  close $fh or die "Cannot close $file: $!";
  my $str; # linecontent
  my $i=0; # linecounter
  foreach my $n (@lines) {
     $str = $lines[$i];
if($str =~ m/AI04PGKK/) { # if line contents of devicename of Jee-Link
    #Log3 undef, 3,"$i: $lines[$i-3]";
if ($lines[$i-3]  =~ m/Dev#=(.*)\sSpd/) { # if 3 lines before contains of "Dev#=", take value
   $USB_devno = sprintf("%03d",$1);
   USB_Reset($USB_devno);
   Log3 undef, 3,"$name: JeeLink Ausfall wurde durch Reset von USB: $USB_devno getriggert";
   return 1;
}
}
$i++;
  }
  return 0;
} # End Jee_Link_Reset()


Dabei wird vor dem reset mit usblist.scr eine gefilterte USB device Liste erstellt, welche im Anschluss dann von Jee_Link_Reset() eingelesen und das entsprechende Device ermittelt wird.
Der eigentliche USB reset erfolgt mit USB_Reset($)

Script usblist.scr:

sudo cat /sys/kernel/debug/usb/devices | grep -E "^([TS]:.*|)$" > $1


VG

Alex
- RPI 4 fhem in Docker, 2 x Arduino Uno, HM-GW, HM-Dev. (Fensterkontakte, HK-Thermostate, div. Aktoren), JeeLink,
- GPIOs, HM-LAN, ESPs (MQTT2)
-Überwachung Fenster/Türen/Licht, HK-Thermostatregelung, Rollosteuerung, Überw. Betriebstemperaturen Heizung, Erfassung Gas/Wasser, PV-Anl., Wetter (WS1600)

KölnSolar

Hi Alex,
viele Wege führen nach Rom.  ;)

Ich wollte eine Perllösung anbieten. Wenn Du mein Skript/Funktion nutzt, müsste es mit # Jeelink(FTDI)  use with vid_pid_serial
   my $VENDOR = 0x0403;
   my $PRODUCT = 0x6001;
   my $SERIAL = "AI04PGKK";
funktionieren und Du sparst die Systembefehle, file....

Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

Homalix99

Hallo Markus,

vielen Dank. Hat sich irgendwie überschnitten. Deine Lösung klingt interessant. Kannst Du mir diese mal zustellen?
Dann werde ich diese verwenden, da meine ziemlich umständlich ist.

VG

Alex
- RPI 4 fhem in Docker, 2 x Arduino Uno, HM-GW, HM-Dev. (Fensterkontakte, HK-Thermostate, div. Aktoren), JeeLink,
- GPIOs, HM-LAN, ESPs (MQTT2)
-Überwachung Fenster/Türen/Licht, HK-Thermostatregelung, Rollosteuerung, Überw. Betriebstemperaturen Heizung, Erfassung Gas/Wasser, PV-Anl., Wetter (WS1600)

KölnSolar

Hi Alex,
ich hab doch oben beschrieben, wie man die Grundlage schafft und auch das Skript attached.

Wenn Du es als Funktion in Deine myutils einbaust, kannst Du es ähnlich Deiner Vorgehensweise nutzen.
Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

jw2013

Ich habe ein ähnliches Problem, ein paar IR Leseköpfe hängen an einem USB-Hub, der über ca. 10m Cat.7 Kabel und Pegelwandler angebunden ist.
Funktioniert eigentlich top, aber alle paar Tage hängt sich die mit dem Hub Kommunikation auf.

Wenn man in udev die Rechte des Geräts passend setzt, könnte man den USB Reset auch direkt in FHEM ausführen, ohne ein kompiliertes C-Programm dazwischen.
"ioctl" ist in Perl drin, und "USBDEVFS_RESET" ist eine Konstante mit dem Wert 21780.

# use constant USBDEVFS_RESET => 21780; 

perl -w -e 'use Fcntl; sysopen(U, "/dev/bus/usb/001/003", O_WRONLY) or die "$!"; print fileno(U)." ".ioctl(U, 21780, 0)."\n";'


funktioniert bei mir, dort ist der betroffene Hub das 3. Gerät am 1. Bus.