DevIo: FHEM-Modul als IO-Device

Begonnen von jensb, 27 Dezember 2015, 19:24:21

Vorheriges Thema - Nächstes Thema

jensb

Hallo Rudi,

DevIo wird bereits von mehr als 30 Modulen für den Zugriff auf IO-Devices (über DevIo_OpenDev) genutzt. Bei einem solchen IO-Device handelt es sich meist um eine serielle Schnittstelle bzw. USB-Schnittstelle oder eine Netzwerkverbindung. Während Netzwerkverbindung per se flexibel sind, sind die anderen Schnittstellen bisher an die lokale Hardware gebunden. Will man nun weg von der lokalen Hardware, könnte man entsprechende Sonderlösungen in das jeweilige Modul einbauen.

Wünschenswert ist jedoch ein Schnittstellenabstraktion außerhalb der Anwendungsmodule, und die existiert mit DevIo ja schon. Es fehlt "nur" die Möglichkeit, statt eines der bisher unterstützten betriebssystemnahen IO-Device-Typen ein FHEM-Modul als IO-Device anzugeben. Durch eine Erweiterung der Syntax von DevIo für den Devicenamen (z.B. mit Präfix "FHEM:...", analog "UNIX:...") könnte man diese neue Form eines IO-Devices auswählen. Hinter dem Präfix folgen dann weitere Parameter, u.a. der Modulname, der als IO-Device angesprochen werden soll. Ein solches IO-Device-Modul müsste die für ein IO-Device erforderlichen Funktionen exportieren, z.B. als  IOOpenFn, IOWriteFn und IOCloseFn, während es selbst die ReadFn des Anwendungsmoduls bedient. Wenn das IO-Device-Modul neue Daten aufliefert, werden sie im Hash des Anwendungsmoduls geparkt (z.B. als {IODevRxBuffer}), bis das Anwendungsmodul eine Variante von DevIo_SimpleRead aufruft. Damit bleiben die Programmierschnittstellen von DevIo und den Anwendungsmodulen unverändert. Eine konsequente Nutzung dieses Ansatzes bietet die Möglichkeit, dass Telegrammdekoder und die nachfolgenden Verarbeitungsketten nur einmal programmiert werden müssten, während der Weg zur Datenquelle bei Bedarf geändert werden kann. Dies könnte vor allem bei neuen Modulen berücksichtigt werden.

Damit das Ganze nicht so abstrakt klingt, hier ein Anwendungsbeispiel: Das Anwendungsmodul HEATRONIC nutzt eine serielle Schnittstelle als Datenquelle über DevIo. Ab Version 2.5 hat Firmata Support für serielle Schnittstellen und bietet damit die Möglichkeit eines COM-Servers. Um nun die HEATRONIC über die serielle Schnittstelle am Ardunino nutzen zu können, ist es nicht sinnvoll, dazu das Modul HEATRONIC auf Firmata anzupassen, sondern es sollte reichen, dort für DEF z.B. "FHEM:DEVIO:<FRM device name>:<serial port>@<baud rate>" anzugeben. Auch jedes andere Anwendungsmodul, das DevIo_OpenDev benutzt, könnte sich so Zugang zu einer seriellen Schnittstelle über Firmata verschaffen, ohne geändert werden zu müssen.

Den einzigen Verhaltensunterschied zwischen betriebssystemnahen IO-Devices und IO-Device-Modulen scheint nach meinen Experimenten beim Neustart von FHEM aufzutreten, da die betriebssystemnahen IO-Devices mit der Initialisierung des Anwendungsmodul z.T. sofort zur Verfügung stehen (z.B. bei seriellen Schnittstellen), während ein IO-Device-Modul u.U. etwas Zeit zur Initialisierung benötigt, z.B. um eine Netzwerkverbindung herzustellen.

Was hältst du von diesem Vorschlag?

Grüße,
Jens
FHEM 6.1 - RPi 4 Raspbian 12 + PiTFT - OPi Zero Armbian 5.35
EnOcean - (W)LAN/Firmata: BMP180, TSL2561, SHT21, Heatronic 3, OBIS - WLAN/ESP8266: Gardena 1251, Zirkulationspumpe - RTL433: Oregon - Bluetooth - MQTT
Contributions: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/jensb

rudolfkoenig

Ich verstehe noch nicht den Unterschied zu den vorhandenen physikalischen/logischen Modulen (ala CUL/FS20).

jensb

Hallo Rudi,

