Modul für die Ansteuerung des MCP23017 I2C Portextender

Begonnen von klausw, 03 Mai 2014, 01:02:40

Vorheriges Thema - Nächstes Thema

klausw

Hallo Holger,
das System ist nicht das Problem.
Aber I2C unterstützt keinen Interrupt. Daher lässt sich ein longpress nicht einbauen.
Du könntest aber eine GPIO vom Raspberry als Interrupt Eingang nutzen und da über einen notify einen Timer ablaufen lassen, der nach 2s ein Reading longpress setz,t bzw. löscht wenn der Pin wieder auf low geht.

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

hollyghost

Hallo Klaus,
I2C per se ist natürlich nicht Interrupt fähig, der Chip schon & diesen nutze ich auch - wer will schon Pollen :)
Du siehst also kein Problem, wenn im worst case 16 Timer angestoßen werden?
Gruß Holger

klausw

Zitat von: hollyghost am 02 September 2014, 08:33:23
Hallo Klaus,
I2C per se ist natürlich nicht Interrupt fähig, der Chip schon & diesen nutze ich auch - wer will schon Pollen :)
Du siehst also kein Problem, wenn im worst case 16 Timer angestoßen werden?
Gruß Holger
Oh je, willst du Klavier spielen ::)
Sollte funktionieren... Einfach mal probieren. Wenn Du den Interrupt schon nutzt ist es ja kein Riesenaufwand.
Kannst das Ergebnis gern hier posten.
Der Eine oder andere freut sich bestimmt
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

hollyghost

Hallo Klaus,
ich bin dir ja noch ne Antwort schuldig  ;)
Nein, Klavierspielen will ich nicht (wer will das schon auf nur 16 Tasten  ;D )
Ich möchte darüber Rollläden steuern. Deshalb benötige ich den kurzen und langen Tastendruck.
Kurzer Tastendruck - Rollladen fährt bis zur jeweiligen Endposition (wenn er nicht zwischendurch durch einen weiteren Tastendruck angehalten bzw. in die entgegengesetzte Richtung geschickt wird)
Langer Tastendruck - Rollladen fährt in Richtung der jeweiligen Endposition, solange bis die Taste losgelassen wird.
Umgesetzt habe ich das jetzt analog deinem Vorschlag, mit nem dummy, der 2Sekunden nach einem Tastendruck durch ein 'at' gesetzt wird (longPressTimer). Sollte die Taste innerhalb dieser zwei Sekunden losgelassen werden, wird der Timer einfach gelöscht.
Bei der Konfiguration hab ich mich stark an die Einstellungen von Christian (linusd) aus Post #40 in diesem Thread gehalten. Eine Ergänzung musste ich bei den ReadingProxies machen: das Attribut 'event-on-change-reading' musste ich für 'state' aktivieren – da die Eingangspins des MCP23017 ja bei jedem beschreiben der Ausgangspins erneut eingelesen werden. Mein Notify sollte aber nur getriggert werden, wenn sie der Zustand der Pins verändert hat.
Den zweiten Timer (reTriggerTimer) verwende ich für folgendes Szenario: Wenn während einer laufenden Fahrt eine Taste gedrückt wird, wird der Rollladen zunächst gestoppt. Wird die Taste nun gedrückt gehalten, setzt sich der Rollladen in Richtung der jeweiligen Endposition in Bewegung. Klassischer Fall, Umkehrung der Laufrichtung, wenn die Automatik den Rollladen auffährt, der Nutzer aber gerne noch im dunkeln bleiben möchte  ;)
Vielleicht kann ja jemand was damit anfangen:


###I2C-Device###
define i2cBus RPII2C 1
attr i2cBus group MCP23017

###MCP23017-0x20###
define MCP23017_20 I2C_MCP23017 0x20
attr MCP23017_20 IODev i2cBus
attr MCP23017_20 Interrupt A3,A4
attr MCP23017_20 InterruptOut connected_active-low
attr MCP23017_20 group MCP23017
attr MCP23017_20 invert_input A3,A4

###Interrupt A&B####
define Interrupt RPI_GPIO 4
attr Interrupt active_low yes
attr Interrupt direction input
attr Interrupt group MCP23017
attr Interrupt interrupt both
attr Interrupt userReadings test {fhem ("get MCP23017_20")}

###Sensoren (Input)####

#--Bank-A--#
define tastGwcUp readingsProxy MCP23017_20:PortA3
attr tastGwcUp group InputPorts
#Events nur senden, wenn sich der Status geändert hat
attr tastGwcUp event-on-change-reading state
attr tastGwcUp valueFn {($VALUE eq "on")?"Up":"Off"}

