modul für ein I2C Device auf unterschiedlicher Hardware (two level approach?)

Begonnen von klausw, 07 Januar 2014, 17:25:51

Vorheriges Thema - Nächstes Thema

klausw

Hallo zusammen,

ich schreibe gerade ein Modul um ein I2C IC (LED PWM Treiber) angeschlossen ans Pi in FHEM einzubinden. Das funktioniert auch soweit (ich dimme damit über einen Treiber die Halogenlampen in meiner Vitrine).
Jetzt habe ich noch eine weitere Hardware mit der ich ähnliches machen will: http://www.mobacon.de/wiki/doku.php/de/netzer/index Ein kleines Modul mit Mikrocontroller, das es ermöglicht über TCP/IP direkt auf den internen I2C Bus zuzugreifen.
Jetzt gibt es 2 Probleme, zum einen möchte ich kein zweites Modul schreiben und zum anderen kann es ja auch sein, das ich mehrere I2C ICs anschließen will, das Netzermodul aber nur eine Verbindung akzeptiert.
Wenn ich es richtig verstanden habe ist der two level approach dafür die beste Lösung.
Das ganze würde sich etwas weiter gedacht recht flexibel gestalten lassen, z.B. so:
xx_RPI_I2C, xx_BBB_I2C, xx_Netzer_I2C,... für die Ansteuerung
und:
xx_I2C_PCA9635, xx_I2C_BMP180, ... für die ICs
So ließen sich auch neue Hardwareplattformen schnell integrieren.

Ich habe mit schonmal das CUL modul angeschaut, bin aber nicht schlau draus geworden.
Woher weiss z.B. ein logical device, auf welches physical device es zugreifen muss wenn mehrere vorhanden sind.
Beispiel:
ich habe 2 dieser Netzermodule und das Paspberry mit je einem I2C IC bestückt und möchte diese natürlich auch separat ansprechen können.
Gibt es da einfache Beispielmodule?

Grüße
Klaus

RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

rudolfkoenig

ZitatWoher weiss z.B. ein logical device, auf welches physical device es zugreifen muss wenn mehrere vorhanden sind.

Siehe AssignIoPort(), $hash->{IODev}, IOWrite().

klausw

ah langsam steige ich durch

mit IOWrite() wird dann die WriteFn vom physical ausgeführt?

und umgekehrt?

Wenn ich vom physical was ans logical senden will, nehme ich vermutlich Dispatch()
Aber woher weiss das physical Device (oder eher fhem) an welches logical device die Message geehn soll?
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

justme1968

edit: da hat die hälfte gefehlt.

ja. das geht über dispatch. das globale dispatch findet über Clients und MatchList welche dispatchFn in welchem client device typ dann aufgerufen werden soll. dieses (dein) dispatch ist dann dafür zuständig rauszufinden welches logische device dann gemeint ist. die meisten module machen das dann rückwärts über ein $modules{<device type>}{defptr} über das sie den hash zu einer eindeutigen id finden.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Wobei man inzwischen auf Clients verzichten koennte: Dispatch hat mit Clients anfgefangen, aber fuer das automatische Laden von Modulen beim autocreate war mehr Info notwendig, deswegen wurde MatchList eingefuehrt. Leider habe ich es versaeumt dabei Clients abzuschaffen. Logische Module muessen ein Match Eintrag haben, um nur passende Module aufzurufen. Auf diesen koennte man wegen MatchList auch verzichten.

justme1968

ohne die Clients funktioniert aber umgekehrt das AssignIoPort nicht.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Klar, "koennte" bedeutet auch nur, dass man dazu fhem.pl anpassen muesste. Solange sind Client, MatchList & Match alle notwendig.

klausw

Zitat von: justme1968 am 08 Januar 2014, 18:33:52
edit: da hat die hälfte gefehlt.

ja. das geht über dispatch. das globale dispatch findet über Clients und MatchList welche dispatchFn in welchem client device typ dann aufgerufen werden soll. dieses (dein) dispatch ist dann dafür zuständig rauszufinden welches logische device dann gemeint ist. die meisten module machen das dann rückwärts über ein $modules{<device type>}{defptr} über das sie den hash zu einer eindeutigen id finden.

