6. díl - Ovládací tlačítka (vypínače)
V projektu Pi-Home můžete použít jakékoliv standardní tlačítka a vypínače pro 230 V nebo speciální pro 24 V atp. V inteligentních domech se namísto vypínačů (klasické polohy vypnuto/zapnuto) používají designově úplně stejné krytky, akorát mechanizmus je tlačítko (pružinka a po stisku vrácení do původní polohy) . Důvod je zřejmý, na tlačítko můžeme navázat víc ruzných funkcí a neřešíme stav (opakované stlačení, podržení atd). V naších realizacích máme velmi dobrou zkušenost s klasickými 230V tlačítky od firmy Hager/Berker, ale samozřejmě je možné použít jakékoliv jiné značky.
Co budeme potřebovat:
2. díl - OpenHAB na Raspberry Pi
Klasické 230V tlačítka - volba dle designu, aby se vám líbily
Originál Arduino Mega s originál Ethernet 2 Shieldem (DIN držák)
Krone svorky / DIN držák
Napájení a propojení
Standardně se k tlačítku tahá UTP kabel. Postačí bohatě CAT5 nebo CAT6. Pro jednotlačítko potřebujeme pouze 2 žíly, pro dvojtlačítko 3 žíly, pro čtyřtlačítko 5 žil. Tam kde tedy bude víc tlačítek lze potáhnout i jeden UTP kabel a zapojit více tlačítek z jednoho kabelu, určitě si ale ponechte rezervu, nikdy nevíte co bude ještě potřeba. Vždy je zapojena země GND a ze všech tlačítek jsou všechny GND pospojované na zemnící KRONE svorce - na obrázku červená svorka (má všechny piny pospojené). Jednotlivé tlačítka jsou pak na klasické bílé KRONE svorce a jednotlivé vývody jsou pak odtud připojené k pinům desky Arduino Mega. Přes KRONE svorku to jde kvůli možnostem změn a lepšímu přehledu. Samozřejmě lze vyvést UTP žíly přímo na pin Arduina, ale může se to stát rigindní a nepřehledné. Na jednu Arduino Mega desku lze zapojit více než 50 jednotlačítek nebo 25 dvoutlačítek atd.
Software
Cílem je aby nám Arduino poslalo přes MQTT protokol informaci, že došlo ke stisku (spojení PIN a GND). Podržíme-li tlačítko bude se informace o stisku opakovat po zvolené časové prodlevě, např. po půlsekundě. Sketch zapojení tlačítek modelového domu naleznete níže. Informace o stisku je přes MQTT odchycena v OpenHAB kde dojde k updatu u daného tlačítka v seznamu dle konkrétní zprávy MQTT. V OpenHAB je nastavena expirace (automatické vypnutí) na 1s. Posledním krokem je pak nastavení pravidel (Rules), které provedou akci když dojde k updatu hodnoty u daného tlačítka - jakou akci vyvolat.
Ukázkový sketch
V tomto jednoduchém sketchi jsou použité knihovny SPI.h, Ethernet2.h a PubSubClient.h. V adresáři pro Arduino se musí nacházet Makefile (název souboru) s obsahem níže. Zde je uvedeno, jaké knihovny budeme načítat a kde jsou umístěny. Knihovny můžete vyhledat na internetu a stáhnout. Dále je v Makefile jednoznačná specifikace Arduina, já používám specifický název, jak se Arduino hlásí na cestě /dev/serial/by-id/usb-Arduinoxxxx. Jednoduše jděte do složky a zkuste zapojit/odpojit dané Arduino a zaznamenejte si jaký název se zde objeví. Jmeno zařízení zkopírujte do Makefile. V sketchi jsou pak deklarované proměnné (piny), na kterých jsou připojeny jednotlivé tlačítka. Stisknutí tlačítka vyvolá spojení pinu Arduina s GND a zaslání MQTT s informací, že došlo k stisku. Aktualizuje se Item daného tlačítka v OpenHAB a vyvolá se pravidlo, pokud je definované. Vzor sketche Arduina a příklad pravidla Rule pro OpenHAB naleznete níže:
Vzorový "Makefile"
ARDUINO_DIR = /usr/share/arduino
BOARD_TAG = mega2560
ARDUINO_PORT = /dev/serial/by-id/usb-Arduino__www.arduino.cc__0042_85531303630351119291-if00 (nahraďte vlastním názvem)
USER_LIB_PATH = /usr/share/arduino/libraries
ARDUINO_LIBS = Ethernet2 SPI pubsubclient
include /usr/share/arduino/Arduino.mk
Vzorový sketch "ArduinoPA3.ino"
/*
Arduino 3 (PA03)
- connects to an MQTT server
- publishes "hello world" to the topic "pihome"
- subscribes to the specific topic pihome/xxx
- sends a specific "on"/"off" to the specific topic when a specific button is pressed
- multiple arduino's with same generic sketch can run parallel to each other
- multiple arduino's need each to have a unique ip-addres, unique mac address and unique MQTT client-ID
- tested on arduino-mega with W5500 ethernet shield
*/
//------------------------------------------------------------------------------
#include <SPI.h>
#include <Ethernet2.h>
#include <PubSubClient.h>
// Set relay variables to Arduino digital pins
// pin 0 RX
// pin 1 TX
// pin 4 (SS for SD Card)
//B111 has underscore because B111 variable already exist in some of the library :D and PIN 5 is not usable as well
int B111_ = 39;
int B112 = 6;
int B121 = 7;
int B122 = 8;
int B131 = 9;
// pin 10 (SS for Ethernet)
int B132 = 11;
int B133 = 12;
int B134 = 13;
int B141 = 2;
int B142 = 3;
int B151 = 14;
int B152 = 15;
int B153 = 16;
int B154 = 17;
int B155 = 18;
int B156 = 19;
// pin 20 SDA
// pin 21 SCL
int B157 = 22;
int B158 = 24;
int B159 = 26;
int B160 = 28;
int B161 = 30;
int B162 = 32;
int B201 = 34;
int B202 = 36;
int B211 = 23;
int B212 = 25;
int B213 = 27;
int B214 = 29;
int B221 = 31;
int B222 = 33;
int B223 = 35;
int B224 = 37;
int B231 = 38;
int B232 = 40;
int B233 = 42;
int B234 = 44;
int B241 = 46;
int B242 = 47;
int B243 = 48;
int B244 = 49;
//int rez = 39;
//int rez = 41;
//int rez = 43;
//int rez = 45;
// pin 50 (SS for Ethernet)
// pin 51 (MOSI)
// pin 52 (MISO)
// pin 53 (SCK)
//A0 (D54)
// int Rez = 54;
// int Rez = 55;
// int Rez = 56;
// int Rez = 57;
// int Rez = 58;
// int Rez = 59;
// pin 60 inaccesibble
// int Rez = 61;
//int rez = 63;
//int rez = 64;
//int rez = 65;
//int rez = 66;
//int rez = 67;
//int rez = 68;
//int rez = 69;
//A15 (D69)
// Set variables to act as virtual switches
// Set variable values initially to LOW (and not HIGH)
// HIGH or LOW as defautl is based on Relay Board
//---------------------------------------------------------------------------
// Arduino MAC address must be unique for every node in same network
// To make a new unique address change last letter
// Arduino 3
byte mac[] = { 0xCC, 0xFA, 0x0B, 0xCC, 0x19, 0x01 };
// Unique static IP address of this Arduino 1
IPAddress ip(10,0,0,173);
// IP Address of your MQTT broker (OpenHAB server)
byte server[] = { 10, 0, 0, 24 };
// Handle and convert incoming MQTT messages ----------------------------------------
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived (no messages expected though)
}
// Initiate instances -----------------------------------
EthernetClient arduino3;
PubSubClient client(server, 1883, callback, arduino3);
void setup(){
Ethernet.begin(mac, ip);
if (client.connect("arduino3", "openhabian", "openhabian")) {
client.publish("pihome", "Hello world - here Arduino PA03 with IP 10.0.0.173");
}
pinMode(B111_, INPUT);
digitalWrite(B111_, HIGH);
pinMode(B112, INPUT);
digitalWrite(B112, HIGH);
pinMode(B121, INPUT);
digitalWrite(B121, HIGH);
pinMode(B122, INPUT);
digitalWrite(B122, HIGH);
pinMode(B131, INPUT);
digitalWrite(B131, HIGH);
pinMode(B132, INPUT);
digitalWrite(B132, HIGH);
pinMode(B133, INPUT);
digitalWrite(B133, HIGH);
pinMode(B134, INPUT);
digitalWrite(B134, HIGH);
pinMode(B141, INPUT);
digitalWrite(B141, HIGH);
pinMode(B142, INPUT);
digitalWrite(B142, HIGH);
pinMode(B151, INPUT);
digitalWrite(B151, HIGH);
pinMode(B152, INPUT);
digitalWrite(B152, HIGH);
pinMode(B153, INPUT);
digitalWrite(B153, HIGH);
pinMode(B154, INPUT);
digitalWrite(B154, HIGH);
pinMode(B155, INPUT);
digitalWrite(B155, HIGH);
pinMode(B156, INPUT);
digitalWrite(B156, HIGH);
pinMode(B157, INPUT);
digitalWrite(B157, HIGH);
pinMode(B158, INPUT);
digitalWrite(B158, HIGH);
pinMode(B159, INPUT);
digitalWrite(B159, HIGH);
pinMode(B160, INPUT);
digitalWrite(B160, HIGH);
pinMode(B161, INPUT);
digitalWrite(B161, HIGH);
pinMode(B162, INPUT);
digitalWrite(B162, HIGH);
pinMode(B201, INPUT);
digitalWrite(B201, HIGH);
pinMode(B202, INPUT);
digitalWrite(B202, HIGH);
pinMode(B211, INPUT);
digitalWrite(B211, HIGH);
pinMode(B212, INPUT);
digitalWrite(B212, HIGH);
pinMode(B213, INPUT);
digitalWrite(B213, HIGH);
pinMode(B214, INPUT);
digitalWrite(B214, HIGH);
pinMode(B221, INPUT);
digitalWrite(B221, HIGH);
pinMode(B222, INPUT);
digitalWrite(B222, HIGH);
pinMode(B223, INPUT);
digitalWrite(B223, HIGH);
pinMode(B224, INPUT);
digitalWrite(B224, HIGH);
pinMode(B231, INPUT);
digitalWrite(B231, HIGH);
pinMode(B232, INPUT);
digitalWrite(B232, HIGH);
pinMode(B233, INPUT);
digitalWrite(B233, HIGH);
pinMode(B234, INPUT);
digitalWrite(B234, HIGH);
pinMode(B241, INPUT);
digitalWrite(B241, HIGH);
pinMode(B242, INPUT);
digitalWrite(B242, HIGH);
pinMode(B243, INPUT);
digitalWrite(B243, HIGH);
pinMode(B244, INPUT);
digitalWrite(B244, HIGH);
}
//-----------------------------------------------
long lastReconnectAttempt = 0;
boolean reconnect() {
if (client.connect("arduino3", "openhabian", "openhabian")) {
// Once connected, publish an announcement...
client.publish("pihome","Arduino 3 - reconnected");
client.subscribe("pihome/heating");
client.subscribe("pihome/shutters");
}
return client.connected();
}
//----------------------------------------------
//Priprava tlacitek
void loop()
{
// read the pushbutton input pin:
if (digitalRead(B111_)==LOW){
client.publish("pihome/buttons","B111_push");
delay(50);
}
if (digitalRead(B112)==LOW){
client.publish("pihome/buttons","B112_push");
delay(50);
}
if (digitalRead(B121)==LOW){
client.publish("pihome/buttons","B121_push");
delay(50);
}
if (digitalRead(B122)==LOW){
client.publish("pihome/buttons","B122_push");
delay(50);
}
if (digitalRead(B131)==LOW){
client.publish("pihome/buttons","B131_push");
delay(50);
}
if (digitalRead(B132)==LOW){
client.publish("pihome/buttons","B132_push");
delay(50);
}
if (digitalRead(B133)==LOW){
client.publish("pihome/buttons","B133_push");
delay(50);
}
if (digitalRead(B134)==LOW){
client.publish("pihome/buttons","B134_push");
delay(50);
}
if (digitalRead(B141)==LOW){
client.publish("pihome/buttons","B141_push");
delay(50);
}
if (digitalRead(B142)==LOW){
client.publish("pihome/buttons","B142_push");
delay(50);
}
if (digitalRead(B151)==LOW){
client.publish("pihome/buttons","B151_push");
delay(50);
}
if (digitalRead(B152)==LOW){
client.publish("pihome/buttons","B152_push");
delay(50);
}
if (digitalRead(B153)==LOW){
client.publish("pihome/buttons","B153_push");
delay(50);
}
if (digitalRead(B154)==LOW){
client.publish("pihome/buttons","B154_push");
delay(50);
}
if (digitalRead(B155)==LOW){
client.publish("pihome/buttons","B155_push");
delay(50);
}
if (digitalRead(B156)==LOW){
client.publish("pihome/buttons","B156_push");
delay(50);
}
if (digitalRead(B157)==LOW){
client.publish("pihome/buttons","B157_push");
delay(50);
}
if (digitalRead(B158)==LOW){
client.publish("pihome/buttons","B158_push");
delay(50);
}
if (digitalRead(B159)==LOW){
client.publish("pihome/buttons","B159_push");
delay(50);
}
if (digitalRead(B160)==LOW){
client.publish("pihome/buttons","B160_push");
delay(50);
}
if (digitalRead(B161)==LOW){
client.publish("pihome/buttons","B161_push");
delay(50);
}
if (digitalRead(B162)==LOW){
client.publish("pihome/buttons","B162_push");
delay(50);
}
if (digitalRead(B201)==LOW){
client.publish("pihome/buttons","B201_push");
delay(50);
}
if (digitalRead(B202)==LOW){
client.publish("pihome/buttons","B202_push");
delay(50);
}
if (digitalRead(B211)==LOW){
client.publish("pihome/buttons","B211_push");
delay(50);
}
if (digitalRead(B212)==LOW){
client.publish("pihome/buttons","B212_push");
delay(50);
}
if (digitalRead(B213)==LOW){
client.publish("pihome/buttons","B213_push");
delay(50);
}
if (digitalRead(B214)==LOW){
client.publish("pihome/buttons","B214_push");
delay(50);
}
if (digitalRead(B221)==LOW){
client.publish("pihome/buttons","B221_push");
delay(50);
}
if (digitalRead(B222)==LOW){
client.publish("pihome/buttons","B222_push");
delay(50);
}
if (digitalRead(B223)==LOW){
client.publish("pihome/buttons","B223_push");
delay(50);
}
if (digitalRead(B224)==LOW){
client.publish("pihome/buttons","B224_push");
delay(50);
}
if (digitalRead(B231)==LOW){
client.publish("pihome/buttons","B231_push");
delay(50);
}
if (digitalRead(B232)==LOW){
client.publish("pihome/buttons","B232_push");
delay(50);
}
if (digitalRead(B233)==LOW){
client.publish("pihome/buttons","B233_push");
delay(50);
}
if (digitalRead(B234)==LOW){
client.publish("pihome/buttons","B234_push");
delay(50);
}
if (digitalRead(B241)==LOW){
client.publish("pihome/buttons","B241_push");
delay(50);
}
if (digitalRead(B242)==LOW){
client.publish("pihome/buttons","B242_push");
delay(50);
}
if (digitalRead(B243)==LOW){
client.publish("pihome/buttons","B243_push");
delay(50);
}
if (digitalRead(B244)==LOW){
client.publish("pihome/buttons","B244_push");
delay(50);
}
//Wait 50 ms and repeat
delay(50);
if (!client.connected()) {
long now = millis();
if (now - lastReconnectAttempt > 5000) {
lastReconnectAttempt = now;
// Attempt to reconnect
if (reconnect()) {
lastReconnectAttempt = 0;
}
}
} else {
// Client connected
client.loop();
}
}
// End of sketch ---------------------------------
OpenHAB
V OpenHAB by jste již měli dle tutoriálu mít tlačítka připravené. Zkuste si tedy přidat nějaké pravidlo. Níže je vzorové pravidlo pro tlačítko B111 a rosvěcení/zhasnutí světla L111.
configuration: {}
triggers:
- id: "2"
configuration:
itemName: B111
state: ON
previousState: OFF
type: core.ItemStateChangeTrigger
conditions: []
actions:
- inputs: {}
id: "1"
configuration:
type: application/vnd.openhab.dsl.rule
script: |2
if(L111.state == ON){
sendCommand(L111, OFF)
}else{
sendCommand(L111, ON)
}
type: script.ScriptAction
A je to! Teď můžete otestovat nějaké tlačítko. Toto řešení lze neomezeně rozšířit. Máme zkušenosti s bezproblémovou instalaci až s 200 tlačítky v rodinném domě.
Tip: Na jednu desku Arduino Mega s Ethernet shieldem se vejde přes 50 tlačítek.