define tastGwcDown readingsProxy MCP23017_20:PortA4
attr tastGwcDown event-on-change-reading state
attr tastGwcDown group InputPorts
attr tastGwcDown valueFn {($VALUE eq "on")?"Down":"Off"}

#--Longpress Dummy--
define gwc_Longpress dummy
attr gwc_Longpress room Rollo

#--Notify Test--
define gwc_UpOn notify tastGwcUp:Up {\
fhem "set gwc_Longpress no";;\
if(ReadingsVal("gwc_rollladen","locked",1)){\
fhem ("set gwc_rollladen stop;;define gwc_reTriggerTimer at +00:00:02 trigger tastGwcUp Up");;\
}else{\
fhem ("set gwc_rollladen 1;;define gwc_longPressTimer at +00:00:02 set gwc_Longpress yes");;\
}\
}

define gwc_UpOff notify tastGwcUp:Off {\
if(defined $defs{gwc_reTriggerTimer}) {fhem "delete gwc_reTriggerTimer"};;\
if(defined $defs{gwc_longPressTimer}) {fhem "delete gwc_longPressTimer"};;\
if (Value("gwc_Longpress") eq "yes") {fhem "set gwc_rollladen stop"};;\
Log 3, "gwc Longpress-Status: ".Value("gwc_Longpress");;\
}
define gwc_DownOn notify tastGwcDown:Down {\
fhem "set gwc_Longpress no";;\
if(ReadingsVal("gwc_rollladen","locked",1)){\
fhem ("set gwc_rollladen stop;;define gwc_reTriggerTimer at +00:00:02 trigger tastGwcDown Down");;\
}else{\
fhem ("set gwc_rollladen 100;;define gwc_longPressTimer at +00:00:02 set gwc_Longpress yes");;\
}\
}

define gwc_DownOff notify tastGwcDown:Off {\
if(defined $defs{gwc_reTriggerTimer}) {fhem "delete gwc_reTriggerTimer"};;\
if(defined $defs{gwc_longPressTimer}) {fhem "delete gwc_longPressTimer"};;\
if (Value("gwc_Longpress") eq "yes") {fhem "set gwc_rollladen stop"};;\
Log 3, "gwc Longpress-Status: ".Value("gwc_Longpress");;\
}

Grüße
Holger

PiUser

Hallo,

Ich bin gerade auch dabei in Projekt mit fhem und zwei MCP23017 zu realisieren. Einer dieser Bausteine ist als Eingang für Taster vorgesehen, der andere als Ausgang für Relais.
Dank klausw ist ja eine Anbindung an den MCP möglich.

Ich habe die Programmierung ähnlich des Post40 vorgenommen, d.h. mit ReadingProxys gearbeitet.
Soweit funktioniert auch alles, ABER:
Während des "bootens" von FHEM schalten alle Relais - durch ein "shutdown restart" zu 100% reproduzierbar.
Dies ist im Moment ein absoluter Showstopper.

Kann mir jemand sagen was ich falsch mache? Oder ist das so gewollt?

Und noch eine Frage habe an klausw:
Wenn ich mehrere Ausgänge gleichzeitig schalten möchte, hattest Du ja extra eine Funktion vorgesehen, der man verschiedene Ports gleichzeitig übergeben kann.
leider werden diese sequentiell geschaltet.
Im Prinzip müsste das aber auch richtig gleichzeitig gehen. Könntest Du die Funktion entsprechend ändern? Das wäre echt toll.


Vielen Dank schon mal für die Rückmeldungen!
PiUser

klausw

Zitat von: PiUser am 11 Oktober 2014, 16:23:03
Ich habe die Programmierung ähnlich des Post40 vorgenommen, d.h. mit ReadingProxys gearbeitet.
Soweit funktioniert auch alles, ABER:
Während des "bootens" von FHEM schalten alle Relais - durch ein "shutdown restart" zu 100% reproduzierbar.
Dies ist im Moment ein absoluter Showstopper.

Kann mir jemand sagen was ich falsch mache? Oder ist das so gewollt?
Gewollt ist das nicht. Vielleicht ist es bisher keinem aufgefallen.
OnStartup ist auf last gestellt?

Bei Neu- und Restart setze ich alle Register im MCP in dieser Reihenfolge neu:

  • GPIOA/B
  • IPOLA/B (invert_input)
  • IODIRA/B (OutputPorts)
  • GPPUA/B (Pullup)
  • GPINTENA/B (Interrupt)
  • IOCON (InterruptOut)

Es ist möglich, das diese Reihenfolge verändert werden muss.
Dazu müsste die ganze Prozedur händisch (z.B. von Dir ;)) über i2cwrite getestet werden.
Ich habe keinen MCP23017 und kann es daher nicht testen.