vielen Dank schonmal, ich muss trotzdem nochmal nachhaken ;)


  • Also ruft der gobale dipatch alle clients auf, die laut MatchList bzw. Clients infrage kommen?
  • Kann diese dispatchFn im client auch eine ParseFn sein (z.B. FS20_Parse im 10_FS20.pm Modul)?
  • Mit $modules{FS20}{defptr}{$code} bekommt das modul aber nur raus, ob es gemeint ist, wenn im globalen dispatch auch ein entsprechender $code mit drin ist?

Ich möchte das ganze gern mit I2C Befehlen machen (also die Botschaften zwischen physikalischem und logischem modul).
z.B. eine den Inhalt eines Registers von einem I2C IC lesen. Beim senden des requests ist die Adresse des IC's in der Botschaft (die auch dem $code entsprechen könnte) enthalten.
Das Problem aber ist, das in der Antwort nicht mehr die Adresse des I2C IC's drinsteckt. Das heisst wenn mehrere clients definiert sind dann klappt die Zuordnung nicht mehr.
Das heisst doch, ich müsste es irgendwie sequentiell machen?


RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

justme1968

1. es ruft alle clients der reihe nach auf bis der erste etwas zurück gibt

2. es muss natürlich parseFn heissen

3. das defptr wird nur innerhalb des moduls verwendet. du musst irgendetwas verwenden das im define bekannt ist und das in der
parseFn anhand der antwort abgeleitet werden kann.

wenn es keine eindeutige zuordnung zwischen antwort und device gibt du aber sicher stellen kannst das die antworten ohne ausnahme in der gleichen reihenfolge wie die kommandos kommen kannst du versuchen es darüber zu lösen. also die die reihenfolge in einem fifo merken und in parse auslesen.

wenn das nicht klappt fällt mir gerade nichts ein wie es mit mehreren clients pro physikalischem device gehen kann.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

klausw

Bin zwar noch nicht so weit, aber falls du diese Anpassung vornimmst. Wie bekomme ich diese Veränderung mit?
Zitat von: rudolfkoenig am 08 Januar 2014, 19:24:47
Klar, "koennte" bedeutet auch nur, dass man dazu fhem.pl anpassen muesste. Solange sind Client, MatchList & Match alle notwendig.
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

rudolfkoenig

1. Das ist ganz unten auf der TODO (wenn ueberhaupt)
2. Ich wuerde es hier posten
3. Es wuerde ja weiter funktionieren, nur Client und Match waere irrelevant.

klausw

ich habe mit einfach die CUL und FS20 Module hergenommen und auf der Basis begonnen.

und wieder ein paar Fragen bzw. Gedanken:

  • an die ParseFn wird der $hash vom physical übergeben und daher benötige ich defptr um die ensprechenden logical rauszubekommen?
  • ich würde auch  das I2C read in der WriteFn des physical machen
    also mit IOWrite übergeben, ob ich auf dem I2C lesen oder schreiben möchte und im fall von lesen ein DevIo_SimpleWrite mit einem DevIo_SimpleRead kombinieren. So habe ich immer die passende Antwort zum Befehl und kann in den Dispatch die passende Id für defptr reinpacken.
    Ist das so akzeptabel?
  • Einen Sendepuffer kann ich auch noch anlegen, aber ich sehe im Moment keinen Sinn darin, oder maximal darin, den letzten Befehl pro logical Device zu speichern
  • Die Read_Fn benötige ich eigentlich nicht, da über den I2C nichts ohne Anforderung empfangen wird.
    Kann ich das dann einfach weglassen, oder macht eine Umleitung ins Log Sinn, um Fehler besser zu erkennen?
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

rudolfkoenig