vielleicht hilft uns dieses Beispiel weiter:

Jetzt: 
USB-CUL -> lokale USB-Schnittstelle -> CUL-Modul (in DevIo, out Dispatch) -> FS20-Modul (in Dispatch)
mit "define myCUL CUL /dev/ttyACM0"

Neue Option:
USB-CUL -> USB-TTL-Wandler -> Arduino mit Firmata -> FRM-Modul (in DevIo, out DevIo-Neu) -> CUL-Modul (in DevIo, out Dispatch) -> FS20-Modul (in Dispatch)
mit "define myCUL CUL FHEM:DEVIO:myFirmata:1@9600"

Im Kern geht mein Vorschlag davon aus, dass man sich als IO-Device-Modul (hier das noch zu modifizierende FRM-Modul) mit dem modifizierten DevIo gegenüber anderen Modulen als Ersatz für ein physikalischen Device (wie hier z.B. /dev/ttyACM0) ausgeben kann. Es geht also darum, ggf. die Verbindung zwischen dem CUL-Modul und dem physikalischen CUL-Device ändern zu können, indem man über ein IO-Device-Modul den physikalischen Layer für den Datentransport ändert (hier Firmata statt lokales USB).

Funktionell bleibt dieses Beispiel erst einmal noch Theorie, da ich nicht weiß, wie zeitkritisch beim CUL die Kommunikation abläuft.

Alternativ könnte man statt der vorgeschlagenen DevIo-Erweiterung auch einen Socket über localhost aufbauen (hier müsste das FRM-Modul einen TCP Server implementieren), denn DevIo kann ja bereits einen TCP Client nutzten. Wahrscheinlich wäre der IO-Delay zwischen den Modulen dadurch geringfügig höher als beim Direktaufruf mit CallFn.

Grüße,
Jens
FHEM 6.1 - RPi 4 Raspbian 12 + PiTFT - OPi Zero Armbian 5.35
EnOcean - (W)LAN/Firmata: BMP180, TSL2561, SHT21, Heatronic 3, OBIS - WLAN/ESP8266: Gardena 1251, Zirkulationspumpe - RTL433: Oregon - Bluetooth - MQTT
Contributions: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/jensb

rudolfkoenig

Trotz deines Beispiels verstehe ich immer noch nicht so recht den Einsatzzweck, aber was solls, FHEM ist auch zum spielen da (bitte nicht weitersagen).

Ich sehe noch ungeloeste Probleme bei deinem Vorschlag:
- wer & wann ruft das ReadFn des oberen Moduls auf? Bisher wird das durch das globale select erledigt.
- wie loest man das "CUL_ReadAnswer" Problem (da wird ganz haesslich blockierend vom FD gelesen).
- nicht alle Module verwenden DevIo_SimpleWrite, z.Bsp. 00_CUL.pm und 00_ZWCUL.pm

Ich wuerde diese Probleme durch einen altmodischen pipe() loesen.

jensb

Zitat... wer & wann ruft das ReadFn des oberen Moduls auf?
Das globale select würde im letzten Beispiel zunächst die ReadFn des FRM-Modul auslösen, wenn der Arduino Daten von seiner seriellen Schnittstelle schickt. Der Firmata-Protokollhandler würde das Firmata-Telegramm einlesen und das FRM-Modul würde die ReadFn des CUL-Moduls direkt aufrufen und die seriellen Daten aus dem Firmata-Telegramm weitergeben. Der Anfang ist also unverändert, nur die Verarbeitungskette ist wegen der Protokollumsetzung etwas länger.

ZitatIch wuerde diese Probleme durch einen altmodischen pipe() loesen.
War auch einer meiner ersten Überlegungen. Aber Pipe und Socket haben einen entscheidenden Nachteil: Die Schnittstellenparameter (z.B. serielle Portnummer, Baudrate, etc.) müssten bei jedem Verbindungsaufbau als erstes übertragen werden, damit die verlagerte physikalische Schnittstelle richtig konfiguriert werden kann. Das ist nicht unmöglich, nur aufwendiger. Damit es das CUL-Modul nicht merkt, müsste man hierfür im DevIo_OpenDev direkt nach dem Öffnen eine entsprechendes Setup-Telegramm in die Pipe bzw. den Socket schicken. Außerdem sollte man auch IO-Device-Module berücksichtigen, die mehrere IO-Devices anbieten können. Ein Teensy LC hat z.B. 4 serielle Schnittstellen, von denen 3 über Firmata genutzt werden können. Will man das ggf. ausnutzen, bräuchte man 3 Pipes bzw. Sockets zu einem FRM-Modul. Wenn man CallFn verwendet, übergibt man die Schnittstellenparameter einfach als Aufrufparameter oder im Hash.

