So schön die Welt des Hotplugging und USB auch sein mag; es gibt Situationen da möchte man, dass das angesteckte Gerät immer unter dem gleichen Devicenamen ansprechbar ist. Um das zu ermöglichen, muß unter Linux selbst Hand angelegt werden.
Im folgenden Beispiel gehe ich davon aus, das für FHEM ein CUL Device immer unter /dev/cul868 und eine FHZ 1300 PC von ELV immer unter /dev/fhz1300pc mit den richtigen Rechten ansprechbar ist.
Doch vorab ein kurzes, vereinfachtes Vorwort zu udev. Vereinfacht weil mit udev auch recht komplexe Aufgaben gelöst werden können, die aber hier den Rahmen sprengen würden. Man könnte z.B. realisieren, das nach dem Einstecken einer FHZ 1300 PC automatisch FHEM gestartet und beim Abziehen der FHZ 1300 PC FHEM automatisch beendet wird. Ob das nun einen Sinn ergibt sei mal dahin gestellt.
udev überwacht und wertet sogenannte Hotplug-Ereignisse aus. Wird z.B. ein neues USB-Gerät angesteckt, dann wird udev die Informationen des Gerätes anhand definierter Regeln auswerten und entsprechende Aktionen auslösen wie z.B. eine Gerätedatei anlegen. Das USB-Gerät ist dann unter der von udev angelegten Gerätedatei im /dev/-Verzeichnis ansprechbar.
In den mir bekannten Linux-Distributionen hat man die Möglichkeit im Verzeichnis /etc/udev/rules.d/ eigene Regeln zu definieren. Dabei ist im ersten Schritt die Vergabe des richtigen Dateinames wichtig. Es gilt zwei Grundsätze zu beachten:
Die niedrige, zweistellige Zahl am Anfang des Dateinamens ist notwendig, damit evtl. in /lib/udev/rules.d/ vorhandene Regeln erst nach der eigenen Regel ausgeführt werden. Damit udev die angelegte Datei auch als eine gültige Regel erkennt, muss die Datei mit .rules enden.
Eine gültige Regel könnte z.B. 61-persistent-FHZ1300PC.rules lauten.
Im ersten Schritt schauen wir uns an, welche USB-Geräte angeschlossen sind. Dazu wird ein Terminal (Konsole) benötigt. In das (hoffentlich) geöffnete Terminalfenster wird nun der folgende Befehl abgesetzt:
lsusb
Die Ausgabe könnte z.B. so ähnlich aussehen:
Bus 005 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 002: ID 04fa:2490 Dallas Semiconductor DS1490F 2-in-1 Fob, 1-Wire adapter Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 002 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC Bus 002 Device 004: ID 0403:e0e8 Future Technology Devices International, Ltd Bus 002 Device 003: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Die obige Liste zeigt, das der Rechner mehrere Geräte (Device) an verschiedenen Bussen gefunden hat. Die einzelnen Geräte sind jeweils pro Bus aufsteigend nummeriert und haben neber einer ID auch eine Bezeichnung, die meist durch den Hersteller (oder den Kernel) vorgegeben wird.
Es wird vorausgesetzt das die FHZ 1300 PC bereits in einem USB-Steckplatz eingesteckt ist.
Schaut man sich nun die obige Liste an, so wird der versierte Benutzer die FHZ 1300 PC bereits an seiner ID erkannt haben, doch nicht jeder kennt diese auf Anhieb. Also müssen wir lsusb etwas gesprächiger machen. Und da bei dem folgenden Aufruf doch etwas mehr als nur eine Bildschirmseite dargestellt wird, übergeben wir die Ausgabe gleich an less um im Ergebnis in Ruhe mit den Cursor- bzw. Bild-Hoch- und Bild-Runter-Tasten lesen zu können (die Ausgabe kann übrigens mit der Taste q beendet werden!):
lsusb -v | less
Die Ausgabe sollte nun so ähnlich (hier gekürzt) aussehen:
Bus 005 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 3.00 bDeviceClass 9 Hub bDeviceSubClass 0 Unused bDeviceProtocol 3 bMaxPacketSize0 9 idVendor 0x1d6b Linux Foundation idProduct 0x0003 3.0 root hub bcdDevice 2.06 iManufacturer 3 Linux 2.6.38-13-generic-pae xhci_hcd iProduct 2 xHCI Host Controller iSerial 1 0000:0a:00.0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 25 ...
Nun gilt es das richtige Gerät zu finden: FHZ 1300 PC. Also wird die Ausgabe so weit durchblättert, bis man auf das gesuchte Device gestossen ist:
Bus 002 Device 004: ID 0403:e0e8 Future Technology Devices International, Ltd Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x0403 Future Technology Devices International, Ltd idProduct 0xe0e8 bcdDevice 2.00 iManufacturer 1 ELV AG iProduct 2 ELV FHZ 1300 PC iSerial 3 EL4IADOC bNumConfigurations 1 ...
Die Ausgabe der FHZ 1300 PC habe ich hier bewusst gekürzt. Es folgen noch weitere Informationen, die in an dieser Stelle nicht relevant sind.
Zwei Attribute sind jedoch wichtig: idVendor und idProduct. Für die FHZ 1300 PC sind das die Werte:
idVendor 0x0403
idProduct 0xe0e8
Auf Grundlage der gerade genannten Attribute wird nun die entsprechende udev-Regel definiert. Dazu wird in das entsprechende Verzeichnis gewechselt:
cd /etc/udev/rules.d/
Nun wird in diesem Verzeichnis mit einem bevorzugtem Editor (ich nutze Vim) die entsprechende Regeldatei nach dem anfangs erklärtem Schema angelegt (Achtung: Es werden root-Rechte benötigt! Also entweder dem folgenden Befehl ein sudo voranstellen oder vorher mittels su - nach root wechseln, sofern eingerichtet!):
vi 61-persisten-FHZ1300PC.rules
Wir geben udev nun die Regeln zur Erkennung der FHZ 1300 PC bekannt und teilen gleichzeitig mit, was udev damit machen soll (alles in einer Zeile!).:
KERNEL=="ttyUSB*", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="e0e8", SYMLINK+="fhz1300pc", MODE="0666"
Wer die Anleitung bis hier her aufmerksam verfolgt hat, dem sollte aufgefallen sein, das idVendor und idProduct in der obigen Zeile ohne die einleitenden 0x eingetragen wurden. Dies muss an dieser Stelle auch so sein und hat seine Richtigkeit.
Wir teilen also udev mit, dass sobald der Kernel ein Device ttyUSB* am Subsystem usb ein Gerät mit der Vendor-ID 0403 und der Product-ID e0e8 erkannt hat, ein symbolischer Link auf das Gerät unter /dev/fhz1300pc angelegt werden soll und sowohl der Besitzer, wie die Gruppe als auch alle anderen dieses Gerät zu Lesen und Schreiben 0666 öffnen kann.
Wie in dem Abschnitt FHZ 1300 PC Daten auslesen beschrieben, müssen die relevanten Attribute idVendor und idProduct für das CUL ausgelesen werden. Diese sollten wie folgt lauten:
idVendor 0x03eb
idProduct 0x204b
Nun wird wieder die entsprechende Regel-Datei (immer noch mit root-Rechten (siehe oben!)) angelegt
vi 61-persisten-CUL868.rules
und mit folgendem Inhalt versehen:
KERNEL=="ttyACM*", SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", SYMLINK+="cul868", MODE="0666"
Wer auch hier aufgepasst hat, der hat sicher bemerkt, das der Kernel im Gegensatz zu der FHZ 1300 PC mit ttyUSB* den CUL unter ttyACM* erkennen wird.
Um sicher zu gehen, das unsere Regeln ab sofort auch von udev verarbeitet werden, wird udev neu gestartet (nicht das ganze System! Wir kommen schliesslich nicht aus Redmond (Washington). ;-) )
Auch hierfür werden root-Rechte vorausgesetzt! Also entweder wieder ein sudo davor setzen oder vorher mit su - root werden. Unter meiner bevorzugten Distribution Ubuntu wird udev mittels den folgenden Befehlen neu gestartet:
/etc/init.d/udev reload
oder
service udev reload
Nach dem udev die Regeln neu eingelesen hat und hoffentlich keine Fehler aufgetreten sind (siehe tail -f /var/log/syslog bzw. tail -f /var/log/messages), prüfen wir diese.
Dazu ziehen wir die noch gesteckten Geräte CUL und FHZ 1300 PC ab und stecken diese wieder jeweils in eine freie USB-Buchse. Anschliessend schauen wir im Verzeichnis /dev/ nach den angelegten symbolischen Links:
ls -la /dev/ | grep -i -E "(fhz1300pc|cul868)"
Als Ergebnis sollte nun folgende (ähnliche) Ausgabe erscheinen:
lrwxrwxrwx 1 root root 7 2012-04-04 13:25 cul868 -> ttyUSB2 lrwxrwxrwx 1 root root 7 2012-04-04 13:25 fhz1300pc -> ttyUSB0
In meinem Fall ist also der CUL eigentlich unter ttyUSB2 und die FHZ 1300 PC unter ttyUSB0 ansprechbar. Und da wir ja hier von Hotplugging sprechen, könnte das bei dem nächsten An- / Abstecken schon wieder ganz anders aussehen.
Wichtig ist jedoch, das udev die Regeln erkannt und die entsprechenden symbolischen Links angelegt hat.
Nach dem nun sichergestellt ist, das beide Geräte immer unter dem jeweiligen Namen ansprechbar sind, übernehmen wir diese in die Konfiguration von FHEM.
Abweichend von den Angaben im FHEM Howto wird für den CUL nun nicht mehr
define CUL1 CUL /dev/ttyACM0@9600 1234
sondern
define CUL1 CUL /dev/cul868@9600 1234
eingetragen. Analog dazu wird für die FHZ 1300 PC nicht mehr
define FHZ1 FHZ /dev/ttyUSB0
sondern
define FHZ1 FHZ /dev/fhz1300pc
eingetragen.
Damit ist der kleine Exkurs von dynamischen und persistenten Devicenamen nun abgeschlossen und die Geräte sind auch nach dem nächsten Neustart ansprechbar.