1. an ParseFn werden die (vom ReadFn) gelesenen Daten uebergegeben. ParseFn erzeugt mit den update*Readings Funktionen die Events/Readings, und liefert den Namen der betroffenen logischen Geraete zurueck.
2. das ist schlecht, weil solange FHEM blockiert wird. Sowas stoert viele enorm.
4. ReadFn wird vom gloabalen select aufgerufen, sie liest die Daten und ruft Dispatch() auf, falls ein Paket komplett ist. Dispatch filtert doppelte Nachrichten, sucht den passenden logischen Device (und laedt das Modul, falls es noch nicht geladen ist), ruft dessen ParseFn auf, und triggert die Events.


klausw

Zitat von: rudolfkoenig am 10 Januar 2014, 14:56:19
2. das ist schlecht, weil solange FHEM blockiert wird. Sowas stoert viele enorm.
Die Antwortzeit vom I2C liegt im ms Bereich. Kann das problematisch werden?
Für ungültige Befehle könnte ich ja einen timeout einbauen.

Die 2. Variante währe ein Sendepuffer.

  • IOWrite übergibt daten und info ob i2cread oder i2cwrite
  • WriteFn schreibt es in einen Sendepuffer
  • WriteFn startet das schreiben aus dem Sendepuffer wenn der Sendepuffer durch ReadFn freigegeben
  • Sendepuffer prüft ob die Botschaft ein read request ist
  • wenn nein senden und nächste Botschaft prüfen
    wenn ja senden, die I2C Adresse aus der Botschaft für die ReadFn lesbar speichern und keine weiteren Botschaften senden
  • ReadFn holt sich wenn was reinkommt diese I2C adresse  und schickt sie zusammen mit den empfangenen Daten über Dispatch raus
  • ReadFn gibt den Sendepuffer wieder frei
  • wenn keine Antwort kommt muss es einen Timeout geben
Es sollte eigentlich keine Nachricht kommen, für die nicht schon das Modul geladen ist. Der I2C arbeitet als Slave und sendet nix von sich aus.
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

klausw

mit dem sendepuffer funktioniert es ganz gut

jetzt habe ich eine weitere Hürde:
wenn ich z.B. ein I2C IC mit beispielsweise 16 GPIOs habe möchte ich ja für jeden GPiO einen eigenen define machen. Bisher nutze ich nur die I2C Adresse um in der ParseFn über defptr das passende Modul zu finden.
Wenn ich allerdings für alle 16 GPIOs ein define machen, dann würden sich alle angesprochen fühlen.
Das hätte den evtl. den Vorteil, das Einstellungen, die für mehrere GPIOs gelten auch an alle weitergegeben werden.

  • funktioniert das überhaupt, wenn mehrere definierte Module die gleiche defptr haben?
  • wie könnte ich für unterschiedliche defptr "Ids" erzeugen? Den namen aus dem define zu nehmen habe ich testweise probiert, erscheint mir aber nicht optimal
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

justme1968

1. der key muss eindeutig sein. wie du das erreichst hängt von deinem modul ab. wenn du dein device mit adressen hast ist die adresse gut. wenn du das device weiter unterteilst kannst du diese unterteilung einfach an den key dran hängen. also als key dann z.b. '<addr>.<pin>' verwenden.

je nach dem wie dein modul ausschaut geht das auch gemischt.

2. vielleicht ist es sinnvoll das modul in zwei teile zu trennen. eins was für alle 16 pins auf einem device zuständig ist und eins das als client dran hängt und dann jeweil für 1 oder mehrere pins zuständig ist. eventuell haben die pins ja auch unterschliedliche aufgaben. eins steuert vielleicht einen rolladen, dann sollte es up und down als kommandos geben, ein anderes vielleicht eine lampe, dann sollte es on und off geben.

für das client device kannst du dir auch mal readingsProxy anschauen. damit kannst du genau einen 'teil' (bei dir eben 1 oder mehrere pins) eines device als eigenständiges device ansprechen und flexibel mit eigenen kommandos und icons und webCmd versorgen.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

klausw