Die beiden anderen Aspekte mit CUL_ReadAnswer bzw. ohne DevIo_SimpleWrite werde ich mir noch ansehen.
FHEM 6.1 - RPi 4 Raspbian 12 + PiTFT - OPi Zero Armbian 5.35
EnOcean - (W)LAN/Firmata: BMP180, TSL2561, SHT21, Heatronic 3, OBIS - WLAN/ESP8266: Gardena 1251, Zirkulationspumpe - RTL433: Oregon - Bluetooth - MQTT
Contributions: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/jensb

betateilchen

muss ja eine coole Party gewesen sein...  8)

Wer braucht sowas wirklich? Welche real existierenden, funktionseinschränkenden Probleme kann man durch die vorgeschlagene Änderung lösen?

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

jensb

Hallo betateilchen,

ja, hat Spaß gemacht, vor allem weil es am Ende funktioniert hat ;)

Wofür mans aus meiner Sicht z.B. gebrauchen kann, steht im 1. Post: Firmata als COM-Server für vorhandene FHEM-Module, ohne diese ändern zu müssen. Kommerzielle COM-Server sind nicht nur relativ teuer, sie haben meist auch kein TTL-Interface, was für uns Bastler hin und wieder die bessere Andockstelle ist.

Die Tendenz, insbesondere klassische serielle Schnittstellen loszuwerden, hat mit USB ja schon vor längerer Zeit begonnen - aber auch USB hängt an einem kurzem Kabel. Erst mit LAN oder einem der Funkstandards hat man die erforderliche Flexibilität. Solange nicht alles darauf umgestellt ist, braucht man Brückenlösungen und COM-Server sind für vorhandene serielle Schnittstellen die 1. Wahl.

Grüße,
Jens
FHEM 6.1 - RPi 4 Raspbian 12 + PiTFT - OPi Zero Armbian 5.35
EnOcean - (W)LAN/Firmata: BMP180, TSL2561, SHT21, Heatronic 3, OBIS - WLAN/ESP8266: Gardena 1251, Zirkulationspumpe - RTL433: Oregon - Bluetooth - MQTT
Contributions: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/jensb

rudolfkoenig

Fuer diesen Zweck wuerde ich nicht mein eigenes Protokoll bauen, sondern auf TCP/IP setzen, z.Bsp auf einem RPi mit socat/ser2net. Wem das zu doof ist kann bestimmt tcp/ip auf dem Arduino zum laufen bringen.

Markus Bloch

Für solche Spezialbauten mit Arduino, etc. gibt es extra die Module ECMD und ECMDDevice. Die sind sehr flexibel und für solche Sachen gedacht, wo man z.B. am Arduino mehrere Sachen an den schaltbaren Aus- und Eingängen hat. Die kann man damit logisch voneinander trennen.

Ansonsten haue das Ding an einen Raspberry oder ähnliches und mach ser2net drauf, wie von Rudi vorgeschlagen. Funktioniert bei mir mit dem panStamp-Shield auf dem Raspberry super. FHEM greift dann direkt auf den Socket zu und wird die seriellen Kommandos los. Geht astrein.

Aus meiner Sicht ist dein Szenario zu speziell, als das ich so etwas in FHEM einbauen würde.

Grüße

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

jensb

Hallo Rudi, hallo Markus,

danke für eure Rückmeldungen.

Vielleicht noch mal kurz zu meiner Motivation: Momentan habe ich das alles am RPi und es funktioniert in Bezug auf die serielle Schnittstelle prima. Aber mein RPi steht im Keller und mein USB-CUL kann von da aus nicht alles erreichen. Da ich keinen CUL-Repeater verwenden möchte, muss der RPi mit CUL umziehen - aber die seriellen Kabel kann er dabei nicht mitnehmen. FHEM kann Firmata und Firmata hat IO, I2C und serielle Schnittstellen im Protokoll. Lediglich die Implementierung der Firmata-Telegramme für serielles IO fehlt noch im FRM-Modul. Daher war das für mich die naheliegende Lösung, vor allem weil ich gleichzeitig noch I2C und digitales IO machen möchte. Wenn ich dafür einen Arduino selbst programmiere, müsste ich Firmata noch mal erfinden und das macht keinen Sinn. Nehme ich 2 Arduinos, einen mit Firmata und einen für die serielle Schnittstelle, brauche ich einen Switch und das ist auch nicht elegant. Und einen ganzen RPi (z.B. mit FHEM2FHEM) für eine serielle Schnittstelle, einmal I2C und 3 digitale Ausgänge abzustellen, halte ich für oversized.

