angeregt durch diesen Thread hab ich mich mal hin gesetzt und ein PIN Pad /Codetastatur für die Homematic gebastelt.
Die Auswertung der Eingabe findet in der CCU statt, kann also nicht durch Manipulation am PinPad übergangen werden. Was natürlich am Pin Pad im Aussenbereich geht wäre einen Keylogger anzuschließen.
Das ursprüngliche Arduinoprogramm ist NICHT auf Stromsparen ausgelegt, ein Batteriebetrieb daher NICHT möglich. Es wird eine Spannungsversorgung per USB oder 5 bis 12V an VIN / GND benötigt.
Erweiterung: Jerome hat dankenswerterweise den Sketch erweitert. Nach installation der LowPower Bibliothek kann ein Arduino Pro Mini (3,3v, 8MHz, wie bei den AskSin Projekten auch) verwendet werden, das ganze ist dann Batterietauglich. Versorgung über z.B. 2xAA Batterie. Bitte auch die Hinweise hier beachten:
https://asksinpp.de/Grundlagen/01_hardw ... versorgung
DISCLAIMER:
Der HM Funk ist als NICHT SICHER zu betrachten, dessen sollte sich jeder bewusst sein der damit seine Haustüre oder das Garagentor öffnen will. Verwendung auf eigene Verantwortung!
Mit einer 3x4 Matrix Tastatur ist es in Kombination mit dem HM-MOD-EM-8Bit möglich die Auswertung der Tasten in die CCU zu legen.
Benötigt werden:
- 3x4 Matrix Tastatur
- Arduino (hier: Nano, oder Pro Mini 3,3v 8MHz)
- HM-MOD-EM-8Bit
- Gehäuse
- optional: LED rot und grün (oder DuoLED)
- Für Batteriebetrieb: zusätzlichen Taster, weitere LED um Wachzustand anzuzeigen
Verkabelung:
Einstellungen des HM-MOD-EM-8bit auf der CCU:
Das Modul muss auf "Modus 2" gestellt werden damit es mit meinem Skript zusammen arbeitet.
Ebenfalls sollte die Übertragung auf gesichert gestellt werden, um zumindest eine einfache Replay-Attacke zu erschweren.
Sketch für den Arduino (Quick und Dirty):
Code: Alles auswählen
#include <Keypad.h>
//Hier wird die größe des Keypads definiert
const byte COLS = 3; //3 Spalten
const byte ROWS = 4; //4 Zeilen
//Die Ziffern/Zeichen:
char hexaKeys[ROWS][COLS]={
{'#','0','*'},
{'9','8','7'},
{'6','5','4'},
{'3','2','1'}
};
byte colPins[COLS] = { 8, 7, 6 }; //Definition der Pins für die 3 Spalten
byte rowPins[ROWS] = { 5, 4, 3, 2 };//Definition der Pins für die 4 Zeilen
char Taste; //pressedKey entspricht in Zukunft den gedrückten Tasten
byte dataPins[] = {9, 10, 11, 12};
byte dataAccept = 13;
Keypad Tastenfeld = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); //Das Keypad kann absofort mit myKeypad angesprochen werden
void setup() {
Serial.begin(9600);
for (int i=0; i<=3; i++) {
pinMode(dataPins[i],OUTPUT);
}
pinMode(dataAccept,OUTPUT);
}
void loop() {
Taste = Tastenfeld.getKey(); //pressedKey entspricht der gedrückten Taste
if (Taste) {
switch (Taste) {
case '0':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '1':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '2':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '3':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '4':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '5':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '6':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '7':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '8':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '9':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '*':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '#':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
default:
break;
}
}
}
Und hier der Sketch mit LowPower, für Batteriebetrieb geeignet. Vielen Dank an jp112sdl für die Erweiterung!
ACHTUNG: Alle Pins um eins verschoben, auf Pin 2 wird ein zusätzlicher Taster gegen GND verwendet um den Arduino aus dem Tiefschlaf zu holen. PIN14 ist A0. PIN15 ist A1.
Auf PIN15 kann eine LED (mit Vorwiderstand, ich hatte gerade eine einfache grüne 3mm LED mit 220Ohm benutzt) angeschlossen werden um zu zeigen wenn der Arduino wach ist und eingaben auf der Tastatur möglich sind.
Code: Alles auswählen
#include <Keypad.h>
#include <LowPower.h>
#define WAKEUP_PIN 2
#define POWER_LED 15
#define SLEEP_TIMEOUT_MS 5000
//Hier wird die größe des Keypads definiert
const byte COLS = 3; //3 Spalten
const byte ROWS = 4; //4 Zeilen
//Die Ziffern/Zeichen:
char hexaKeys[ROWS][COLS] = {
{'#', '0', '*'},
{'9', '8', '7'},
{'6', '5', '4'},
{'3', '2', '1'}
};
byte colPins[COLS] = { 9, 8, 7 }; //Definition der Pins für die 3 Spalten
byte rowPins[ROWS] = { 6, 5, 4, 3 };//Definition der Pins für die 4 Zeilen
char Taste; //pressedKey entspricht in Zukunft den gedrückten Tasten
byte dataPins[] = {10, 11, 12, 13};
byte dataAccept = 14;
unsigned long timerStartMillis = 0;
volatile bool wkup = false;
Keypad Tastenfeld = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); //Das Keypad kann absofort mit myKeypad angesprochen werden
void setup() {
Serial.begin(9600);
for (int i = 0; i <= 3; i++) {
pinMode(dataPins[i], OUTPUT);
}
pinMode(dataAccept, OUTPUT);
pinMode(POWER_LED, OUTPUT);
pinMode(WAKEUP_PIN, INPUT_PULLUP);
}
void resetTimer() {
wkup = false;
timerStartMillis = millis();
}
void processKeyPad() {
Taste = Tastenfeld.getKey(); //pressedKey entspricht der gedrückten Taste
if (Taste) {
resetTimer();
switch (Taste) {
case '0':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '1':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '2':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '3':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '4':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '5':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '6':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '7':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], LOW);
digitalWrite(dataPins[3], HIGH);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '8':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '9':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], HIGH);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '*':
digitalWrite(dataPins[0], HIGH);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
case '#':
digitalWrite(dataPins[0], LOW);
digitalWrite(dataPins[1], LOW);
digitalWrite(dataPins[2], HIGH);
digitalWrite(dataPins[3], LOW);
delay(200);
digitalWrite(dataAccept, HIGH);
delay(200);
digitalWrite(dataAccept, LOW);
Serial.print("Die Taste ");
Serial.print(Taste);
Serial.print("wurde gedrueckt");
Serial.println(); //Teile uns am Serial Monitor die gedrückte Taste mit
break;
default:
break;
}
}
}
void dummyISR() {
wkup = true;
}
void loop() {
if (wkup) resetTimer();
processKeyPad();
attachInterrupt(0, dummyISR, LOW);
if (millis() - timerStartMillis > SLEEP_TIMEOUT_MS) {
digitalWrite(POWER_LED, LOW);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
} else {
digitalWrite(POWER_LED, HIGH);
}
detachInterrupt(0);
}
Systemvariablen auf der CCU:
Auf der CCU werden 3 Variablen benötigt:
Programme auf der CCU:
Auf der CCU werden 3 Programme benötigt.
Mein "Auswerteprogramm" verschickt im Moment bei korrekter Codeeingabe (1234 oder 4567) lediglich eine Pushovernachricht per Skript mit dem Code als Inhalt. Das Skript kann man gegen die gewünschte Aktion austauschen, also z.B. Garage öffnen, Keymatic öffnen, ...
Mit * wird der aktuelle Inhalt der Eingabevariable gelöscht, damit kann also eine Eingabe abgebrochen und neu gestartet werden.
Eine Eingabe MUSS mit # abgeschlossen werden, erst dann startet die Auswertung.
Ein Code kann nicht mit 0 beginnen, sondern nur mit den Ziffern 1 bis 9.
Nach der dritten Falscheingabe wird das PinPad für 5 Minuten gesperrt.
Nach der vierten Falscheingabe wird das PinPad für 1 Stunde gesperrt.
Nach der fünften Falscheigabe wird endgültig gesperrt.
Bei korrekter Eingabe wird der Fehlerzähler auf 0 gesetzt.
Ich empfehle dringend die optionalen LEDs zu verbauen, und alle die das Teil bedienen darauf zu Impfen das nach jedem Tastendruck das aufleuchten der grünen LED abzuwarten ist. Sonst könnt ihr euch sicher sein das dass ganze schief geht.
Jetzt fehlt nur noch ein schönes Gehäuse aus dem 3 Drucker, dann könnte das ganze Montiert werden.
Gruß,
Sven