Zitat von: PiUser am 11 Oktober 2014, 16:23:03
Und noch eine Frage habe an klausw:
Wenn ich mehrere Ausgänge gleichzeitig schalten möchte, hattest Du ja extra eine Funktion vorgesehen, der man verschiedene Ports gleichzeitig übergeben kann.
leider werden diese sequentiell geschaltet.
Im Prinzip müsste das aber auch richtig gleichzeitig gehen. Könntest Du die Funktion entsprechend ändern? Das wäre echt toll.
Nur, das wir nicht aneinader vorbei reden.
Der MCP hat 2 Ports zu je 8 Bit.
Ein Port wird am Stück gesetzt.
Port A und B werden in der Tat sequentiell gesetzt, was daran liegt, das es 2 verschiedene Register sind.
set mod1 PortA2,PortA4,PortB6 off beispielsweise setzt A2 und A4 gleichzeitig und direkt danach B6
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

PiUser

Hallo,

ich konnte jetzt noch mal intensive Tests durchführen.
Die Ergebnisse sind kurz zusammengefasst:

Es funktioniert alles so, wie von klausw beschrieben. Auf der Seite ist also kein Problem feststellbar.
Bei den gleichzeitigen Ports hatte ich tatsächlich übersehen, dass es ich A und B Ports verwende, daher das serielle Schalten.

Ich konnte mein Problem jetzt auf folgendes einkreisen - aber kurz noch mal zu meinem Aufbau:
Ich nutze:
1. Mehrere Dummy-Schalter, die auf der FHEM -Oberfläche als Schalter zu sehen und anklickbar sind.
2. Mehrere readingProxy auf einen MCP23017 (als Eingang initialisiert), die per Notifier einen 'Off' Zustand eines echten Schalters melden und daraufhin die Schalter von 1. schalten. Dadurch wird erreicht, dass beim Loslassen des Hardware-Schalters das gleiche ausgeführt wird, als wenn ich im web klicke. Ich nehme extra den Off-state, damit ich noch messen kann, wielange ein Schalter gedrückt wurde.
3. Mehrere readingProxys auf einem anderen MCP, der als Output definiert ist.

Im laufenden Betrieb funktioniert auch alles wie gewünscht: Egal ob per Web-Oberfläche oder über den echten Schalter (via MCP23017) werden die richtigen Funktionen ausgeführt (d.h. die richtigen Outputs geschaltet).

Die Krux ist jetzt beim Booten:
Der Notifier der ReadingProxy unter 2. melden während der Initialisierung den off-State, schalten daraufhin den dummy-Schalter unter 1., welcher dann (richtigerweise) die Outputs aktiviert.

Die Frage ist nun:
Wie kann ich verhindern, dass der Notifier unter 2. während des Bootens den off-state meldet?

Vielen Dank und viele Grüße
PiUser

klausw

Zitat von: PiUser am 17 Oktober 2014, 17:24:18
Die Krux ist jetzt beim Booten:
Der Notifier der ReadingProxy unter 2. melden während der Initialisierung den off-State, schalten daraufhin den dummy-Schalter unter 1., welcher dann (richtigerweise) die Outputs aktiviert.

Die Frage ist nun:
Wie kann ich verhindern, dass der Notifier unter 2. während des Bootens den off-state meldet?
Die ReadingProxy unter 2. melden den Off state, obwohl der Portpin vom MCP high ist?

Was du versuchen kannst, ist zu schauen, ob Du im notify von 2 nicht schauen kannst, ob der ReadingProxy vorher on war, und nur dann den Dummy schaltest.
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

PiUser

Hallo,

ich glaube ich konnte das Problem mit Hilfe des Codes von hollyghost lösen:

Ich habe das Attribut "event-on-change-reading state" dem readingProxy hinzugefügt. Jetzt scheint es so zu laufen.

Vielen Dank zunächst einmal
PiUser

IPPhoner2b

Hallo zusammen,

ich habe jetzt eine ganze Zeit lang das Projekt auf Eis gelegt, weil es zum Glück noch nicht ganz dringend ist.
Jetzt wollte ich so langsam wieder damit anfangen, und das Script von "hollyghost" sieht auch schon sehr interessant aus.

Da habe ich eine Frage, wenn ich einen Schalter für die Rolläden benutze, und diesen Schalter dauerhaft auf "hochfahren" stehen lasse, wie müsste dann der Code geschrieben werden, dass, wenn dieser Eingang gesetzt ist, dass in dem Fall das Rollo auch nicht geschaltet wird?

Also dieser Fall wäre eben für die Terassentür, dass im Sommer halt eben, wenn man länger draußen sitzt, der Schalter einfach in Hochfahrstellung eingerastet wird, und dadurch das absenken des Rollos verhindert wird.

