PCF8574

Auf dieser Seite ist beschrieben, wie PCF8574 mit fhem beispielhaft genutzt werden kann. Mein Fokus liegt auf Anwendung im Bereich Hausautomatisierung.

Voraussetzungen

Achtung: i2c muss konfiguriert sein.

Vorbereitung

Verkabelung

Pi Pin Pi PCF8574
01 3,3V VCC
06 GND GND
03 SDA1 SDA
05 SCL1 SCL
40 GPIO21 INT
06 GND via Taster jeweils auf Port 0 bis 7

Die 8 I/O Ports des PCF8574 sind jeweils über Taster mit GND (z.B. Pin06) verbunden.

i2c Device erzeugen

define i2c RPII2C 1
attr i2c alias Onboard I2C Controller 1
attr i2c room ops

Input mit allen Ports

Tip: Für alle hier aufgeführten Kommandos verwende ich die fhem Telnet-Schnittstelle mit rlwrap.

Beispiel um alle Ports als Input z.B. für Taster nutzen zu können. In diesem Beispiel ist die Adresse des PCF8574 0x21. Zunächst erzeuge ich das Device und setze alle Ports auf „high“. Damit liegt an jedem der 8 Ports „high“-Pegel (3,3 Volt) an. Ein angeschlossener Taster muss nun bei Tastendruck eine Verbindung zu GND (0 Volt) herstellen. Das Betätigen des Tasters wird mit „off“ gemeldet.

PCF8574 Device konfigurieren

define i2c21 I2C_PCF8574 0x21
attr i2c21 IODev i2c
attr i2c21 room ops
set i2c21 Port0,Port1,Port2,Port3,Port4,Port5,Port6,Port7 on
attr i2c21 InputPorts 0 1 2 3 4 5 6 7

Interrupt einrichten

Um eine Änderung der Ports detektieren zu können muss ein Interrupt verwendet werden. Ich verwende hierzu in diesem Beispiel Pin 40 bzw. GPIO 21. Der Port wird als Input konfiguriert und der intere Widerstand gesetzt, so dass am Port „high“ (3,3 Volt) anliegt. Der PCF8574 legt bei jeder Änderung einer der 8 Ports seinen Interrupt-Ausgang auf GND (0 Volt). Sobald ein Interrupt auslöst, wird mit dem „userReadings“-Kommando get i2c21 der Status aller Ports aktualisiert.

define int RPI_GPIO 21
attr int direction input
attr int active_low yes
attr int interrupt both
attr int pud_resistor up
attr int userReadings get_i2c21 {fhem ("get i2c21")}

Testen

Mit inform kann einfach getestet werden, ob alles wie erwartet funktioniert. Wenn man anschließend Taster betätigt, sieht man wann welcher Taster gedrückt (on) und wieder los gelassen wurde (off).

inform timer i2c21:Port.*
beispieloutput.txt
2015-04-25 18:00:24 I2C_PCF8574 i2c21 Port4: on
2015-04-25 18:00:27 I2C_PCF8574 i2c21 Port4: off
2015-04-25 18:00:28 I2C_PCF8574 i2c21 Port0: on
2015-04-25 18:00:29 I2C_PCF8574 i2c21 Port4: on
2015-04-25 18:00:30 I2C_PCF8574 i2c21 Port6: on
2015-04-25 18:00:32 I2C_PCF8574 i2c21 Port4: off
2015-04-25 18:00:32 I2C_PCF8574 i2c21 Port0: off
2015-04-25 18:00:33 I2C_PCF8574 i2c21 Port6: off
2015-04-25 18:00:34 I2C_PCF8574 i2c21 Port6: on
2015-04-25 18:00:34 I2C_PCF8574 i2c21 Port6: off

readingsProxy einrichten

Licht mit Taster

Für die einzelnen Ports können jetzt z.B. einzelne readingsProxys eingerichtet werden. Beispiel für Port 0:

define i2c21p0 readingsProxy i2c21:Port0
attr i2c21p0 room ops
attr i2c21p0 alias Taster 0
attr i2c21p0 valueFn {($VALUE eq "on")?"off":"on"}

Wie man nun eine einzelne Lampe mit dem Taster schalten kann soll folgendes Beispiel mit einem Dummy zeigen:

define lampe0 dummy
attr lampe0 room ops
attr lampe0 devStateIcon on:on:off off:off:on
attr lampe0 alias Lampe 0
set lampe0 off
 
define lampe0_toggle notify i2c21p0:off { \
if   (Value("lampe0") eq "off") {fhem "set lampe0 on"} \
else {fhem "set lampe0 off"} \
}

Jalousie mit einem Taster

Hier ein Beispiel um eine Jalousie mit einem Taster zu steuern:

define i2c21p4 readingsProxy i2c21:Port4
attr i2c21p4 room ops
attr i2c21p4 alias Taster 4
attr i2c21p4 valueFn {($VALUE eq "on")?"off":"on"}
define jalousie0 dummy
attr jalousie0 room ops
attr jalousie0 devStateIcon hoch:fts_shutter_up@yellow:stop_h runter:fts_shutter_down@yellow:stop_r stop_r:fts_shutter_up@white:hoch stop_h:fts_shutter_down@white:runter
attr jalousie0 alias Jalousie 0
set jalousie0 stop_r
 
# Cycle: hoch -> stop_h -> runter -> stop_r -> ..
define jalousie_toggle notify i2c21p4:off { \
if    (Value("jalousie0") eq "stop_r") {fhem "set jalousie0 hoch"} \
elsif (Value("jalousie0") eq "hoch")   {fhem "set jalousie0 stop_h"} \
elsif (Value("jalousie0") eq "stop_h") {fhem "set jalousie0 runter"} \
else  {fhem "set jalousie0 stop_r"} \
}
 
# Alternative/Verbesserung: Automatisch stoppen nach Wartezeit (Nachteil: Wenn zwischenzeitlich noch ein Tastendruck kam werden trotzdem die Kommandos nach dem sleep ausgeführt)
delete jalousie_toggle
define jalousie_toggle notify i2c21p4:on { \
if    (Value("jalousie0") eq "stop_r") {fhem "set jalousie0 hoch;;sleep 5;;set jalousie0 stop_h"} \
elsif (Value("jalousie0") eq "hoch")   {fhem "set jalousie0 stop_h"} \
elsif (Value("jalousie0") eq "stop_h") {fhem "set jalousie0 runter;;sleep 5;;set jalousie0 stop_r"} \
else  {fhem "set jalousie0 stop_r"} \
}

2 Lampen mit einem Taster

Hier ein Beispiel, wie man 2 Lampen mit einem Taster schalten kann:

define i2c21p6 readingsProxy i2c21:Port6
attr i2c21p6 room ops
attr i2c21p6 alias Taster 6
attr i2c21p6 valueFn {($VALUE eq "on")?"off":"on"}
define lampeA dummy
attr lampeA room ops
attr lampeA devStateIcon on:on:off off:off:on
attr lampeA alias Lampe A
set lampeA off
 
define lampeB dummy
attr lampeB room ops
attr lampeB devStateIcon on:on:off off:off:on
attr lampeB alias Lampe B
set lampeB off
 
define lampeAB_toggle notify i2c21p6:off { \
if    (Value("lampeA") eq "off" and Value("lampeB") eq "off")  {fhem "set lampeA on"}  \
elsif (Value("lampeA") eq "on"  and Value("lampeB") eq "off")  {fhem "set lampeB on"}  \
elsif (Value("lampeA") eq "on"  and Value("lampeB") eq "on")   {fhem "set lampeA off"} \
else  {fhem "set lampeA,lampeB off"} \
}