Zitat von: justme1968 am 15 Januar 2014, 22:55:36
2. vielleicht ist es sinnvoll das modul in zwei teile zu trennen.
dann würde es ein three level approach werden, I2C-Schnittstellenmodul->I2C-ICModul->Pinmodul
geht das überhaupt?
Zitat von: justme1968 am 15 Januar 2014, 22:55:36
für das client device kannst du dir auch mal readingsProxy anschauen. damit kannst du genau einen 'teil' (bei dir eben 1 oder mehrere pins) eines device als eigenständiges device ansprechen und flexibel mit eigenen kommandos und icons und webCmd versorgen.
Den nutze ich schon für ein anderes Modul. Klappt super. Aber das mit den GPIOs war nur ein Beispiel.
Es könnten stattdessen auch PWM Stufen sein (die nutze ich für meine Vitrinenbeleuchtung) oder RGB Treiber.
Da würde readingsProxy sicher an seine grenzen stoßen.

Grüße
Klaus

gruss
  andre
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

justme1968

ja. das geht auch mit drei stufen. wobei die zweite und dritte stufe aber anders zusammen arbeiten wie die ersten beiden. ich verwende das bei panstamp/swap/rgb modul. die schnittstelle zwischen swap und nachfolgendem modul ist aber selber gebaut.

so lange es set und get und eindeutige readings gibt sollte es mit dem readingsProxy funktionieren.

und selbst wenn nicht ist es vielleicht immer noch einfacher den readingsProxy für die einfachen dinge zu verwenden und wenn es nicht mehr geht ein eigenes modul zu schreiben oder auch den readingsProxy zu erweitern.

erst wenn so viel logik nötig ist das du mehr code schreibst als du durch den readingsProxy einsparst ist ein eigenes modul besser.

aber pwm stufen sollte eigentlich noch gehen und rgb geht auf jeden fall. sogar mit farbigen lampen icons und colorpicker. spiff verwendet das um mit einem readingsProxy und ECMD einen dmx controller für farbige lampen zu steuern.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

klausw

Dein readingsProxy Modul verwende ich ja schon erfolgreich für einfache Schalter.
define netzer1b readingsProxy netzer01:Port_b
attr netzer1b room Netzer
attr netzer1b setFn {($CMD eq "off")?"b 0":"b 1"}
attr netzer1b setList on off
attr netzer1b valueFn {($VALUE == 0)?"off":"on"}

Es Anstelle mehrerer einzelner Module zu verwenden ist verlockend. Aber am PWM/Dimmer bin ich bisher gescheitert.
sobald ich eine setlist mit state:slider,0,1,100 anlege kommt folgende Fehlermeldung:
Unknown argument 40, choose one of on off state:slider,0,1,100 off-for-timer off-till on-till on-for-timer intervals blink

Hast du einen fhem.cfg Auszug zu einem Dimmer für readingsProxy?

Ein weiteres Problem könnte sein, das ich für off -> 0 und für on/bzw 100 den Wert FF zurückliefern muss.
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280

justme1968

das problem ist das es für state noch keine sonderbehandlung gab.

wenn ein slider für <cmd> mit '<cmd>:slider,min,step,max' definiert wird ruft fhemweb nach dem eingestellen normalerweise 'set <device> <cmd> <value>' auf. wenn <cmd> abder state ist lässt fhem das state weg und ruf nur 'set <device> <value> auf.

das habe ich eben im readingsProxy repariert und es ist ab morgen im update.

du kannst es heute schon mit einem anderen reading/wert anstelle von state testen. also pct/bri oder was auch immer.

das mit 0 für off und FF für on und 100 ist kein problem.genau dafür ist ja die setFn da.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

klausw

Hi Andre,

danke, state funktionert jetzt.

Ich wusste gar nicht, das es auch noch andere slider gibt.

Grüße
Klaus
RasPi B v2 mit FHEM 18B20 über 1Wire, LED PWM Treiber über I2C, Luchtdruck-, Feuchtesensor und ein paar Schalter/LED\'s zum testen
Module: RPI_GPIO, RPII2C, I2C_EEPROM, I2C_MCP23008, I2C_MCP23017, I2C_MCP342x, I2C_PCA9532, I2C_PCF8574, I2C_SHT21, I2C_BME280