Über eine Hilfe wäre ich sehr dankbar. muss mir im Urlaub mal endlich die Zeit nehmen, mich damit wieder zu beschäftigen, aber vielen Dank an alle und vor allem an KlausW mit seiner super Arbeit hier  :D :D

Gruß
Christian

klausw

Zitat von: IPPhoner2b am 02 November 2014, 14:19:16
Also dieser Fall wäre eben für die Terassentür, dass im Sommer halt eben, wenn man länger draußen sitzt, der Schalter einfach in Hochfahrstellung eingerastet wird, und dadurch das absenken des Rollos verhindert wird.

Vermutlich möchtest Du durch den Schalter in Hochfahrstellung, ein schließen der Rolläden per Zeitschaltuhr verhindern. Richtig?
Ich diesem Fall kannst du im notify der Zeiteinstellung die Schalterstellung abfragen.
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

IPPhoner2b

Hallo Klaus,

Genau das habe ich gemeint *g*

Jetzt muss ich nur noch verstehen, wie ich das ganze programmieren muss ...

Aber ich denke, es gibt schon hier und da genug Nutzer, die so etwas in der Art zustande gebracht haben.

Da ist ja in dem Sinne die rwe Smarthome Geschichte leichter einzustellen, aber ich freue mich schon auf die Fragen, die noch kommen *hihi*

Schonmal besten Dank

klausw

Zitat von: IPPhoner2b am 03 November 2014, 18:58:48
Hallo Klaus,

Genau das habe ich gemeint *g*

Jetzt muss ich nur noch verstehen, wie ich das ganze programmieren muss ...

Aber ich denke, es gibt schon hier und da genug Nutzer, die so etwas in der Art zustande gebracht haben.
Klar doch, schau mal in den Anfängerfragen.
Das muss so in der Art aussehen (fhem.cfg Format...wenn Du direkt im def änderst fallen der Backslash und das zweite Semikolon weg):

define act_on_rolladentimer notify rolladentimer {\
  if ("$EVENT" eq "down") {\
    my $svar = ReadingsVal("Rollladenschalter","state",0);;\
    if ($svar ne "up") {fhem "set Rolladen down";;}\
  }\
}
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

IPPhoner2b

Hallo Klaus,

danke für deine Antwort,
bin jetzt mal wieder ein bissl am lesen, habe aber doch eine sehr "banale" Frage (also eigentlich wie immer  :o )

Wenn ich jetzt eine Bank des MCP als Input, und die andere als Output definiere, und davon dann jeweils 2 Ein- und Ausgänge für jeweils ein Rollo brauche, muss ich dass dann jeweils einzeln definieren, oder kann ich den Define Block als ganzes lassen, und kann mir dann die einzelnen Ports irgendwie zuweisen?

So ist es ja momentan
define mcp_20 I2C_MCP23017 0x20
attr mcp_20 IODev chip
attr mcp_20 Interrupt B0,B1,B2,B3,B4,B5,B6,B7
attr mcp_20 InterruptOut connected_active-low
attr mcp_20 OutputPorts A0,A1,A2,A3,A4,A5,A6,A7
attr mcp_20 Pullup B0,B1,B2,B3,B4,B5,B6,B7
attr mcp_20 group MCP23017
attr mcp_20 invert_input B0,B1,B2,B3,B4,B5,B6,B7


Oder müsste ich dann z.B.
define kueche-links I2C_MCP23017 0x20
attr kueche-links IODev chip
attr kueche-links Interrupt B0,B1
attr kueche-links InterruptOut connected_active-low
attr kueche-links OutputPorts A0,A1
attr kueche-links Pullup B0,B1
attr kueche-links group kueche-links
attr kueche-links invert_input B0,B1

define kueche-rechts I2C_MCP23017 0x20
attr kueche-rechts IODev chip
attr kueche-rechts Interrupt B2,B3
attr kueche-rechts InterruptOut connected_active-low
attr kueche-rechts OutputPorts A2,A3
attr kueche-rechts Pullup B2,B3
attr kueche-rechts group kueche-rechts
attr kueche-rechts invert_input B2,B3

klausw

Zitat von: IPPhoner2b am 09 November 2014, 12:33:39
Wenn ich jetzt eine Bank des MCP als Input, und die andere als Output definiere, und davon dann jeweils 2 Ein- und Ausgänge für jeweils ein Rollo brauche, muss ich dass dann jeweils einzeln definieren, oder kann ich den Define Block als ganzes lassen, und kann mir dann die einzelnen Ports irgendwie zuweisen?

so wie Du es hast ist es richtig.
Jedes Ic darf nur einmal definiert werden.
Andernfalls überschreibt die letzte Definition alle Vorangegangenen.
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