Ein eigenes Protokoll oder spezielle Firmware für den Arduino sind also nicht nötig, lediglich eine Datenbrücke über DevIo.

Ich glaube nicht, dass man z.B. das HEATRONIC-Modul per Konfiguration überreden kann, ECMD als Gateway zu akzeptieren, denn das HEATRONIC-Modul ist kein ECMDDevice mit IODev-Support, sondern verwendet DevIo zum Zugriff auf die serielle Schnittstelle. Genau an dieser Stelle setzt mein Vorschlag an. Er macht die Daten aus dem einen Modul in einem vorhandenen Modul als Device-Ersatz verfügbar.

Grüße,
Jens
FHEM 6.1 - RPi 4 Raspbian 12 + PiTFT - OPi Zero Armbian 5.35
EnOcean - (W)LAN/Firmata: BMP180, TSL2561, SHT21, Heatronic 3, OBIS - WLAN/ESP8266: Gardena 1251, Zirkulationspumpe - RTL433: Oregon - Bluetooth - MQTT
Contributions: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/jensb

ntruchsess

ich halte Die Idee grundsätzlich mal schon für Sinnvoll - das ist architekturell ja ähnlich wie die I2C-geschichte, bei der der Hardwarezugriff ja auch über das IODev wegabstrahiert ist.

Allerdings halte ich nix davon in der Definition des Clients irgendwelche Details zur Konfiguration des IODevs mitzugeben:
Zitat von: jensb am 27 Dezember 2015, 21:41:28
"define myCUL CUL FHEM:DEVIO:myFirmata:1@9600"

Also in dem Beispiel sollte das '1@9600' entfallen, das gehört doch in die Konfiguration des IODevs selber.

Gruß,

Norbert
while (!asleep()) {sheep++};

jensb

Hallo Norbert,

damit könnte ich auch gut mit leben. Dann brauchen wir aber in FRM für jeden seriellen Port eine entsprechenden Konfigurationsmöglichkeit.

Grüße,
Jens
FHEM 6.1 - RPi 4 Raspbian 12 + PiTFT - OPi Zero Armbian 5.35
EnOcean - (W)LAN/Firmata: BMP180, TSL2561, SHT21, Heatronic 3, OBIS - WLAN/ESP8266: Gardena 1251, Zirkulationspumpe - RTL433: Oregon - Bluetooth - MQTT
Contributions: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/jensb

ntruchsess

ja genau, da machen wir ein FRM_SER modul in dem dann Pin und Baudrate konfiguriert werden. Das wird dann im Client z.B. per IODev-Attribut referenziert. Es macht ja keinen Sinn, wenn man die IODev-funktionalität auf virtuelle Devices ausdehnt und damit die Hardware wegabstrahiert, dann trotzdem etwas hardwarespezifisches im Define des Clients stehen zu haben.
while (!asleep()) {sheep++};

jensb

Hallo Norbert,

ein FRM_SER-Modul für Pin-Zuordnung und Baudkonfiguration ist eine gute Idee.

Wenn man das aber im Client als IODev-Attribut verwenden will, muss man, anders als bei meinem Vorschlag, die bestehenden potentiellen Clients ändern. Mein Referenzbeispiel 98_HEATRONIC.pm kennt nur OS-Devices, auf die mit DevIo zugegriffen wird. Ähnlich ist das auch bei den anderen Modulen, die zwar DevIo nutzen, aber nicht das IODev-Konzept. Ein entsprechender Umbau der Client-Module auf parallelen Support für IODev kann bei einigen Modulen durchaus aufwendig sein.

Grüße,
Jens
FHEM 6.1 - RPi 4 Raspbian 12 + PiTFT - OPi Zero Armbian 5.35
EnOcean - (W)LAN/Firmata: BMP180, TSL2561, SHT21, Heatronic 3, OBIS - WLAN/ESP8266: Gardena 1251, Zirkulationspumpe - RTL433: Oregon - Bluetooth - MQTT
Contributions: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/jensb

betateilchen

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!