Nachdem erste Grundlagen der Arduino-Plattform in HowTo Teil 1 der Blogserie "Arduino im Smart Home" angesprochen wurden,
geht es in diesem HowTo direkt an die Anbindung des ersten Sensors, dessen Messwerte mithilfe des Arduino Uno ausgewertet
und per UDP-Protokoll über eine Netzwerkverbindung an die Smart-Home-Zentrale in Form eines Loxone Miniservers (Affiliate-Link) gesendet werden.
In nachfolgendem Blogpost werden die dafür notwendigen Installationsschritte für Hard- und Software Schritt für Schritt erklärt und einige relevante Tipps gegeben, sodass der Einstieg auch für interessierte Einsteiger möglich ist.
Bewegungserkennung per Arduino
Aus der Vielzahl möglicher Sensoren, die am Arduino-Board betrieben werden können, wird für diese erste Installation ein Bewegungsmelder genutzt.
Das hat mehrere Gründe. Er ist super günstig, wird praktisch in jedem Raum für eine Anwesenheitserkennung benötigt, kann direkt an die Pins des Arduino angeschlossen werden
und liefert digitale Messwerte (Bewegung bzw. keine Bewegung), welche sehr einfach per UDP weiterverarbeitet werden können.
Benötigte Komponenten
Für die Anwesenheitserkennung werden insgesamt nur wenige Komponenten benötigt, welche für unter 30 Euro erhältlich sind:
Wer gleich alle - und noch viele weitere - Komponenten als Set erwerben möchte, kann sich auch das Funduino Lernset UNO 8 (Affiliate-Link) ansehen.
Bis auf das Ethernet Shield sind dort alle notwendigen Komponenten enthalten, die in diesem und folgenden HowTo-Anleitungen verwendet werden.
Vorbereitung der Hardware
Obwohl erst für spätere Erweiterungen notwendig, wird an dieser Stelle bereits ein Breadboard genutzt, um die Verbindungen zwischen Arduino Uno und PIR (Passiver Infrarot Bewegungsmelder) herzustellen.
Noch eine kurze Info zum Breadboard selbst, die gerade Anfängern helfen kann, dessen Schaltkonzept zu verstehen.
Auf dem Breadboard sind bestimmte Kontakte vertikal bzw. horizontal miteinander verschaltet. So kann bspw. die vom Arduino über den Pin VCC zur Verfügung gestellte Netzspannung über das Breadboard an mehrere Verbraucher verteilt werden.
Dazu werden gewöhnlich die beiden obersten und untersten Reihen verwendet, welche vertikal miteinander verschaltet sind.
Die dazwischenliegenden Reihen sind hingegen vertikal miteinander verschaltet.
Auf diese Weise kann bei obigem Beispiel auch eine Verbindung zwischen den "übereinander" gesteckten Kontakten hergestellt werden, obwohl es auf der Abbildung erst einmal so aussieht, als ob keine Verbindung zustande kommt.
Nachfolgend noch einmal zur Verdeutlichung die miteinander verschalteten Kontakte:
Bevor der Arduino über die Steckbrücken mit dem Breadboard verbunden werden kann, wird das Ethernet Shield auf das Arduino-Board gesteckt, wodurch die fehlende Netzwerkfähigkeit des Arduino-Boards nachgerüstet wird.
Die Pins des Arduino-Boards werden dabei durch das Ethernet Shield durchgeschleift und können weiterhin als Ein- bzw. Ausgänge auf dessen Oberseite verwendet werden.
Danach kann der Bewegungsmelder mit dem Breadboard verbunden werden. Der
- linke Pin des Bewegungsmelders wird an "Ground" (schwarz) angeschlossen, der
- mittlere Pin (gelb) an Pin 2 des Arduino-Boards weiterverbunden und der
- rechte Pin (rot) an VCC (+5 V).
-
Wichtige Anmerkung zu den Pins des Arduino: Der Arduino Uno bietet insgesamt 14 digitale Pins, die als digitale Ein- oder Ausgänge genutzt werden können.
Davon sollten jedoch Pin 0 und 1 nicht direkt verwendet werden, da diese für die serielle Kommunikation zum PC (RX/TX) vorgesehen sind, sodass im Endeffekt beim Arduiono Uno noch 12 digitale Pins zur Verfügung stehen.
Aus oben genanntem Grund wird der Bewegungsmelder in diesem Beispiel direkt mit dem nächsten "freien" Pin 2 verbunden.
So sieht das Ganze dann als fertige Testinstallation aus.
Der Bewegungsmelder besitzt zwei orangefarbene Drehregler.
Mit dem linken Drehregler kann die Dauer des geschalteten Signals nach dem Ende einer erkannten Bewegung eingestellt werden. Wird der Regler im Uhrzeigersinn gedreht, wird die Dauer erhöht.
Empfohlen wird an dieser Stelle die Dauer möglichst gering einzustellen, so dass er ca. drei Sekunden nach der zuletzt erkannten Bewegung ausschaltet (linken Regler gegen den Uhrzeigersinn drehen).
Mit dem rechten Drehregler kann die Empfindlichkeit eingestellt werden.
Die Sensibilität kann erhöht werden, indem der Drehregler im Uhrzeigersinn gedreht wird. Im Smart-Home-Einsatz kann meist die volle Intensität gewählt werden (rechten Regler im Uhrzeigersinn drehen).
Vorbereitung der Arduino-Software
Der Arduino Uno wird nun per USB-Kabel an den PC angeschlossen.
Praktisch ist, dass der Arduino direkt per USB mit der Spannung von 5 V versorgt wird und auch beim späteren Testen kein separates Netzteil (7..12 V) benötigt wird, solange das Arduino-Board am USB-Kabel hängt.
Update vom 24.06.2015:
Der Einsatz eines separaten 9 V Netzweils (Affiliate-Link) macht spätestens ab Szenario 5 Sinn, bei dem ein stromhungriges Schaltrelais vom Arduino angesteuert wird. Die technischen Hintergründe werden im Szenario selbst beschrieben.
Die Arduino-Software, welche als Open-Source-Version heruntergeladen werden kann, steht für Windows, Mac OS X und Linux zur Verfügung. Nachfolgender Screenshot ist von der Mac-Version, die anderen Plattformen bieten jedoch ein vergleichbares Look-and-Feel.
Über den Menüpunkt "Werkzeuge" -> "Platine" -> "Arduino Uno" wird das passende Modell ausgewählt.
Weiterhin wird über den Menüpunkt "Werkzeuge" -> "Port" -> "/dev/cu.usbmodem1411 (Arduino Uno" der vom Betriebssystem erkannte Arduino ausgewählt.
Unter Windows kann das anders aussehen und evtl. Treiber notwendig werden, die im besten Fall jedoch automatisch installiert werden sollten.
Erstellung des Arduino-Programmcodes
Der genutzte Programmcode besteht aus mehreren Teilen.
Teil 1 werden die "Grundeinstellungen" vorgenommen und später verwendeten Variablen definiert.
Teil 2 umfasst das "Setup", welches die relevanten Parameter angibt, die beim Start des Arduino einmal initialisiert werden.
Teil 3 beinhaltet den eigentlichen Programmteil (loop), welcher permanent (mehrfach pro Sekunde) abgearbeitet wird.
Der komplette Sketch kann nachfolgend als Arduino-Datei heruntergeladen werden:
sketch_udp_bewegungsmelder.ino (102 Downloads)
Teil 1 - Grundeinstellungen und Variablendeklaration
Zuerst werden benötigte Softwarebibliotheken mit dem Befehl "#include" eingebunden.
Da es sich dabei um "Standardbibliotheken" handelt, sind diese bereits vorhanden und müssen nicht extra heruntergeladen werden.
Mehr zu Bibliotheken dann in einem späteren HowTo.
Danach wird festgelegt, dass der Bewegungsmelder mit Pin 2 verbunden ist.
Weiterhin wird noch eine Variable namens "BewegungsmelderState" definiert, welche für den späteren Programmablauf notwendig ist, sodass bei einer Statusänderung des Bewegungsmelders jeweils nur ein UDP-Paket abgesendet wird und nicht bei jedem Programmdurchlauf.
Als nächstes werden die Netzwerkeinstellungen vorgenommen.
Hier muss unter "ip" die gewünschte Netzwerkadresse des Arduino vergeben werden, welche im Netzwerk noch nicht belegt ist.
An dieser Stelle werden einige Netzwerkkenntnisse vorausgesetzt. Möchte man später mehrere Arduinos im Netzwerk nutzen, muss darauf geachtet werden, dass sich die "byte mac"-Adresse der Arduinos unterscheidet, da es sonst zu Problemen kommen kann.
Die "Recipient IP" ist der Empfänger der UDP-Nachrichten. In diesem Fall werden die Daten an einen Loxone Miniserver mit der IP 192.168.3.11 und den Port 7001 gesendet, welcher in der Loxone Config frei gewählt werden kann.
Zusätzlich wird noch der Port 7002 als eingehender UDP-Port definiert, der zwar jetzt noch nicht genutzt, aber für spätere Setups relevant sein wird.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
// PIN Settings
#define Bewegungsmelder 2
// Variable Declaration
char BewegungsmelderState = 0;
// Network Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 3, 19);
IPAddress gateway(192, 168, 3, 1);
IPAddress subnet(255, 255, 255, 0);
// Local UDP port to listen on
unsigned int localPort = 7002;
// Recipient IP
IPAddress RecipientIP(192, 168, 3, 11);
// Recipient UDP Port
unsigned int RecipientPort = 7001;
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
// EthernetUDP instance to send and receive packets over UDP
EthernetUDP Udp;
|
Teil 2 - Setup
Im Setup-Teil werden nun relevante Funktionen definiert, die einmal beim Booten des Arduino durchlaufen werden.
Dabei wird der serielle Monitor mit "Serial.begin(9600);" gestartet, sodass später testweise am PC über die Arduino-Software auflaufende Statusmeldungen im "Seriellen Monitor" (zu finden unter dem Menüpunkt "Werkzeuge" verfolgt werden können.
Weiterhin werden mit "Ethernet.begin(mac,ip);" das Netzwerk und mit "Udp.begin(localPort);" die UDP-Funktionalität initialisiert und der Bewegungsmelder als Input definiert.
Zum Schluss wird noch testweise ein "UDP Ready"-Befehl in Empfängerrichtung geschickt, welcher später zur Kontrolle bspw. in der Loxone Config im aktivierten UDP-Monitor erscheint, kurz nachdem der Arduino mit Strom versorgt wird.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void setup()
{
// For debug only
Serial.begin(9600);
// Start Ethernet
Ethernet.begin(mac,ip);
// Start UDP
Udp.begin(localPort);
// Bewegungsmelder
pinMode(Bewegungsmelder, INPUT);
// Send UDP Ready
sendUDP("UDP Ready");
}
|
Teil 3 - Programmablauf (loop)
Als dritter Teil folgt der eigentliche Programmablauf im "loop"-Teil der Programmierung.
Die Programmlogik, die dabei permanent von oben nach unten durchlaufen wird, fragt mit "digitalRead(Bewegungsmelder)"den aktuellen Status des Bewegungsmelders ab und triggert je nach Status entsprechende UDP-Befehle.
Bei einer Bewegung lautet dieser UDP-Befehl "WZ.Bewegungsmelder: 1" und bei Nicht-Bewegung "WZ.Bewegungsmelder: 0".
Bei den jeweiligen if-Schleifen ist dabei wichtig die oben deklarierte Variable "BewegungsmelderState" zu nutzen und entsprechend beim Durchlauf vom Programm anpassen zu lassen.
Sie ist dazu gedacht, dass tatsächlich nur bei einer erfolgten Statusänderung ein einziger UDP-Befehl abgesetzt wird und nicht bei jedem Durchlauf der loop-Logik ein erneuter Befehl mit dem aktuellen Status abgesendet wird.
Am Ende wird mit "delay(20);" eine Zwangspause von 20 Millisekunden eingelegt, bevor der "loop" von vorne beginnt. Weitere Details dazu werden im HowTo Teil 3 vermittelt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
void loop()
{
// Bewegungsmelder (Send)
if (digitalRead(Bewegungsmelder) == LOW && BewegungsmelderState != 0)
{
sendUDP("WZ.Bewegungsmelder: 0");
BewegungsmelderState = 0;
}
if (digitalRead(Bewegungsmelder) == HIGH && BewegungsmelderState != 1)
{
sendUDP("WZ.Bewegungsmelder: 1");
BewegungsmelderState = 1;
}
delay(20);
}
|
Teil 4 - UDP-Sendefunktion
Alles, was jetzt noch fehlt, ist die entsprechende Funktion, welche die UDP-Pakete auch tatsächlich sendet.
|
// Function to send UDP packets
void sendUDP(String text)
{
Udp.beginPacket(RecipientIP, RecipientPort);
// Udp.write("Test");
Udp.print(text);
Udp.endPacket();
}
|
Flashen des Programmcodes auf das Arduino-Board
Sobald der Programmcode in der Arduino-Sofware hinsichtlich der eigenen Netzwerkparameter angepasst wurde, kann über den Play-Button (oben links) das gesamte Programm auf den per USB angeschlossenen Arduino übertragen werden.
Dabei wird links unten die Mitteilung "Sketch wird kompiliert" angezeigt. Nach wenigen Sekunden sollte die Mitteilung "Hochladen abgeschlossen" angezeigt werden.
Einrichtung des Smart-Home-Servers
Unter Loxone lässt sich die eingehende UDP-Nachricht über das Gruppierungselement "Virtueller UDP Eingang" unter Angabe des Ports "7001" abfangen. Dann fehlt nur noch ein "Virtueller UDP Eingang Befehl", welcher als Analogeingang (im Standard vorbelegt) mit der Befehlskennung "WZ.Bewegungsmelder: v" eingefügt werden kann.
Weitere Informationen zum Empfang von UDP-Nachrichten in der Loxone-Config gibt es im Artikel H
omeMatic FHEM-Wetterstation per UDP in Loxone integrieren.
Das Signal des Bewegungsmelders steuert nun einen "Treppenlichtschalter" an, welcher die Lampe bei Bewegung schaltet und nach einigen Sekunden Nicht-Bewegung wieder ausschaltet.
Da der Treppenlichtschalter von einem Bewegungsmelder normalerweise bei jeder erkannten Bewegung ein kontinuierliches Trigger-Signal (1... 1... 1...) erwartet, muss etwas nachgeholfen werden, da der UDP-Bewegungsmelder anders (bzw. schlauer) arbeitet.
Er schaltet bei erkannter Bewegung ein (1) und nach einigen Sekunden Nicht-Bewegung wieder aus (0).
Dadurch würde der Treppenlichtschalter die Lampe bei der Erkennung einer Bewegung zwar einschalten, aber nach Ablauf des internen Treppenlichttimers auch wieder ausschalten, auch wenn weiterhin eine Bewegung erkannt wird.
Diese abweichende Logik lässt sich durch einen "Impulsgeber" wieder geradeziehen, welcher als Bindeglied zwischen die beiden Elemente gesetzt wird und den Treppenlichtschalter bei erkannter Bewegung (1) nun sekündlich triggert (1... 1... 1...).
Aus meinem täglichen Leben
Wer die Vorgehensweise und Programmierung einmal verinnerlicht hat, kann dieses Grundgerüst recht schnell ausbauen, um weitere digitale Sensoren an den Arduino anzubinden und per UDP-Protokoll Nachrichten über das Arduino Ethernet Shield zu verschicken.
Bei meinen Tests hat die UDP-Übertragung bisweilen anstandslos funktioniert.
Die Response-Zeiten sind dabei sehr gut. Sobald eine Bewegung erkannt wird, erfolgt so gut wie verzögerungsfrei der hinterlegte Schaltbefehl in Loxone.
Wer als Empfänger nicht Loxone sondern bspw. FHEM nutzen möchte, muss dort noch einige Einstellungen vornehmen, um auch UDP-Nachrichten empfangen zu können. Sobald ich mich auch damit beschäftigt habe, folgt eine entsprechendes HowTo.
Der Bewegungsmelder selbst macht für seinen günstigen Preis von nur knapp über 1 Euro (5 Stück kosten auf Amazon (Affiliate-Link) weniger als 6 Euro) im Dauereinsatz bisher aus technischer Sicht eine wirklich gute Figur.
Er erkennt Bewegungen verzögerungsfrei und zuverlässig bis zu einer Entfernung von etwas über 10 Metern (höchste Intensität), was ich erstaunlich finde.
Zur Seite hin nimmt die Sensibilität bautechnisch bedingt ab, sodass er einen Erfassungsbereich von 70° aufweist. Insgesamt kann man sich aber wirklich nicht beschweren.
Neben digitalen Werten gibt es aber auch viele Sensoren, die analoge Werte in Form verschiedener Spannungswerte liefern. Wie diese Messwerte aufbereitet und per UDP-Protokoll übertragen werden können, ist Inhalt des nächsten Blogposts.
Wer sich noch mehr mit dem Arduino-Basics vertraut machen möchte, sollte einmal bei Funduino und Fritzing vorbeischauen.
Hier gibt es jede Menge Informationen für Einsteiger, wobei gerade auch die Fritzing-Videotutorials auf YouTube wirklich gut gemacht sind.
Und noch ein Tipp zum Schluss: Wer selbst Schaltskizzen erstellen möchte, sollte sich das Open-Source-Tool Fritzing der Fachhochschule Potsdam herunterladen.
Es ist für alle gängigen PC-Plattformen verfügbar und bietet eine intuitive Benutzeroberfläche zur schnellen Erstellung komplexer Zeichnungen.
Weiter geht es in der Blogserie mit HowTo Teil 3: Helligkeitssensor per UDP an Loxone anbinden.
Nachdem die Anbindung des digitalen Bewegungssensors im vorangegangen
HowTo Teil 2 der Serie "
Arduino im Smart Home" beschrieben wurde, folgt nun ein analoger Helligkeitssensor.
Beim technischen Grundaufbau verändert sich im Vergleich zum vorherigen Szenario zwar nicht viel,
dennoch müssen gerade bei der softwareseitigen Umsetzung über die Arduino IDE-Sofware durch die nun analogen Messwerte einige Punkte beachtet werden,
damit die Übertragung per UDP auch in der gewünschten Form abläuft. Wie das im Detail funktioniert und welche Komponenten dazu benötigt werden, wird im nachfolgenden HowTo erläutert.
Helligkeitsmessung per Arduino
Zur Bestimmung der Helligkeit wird ein einfacher Fotowidestand genutzt, welcher später bspw. als Dämmerungssensor eingesetzt werden kann, um das Licht beim Unterschreiten eines bestimmten Helligkeitswertes automatisch einzuschalten.
Er unterscheidet sich im Vergleich zum vorher angebundenen Bewegungsmelder insofern, dass seine Sensorwerte nicht mehr digitale Werte (also 0 und. 1) liefern,
sondern analoge Werte im Bereich 0 und 1023, welche jeweils die gerade gemessene Helligkeit repräsentieren.
Die Messmethode des Fotowiderstands basiert dabei auf einem einfachen physikalischen Prinzip, wobei sich sein eigener Widerstand je nach Helligkeit variabel anpasst.
Je heller es ist, desto geringer wird sein Widerstand und entsprechend höher ist der Strom, der ihn durchfließt. Der Fotowiderstand wird dabei in Reihe mit einem normalen Widerstand geschaltet, welcher einen ähnlichen hohen Widerstand aufweist.
Dadurch wird in nachfolgender Schaltung die notwendige Spannungsteilung erzielt, welche für die Messung durch den Arduino relevant ist.
Der am Fotowiderstand anliegende Spannungswert kann dabei durch einen analogen Pin des Arduino ermittelt und als Zahl im Wertebereich zwischen 0 und 1023 (10 Bit) ausgegeben werden.
Im Endeffekt heisst das: Je heller es ist, desto höher ist auch der vom Arduino gemessene Sensorwert des Fotowiderstands.
Genau die Information, die benötigt wird, um je nach Helligkeit eine gewünschte Aktion auszulösen.
LDR03 LDR05 LDR07
Benötigte Komponenten
Für die Helligkeitsermittlung werden einige Komponenten benötigt, welche (wie beim vorangegangen Szenario auch) für unter 30 Euro erhältlich sind:
Wer das vorangegangene Szenario aus HowTo Teil 2 als Ausgangspunkt verwendet, benötigt für das folgende Setup lediglich die beiden letztgenannten Komponenten aus obiger Liste, die mit weniger als einem Euro zu Buche schlagen und bspw. auch im Set Funduino UNO 8 (Affiliate-Link) B00P0UMEE0 enthalten sind.
Vorbereitung der Hardware
Spätestens jetzt kommt das bisher noch nicht zwingend notwendige Breadboard zum Einsatz, um die Sensoren "geordnet" mit dem Arduino-Board zu verbinden.
Neben dem Bewegungsmelder aus HowTo Teil 2 nehmen nun also auch der Fotowiderstand und der 1K Ohm Widerstand auf dem Breadboard direkt nebeneinnder Platz.
Wie bereits angesprochen, werden die beiden neuen Komponenten in Reihe geschaltet, sodass die anliegende Spannung des Arduino-Boards zwischen den Komponenten aufgeteilt wird.
Das eine Ende des Fotowiderstands wird mit +5 V (VCC) verbunden, das andere Ende mit dem analogen Pin A0 des Arduino.
Der 1K Ohm Widerstand, welcher jetzt bereits auch mit einem Ende an +5 V angeschlossen ist, wird jetzt noch über das andere Ende mit GND / GROUND verbunden, sodass der Stromkreis geschlossen wird.
Erstellung des Arduino-Programmcodes
Genutzt wird die bereits in HowTo Teil 2 erstellte Programmlogik, welche nun erweitert wird.
Der komplette Sketch kann nachfolgend auch direkt als Arduino-Datei heruntergeladen werden: sketch_udp_helligkeitssensor.ino (52 Downloads)
Teil 1 - Grundeinstellungen und Variablendeklaration
Mit dem Befehl "int Helligkeitssensor = 0;" wird der gerade installierte Fotowiderstand definiert. Weiterhin werden einige weitere Variablen deklariert, die für die spätere Auswertung der Messwerte des Fotowiderstands notwendig sind.
Sie werden als eine Art Puffer genutzt, sodass nicht sofort bei geringen Helligkeitsänderungen ein UDP-Befehl in Richtung Smart-Home-Server abgesetzt wird, sondern erst dann, wenn sich die Messwerte seit der letzten Übertragung um "int HelligkeitssensorSchwellwert = 5;" ändern.
Mit "char msg[25];" wird noch eine weitere Variable vom Typ Charakter festgelegt, welche für die UDP-Übertragung der analogen Messwerte als Zeichenkette benötigt wird.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
// PIN Settings
#define Bewegungsmelder 2
// Variable Declaration
char BewegungsmelderState = 0;
int Helligkeitssensor = 0;
int HelligkeitssensordIdle = 100;
int HelligkeitssensorCounter = 0;
int HelligkeitssensorSchwellwert = 5;
int HelligkeitssensorObergrenze = 0;
int HelligkeitssensorUntergrenze = 0;
char msg[25];
// Network Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 3, 19);
IPAddress gateway(192, 168, 3, 1);
IPAddress subnet(255, 255, 255, 0);
// Local UDP port to listen on
unsigned int localPort = 7002;
// Recipient IP
IPAddress RecipientIP(192, 168, 3, 11);
// Recipient UDP Port
unsigned int RecipientPort = 7001;
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
// An EthernetUDP instance to send and receive packets over UDP
EthernetUDP Udp;
|
Teil 2 - Setup
Der Setup-Teil bleibt im Vergleich zum vorhergehenden Szenario unverändert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void setup()
{
// for debug only
Serial.begin(9600);
// start Ethernet
Ethernet.begin(mac,ip);
// Start UDP
Udp.begin(localPort);
// Bewegungsmelder
pinMode(Bewegungsmelder, INPUT);
// send UDP Ready
sendUDP("UDP Ready");
}
|
Teil 3 - Programmablauf (loop)
An dieser Stelle wird es richtig spannend. Zuerst wird bei jedem "loop"-Durchlauf der aktuelle Helligkeitswert mit "Helligkeitssensor=analogRead(A0);" ermittelt.
Währenddessen zählt ein Counter mit, welcher die Variable "HelligkeitssensorCounter" bei jedem Durchlauf um den Wert 1 erhöht, was später wichtig sein wird.
Als nächstes fragt eine if-Schleife ab, ob der gerade gemessene Wert "Helligkeitssensor" entweder größer oder gleich dem Wert "HelligkeitssensorObergrenze" oder kleiner gleich dem Wert "HelligkeitssensorUntergrenze" ist.
Damit wird verhindert, dass jede kleinste Helligkeitsänderung eine UDP-Nachricht auslöst. Über die Variable "HelligkeitssensorSchwellwert", welche am Anfang festgelegt wurde, kann dieser Schwellwert entsprechend eingestellt werden.
Sofern nun keine der Bedingungen zutrifft, passiert nichts weiter.
Sofern sich aber mindestens eine Bedingung bewahrheitet, kommt sofort die nächste if-Abfrage ins Spiel. Dabei wird geprüft, ob der Wert der Variable "HelligkeitssensorCounter" mindestens genauso groß ist wie der Wert der Variable "HelligkeitssensordIdle". Ist der initial festgelegte Wert von "HelligkeitssensordIdle" groß genug, kann so sichergestellt werden, dass nach dem Senden einer UDP-Mitteilung etwas Zeit vergeht, bevor eine neue Nachricht abgesendet werden kann.
Damit wird verhindert, dass der Empfänger zu viele kurz getaktete Nachrichten hintereinander erhält, sofern sich die Lichtverhältnisse in kürzester Zeit (z.B. Strobo-Licht) drastisch ändern.
Die eigentliche UDP-Nachricht wird dann über "sprintf(msg, "WZ.Helligkeitssensor: %d", Helligkeitssensor);" zusammengesetzt. Dieser "Umweg" ist notwendig, da die "sendUDP"-Funktion den eingelesenen Helligkeitswert direkt als String erwartet. Würde man die Variable "Helligkeitssensor" hingegen direkt in der Funktion selbst angeben, würde der korrekte Wert nicht übermittelt werden.
Zum Schluss werden die neuen Ober- und Untergrenzen ("HelligkeitssensorObergrenze" und "HelligkeitssensorUntergrenze") für den nächsten Durchlauf berechnet und der "HelligkeitssensorCounter" auf 0 zurückgesetzt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
void loop()
{
// Bewegungsmelder (Send)
if (digitalRead(Bewegungsmelder) == LOW && BewegungsmelderState != 0)
{
sendUDP("WZ.Bewegungsmelder: 0");
BewegungsmelderState = 0;
}
if (digitalRead(Bewegungsmelder) == HIGH && BewegungsmelderState != 1)
{
sendUDP("WZ.Bewegungsmelder: 1");
BewegungsmelderState = 1;
}
// Helligkeitssensor (Send)
Helligkeitssensor=analogRead(A0);
HelligkeitssensorCounter = HelligkeitssensorCounter + 1;
if (Helligkeitssensor >= HelligkeitssensorObergrenze || Helligkeitssensor <= HelligkeitssensorUntergrenze)
{
if (HelligkeitssensorCounter >= HelligkeitssensordIdle)
{
sprintf(msg, "WZ.Helligkeitssensor: %d", Helligkeitssensor);
Serial.println(msg);
sendUDP(msg);
HelligkeitssensorObergrenze = Helligkeitssensor + HelligkeitssensorSchwellwert;
HelligkeitssensorUntergrenze = Helligkeitssensor - HelligkeitssensorSchwellwert;
HelligkeitssensorCounter = 0;
}
}
delay(20);
}
|
Teil 4 - UDP-Sendefunktion
Die Sendefunktion für die UDP-Nachrichten bleibt im Vergleich zum vorangegangenen Szenario unverändert.
|
// Function to send UDP packets
void sendUDP(String text)
{
Udp.beginPacket(RecipientIP, RecipientPort);
// Udp.write("Test");
Udp.print(text);
Udp.endPacket();
}
|
Programmprüfung per "Seriellem Monitor"
Nach dem Flashen des Arduino-Boards bietet die Arduino-Software mit dem "Seriellen Monitor" ein praktisches Tool, um die Programmierung zu überprüfen.
Mit Klick auf "Werkzeuge" -> "Serieller Monitor" wird ein Fenster geöffnet, in welchem die vom Arduino an den PC übertragenen Daten angezeigt werden können.
Damit entsprechende Daten vom Arduino gesendet werden, muss eine Verbindung zum PC hergestellt (am einfachsten per USB-Kabel) und im Setup-Teil des Sketches die Anweisung "Serial.begin(9600);" enthalten sein.
Weiterhin müssen die gewünschten Informationen, bspw. die ermittelten Messwerte, über "Serial.println(msg);" im "loop"-Teil definiert werden und können dann per "Seriellem Monitor" bequem kontrolliert werden.
Einrichtung des Smart-Home-Servers
In der Loxone-Config lässt sich dann ein neuer "Virtueller UDP Eingang Befehl", in diesem Fall mit dem Namen "WZ.Helligkeitssensor" und der Befehlskennung "WZ.Helligkeitssensor: v", analog zum Beispiel im vorausgegangen Blogpost anlegen und zusammen mit dem Bewegungsmelder aus dem vorangegangen Szenario am virtuellen "Treppenlichtschalter" anschließen.
Er sperrt die Eingänge des Treppenlichtschalters solange er einen Wert kleiner 200 aufweist. Erst ab einem höheren Wert kann der Bewegungsmelder das Licht einschalten.
Prüfen von Widerständen
Noch kurz zum Thema Widerstände: Man liest recht häufig, dass gerade günstige Widerstände (Affiliate-Link) durch Produktionsungenauigkeiten teilweise Schwankungen aufweisen.
Obwohl das sicher nicht die Regel darstellt, wird an dieser Stelle empfohlen den angegebenen Ohm-Wert von Widerständen
(in diesem Fall ein 1K Ohm Widerstand) vorab mithilfe eines Digitalmultimeters (Affiliate-Link) B000VE5QPY zu überprüfen,
da man bei Widerständen mit zu geringen Ohm-Werten seine Komponenten durch Überspannung gefährdet.
Günstige Multimeter sind zwar auch nur beginnt genau, dennoch sollte das für den Privatanwender mehr als ausreichend sein.
Aus meinem täglichen Leben
Das oben beschriebene Setup habe ich jetzt auch erst seit Kurzem im Einsatz, da ich den Programmcode mehrfach abgeändert habe.
Grund war schlicht die Tatsache, dass ich weder zu viele unnötige, noch zu wenige Messwerte per UDP in Richtung Loxone Miniserver schicken wollte.
Die obige Logik muss sich zwar erst noch bewähren, ich denke aber, dass die Kombination aus "übermittle erst, wenn sich neue erst ein Stück weit von den alten Messwerten unterscheiden" und "übermittle erst, wenn etwas Zeit seit der letzten Übertragung vergangen ist" dauerhaft vernünftig funktionieren sollte. Wer einen besseren Vorschlag hat, gerne wie immer her damit per Kommentarfunktion.
Die ermittelten Messwerte sollten sich irgendwo bei 90 bei Dunkelheit und 800 bei Helligkeit einpendeln.
Diese Werte können, je nach eingesetzten Widerständen, jedoch auch abweichen.
Auf Basis der Messwerte habe ich jetzt meinen Loxone Miniserver entsprechend konfiguriert. Bei Bewegung wird erst dann die Beleuchtung eingeschaltet, sofern die Helligkeit unter den Wert 200 fällt.
Um auf obige Logik zurückzukommen. Grundlegend gibt es zwei Möglichkeiten um festzulegen, welche Parameter darüber entscheiden, unter welchen Voraussetzungen neue Messwerte (per UDP) übertragen werden. Gewöhnlich werden neue Messwerte einfach in regelmäßigen Abständen übertragen, auch wenn sich ein Wert nicht oder nur unwesentlich vom vorherigen Wert unterscheidet.
Die hier angewendete Vorgehensweise, nicht direkt bei jeder unwesentlichen Helligkeitsschwankung sofort einen UDP-Befehl zu übertragen, sondern erst dann, sobald sich der aktuelle Messwert um einen festgelegten Schwellwert seit der letzten Übertragung geändert hat, halte ich in diesem Fall für eine elegantere Lösung.
Auf diese Weise werden "unnötige" Nachrichten vermieden, die nichts anderes tun, als den bisherigen (identischen) und bereits übertragenen Wert auf Seiten des Smart-Home-Servers zu bestätigen.
Auf der anderen Seite können bei höheren, schnell aufeinanderfolgenden Messwertänderungen, die den vorgegebenen Schwellwert überschreiten, schnell getaktete UDP-Befehle hintereinander abgesetzt werden, was jedoch durch obige Logik dennoch gewollt begrenzt werden kann.
Auf diese Weise ist die Smart-Home-Zentrale immer auf dem Laufenden und kann verzögerungsfrei reagieren und bspw. sofort das Zimmerlicht einschalten, sobald die Rollos herunterfahren und den Raum verdunkeln.
Weiter geht es in der Blogserie mit
HowTo Teil 4: Status-LED per UDP ansteuern.
In den ersten drei Artikeln der Serie Arduino im Smart Home wurden nach einer kurzen Einführung in die Thematik sowohl digitale als auch analoge Messwerte über einen Arduino Uno erfasst und per UDP-Protokoll mithilfe eines Ethernet Shield an die netzwerkseitig angebundene Smart-Home-Zentrale Loxone gesendet. Daneben lassen sich über das Arduino-Board aber nicht nur Sensorwerte erfassen, sondern auch Aktoren steuern, wobei hierfür mehrere Möglichkeiten zur Verfügung stehen.
Zu diesem Zweck sendet die Smart-Home-Zentrale Loxone (oder FHEM) eine UDP-Nachricht an den Arduino, welcher eine dort angeschlossene LED-Diode ansteuert.
Umgesetzt wird das Ganze über eine LED-Leuchtdiode, welche den aktuellen Verbindungsstatus der angebundenen Smart-Home-Zentrale signalisiert.
Eine leuchtende LED gibt so schnell Auskunft darüber, dass eine funktionstüchtige Netzwerkverbindung zwischen Arduino und Zentrale hergestellt ist.
Wie das im Detail funktioniert und welcher entscheidende Zusatznutzen in Kombination mit der Arduino-Programmlogik entsteht, wird in nachfolgendem Artikel erläutert.
Signal-LED per Arduino schalten
Zur Anzeige des aktuellen Onlinestatus der Smart-Home-Zentrale wird eine grüne LED-Leuchtdiode an Pin 4 des Arduino angeschlossen, welcher nicht nur als digitaler Eingang, sondern wie in diesem Anwendungsfall, auch als digitaler Ausgang genutzt werden kann.
Da die hier verwendete grüne LED-Leuchtiode nativ für eine Spannung von 3,7 V ausgelegt ist, der Arduino jedoch eine Versorgungsspannung von 5 V aufweist, wird die LED in Reihe mit einem 100 Ohm Widerstand geschaltet, um ein Durchbrennen zu vermeiden.
Der Widerstand ist so berechnet, dass er die überschüssige Spannung schluckt und diese in Wärme umwandelt, wodurch die LED nur noch die benötigte Betriebsspannung erhält.
Wer eine andersfarbige LED (weiß, gelb, blau) aus einem Funduino Lernset (Affiliate-Link) verwenden möchte, kann ebenfalls einen 100 Ohm Widerstand als Spannungsteiler nutzen, im Fall der roten LED muss jedoch ein 200 Ohm Widerstand eingesetzt werden, da die rote LED für 2,1 V konzipiert wurde.
LED-gestützter Onlineverbindungsstatus
Damit der Onlineverbindungsstatus zuverlässig ermittelt werden kann, nutzt das nachfolgende Szenario zwei zusammenspielende Sende- und Empfangsbenachrichtigungen.
Der Arduino sendet in regelmäßigen Abständen per UDP-Nachricht ein Lebenszeichen in Form von "Ping" an den Smart-Home-Server. Sobald der Smart-Home-Server (in diesem Beispiel Loxone) die Nachricht empfängt, sendet er zwei direkt aufeinanderfolgende"Pong"-Rückantworten mit dem Inhalt "000" und "001" an den Arduino zurück.
Sobald diese Nachrichten dort eingeht, wird die grüne LED geschaltet. Empfängt der Arduino in einem festgelegten Zeitraum keine Rückantwort (Timeout), wird die LED ausgeschaltet. Mehr Details dazu dann direkt in der Erläuterung zum Arduino-Programm.
Benötigte Komponenten
Für die Ansteuerung einer Signal-LED zur Anzeige des Onlineverbindungsstatus der angebundenen Smart-Home-Zentral werden einige Komponenten benötigt, welche (wie beim vorangegangen Szenario auch) für unter 30 Euro erhältlich sind:
Wer die vorangegangenen Szenarien (HowTo Teil 2 und HowTo Teil 3) als Ausgangspunkt nutzt, benötigt für das folgende Setup lediglich die beiden letztgenannten Komponenten aus obiger Liste, die mit weniger als einem Euro zu Buche schlagen und bspw. bereits im Lernset Funduino UNO 8 (Affiliate-Link) enthalten sind.
Vorbereitung der Hardware
Das bereits für die vorherigen Szenarien eingesetzte Breadboard wird mit einer grünen LED-Leuchtdiode und einem 100 Ohm Widerstand erweitert, welche in Reihe geschaltet werden.
Da der elektrische Strom nur in einer Richtung durch die LED fließt, muss auf die korrekte Polarisation geachtet werden.
Der längere Kontakt der LED-Leuchtdiode (in der Zeichnung mit dem abgeknickten rechten Beinchen symbolisiert) wird gewöhnlich an VCC (+5 V) (in diesem Fall am Pin 4 des Arduino-Boards) und der kürzere Kontakt über den benachbarten Widerstand an GND (Ground) angeschlossen.
Die Installation füllt sich dabei weiter mit Leben, wobei das Ganze durch den Einsatz des Breadboards dennoch überraschend übersichtlich bleibt.
Wie man unschwer erkennen kann, ist sogar noch genügend Platz auf dem Breadboard für spätere Erweiterungen.
Langsam wird es aber dennoch Zeit für einen neuen Satz Drahtbrücken (Affiliate-Link), damit es künftig keine Engpässe bei der prototypischen Verkabelung gibt.
Erstellung des Arduino-Programmcodes
Genutzt wird die bereits in
HowTo Teil 3 erstellte Programmlogik, welche teilweise etwas verbessert wurde und nun erweitert wird.
Der komplette Sketch kann nachfolgend auch direkt als Arduino-Datei heruntergeladen werden:
sketch_onlinestatus_led.ino (62 Downloads)
Teil 1 - Grundeinstellungen und Variablendeklaration
Da eine schnelle Response-Zeit z.B. beim Bewegungsmelder oder einem Tastendruck erzielt werden soll, ist es notwendig, dass der Arduino-Programmcode mehrmals pro Sekunde durchlaufen wird.
Damit man die Timings für verschiedene Intervallabfragen adäquat umsetzen kann, wird die Variable "Programmfrequenz" eingeführt, die mit einem Wert von 50 (Hz) für den Anwendungsfall passend erscheint.
Die angegebene Variable wirkt sich dabei maßgeblich auf das am Ende des loop-Teils angegebene Delay "delay(1000/Programmfrequenz);" aus, wodurch dem Arduino pro Programmdurchlauf eine Zwangspause von 20 ms (1000/50) auferlegt wird, was in der Konsequenz einer Programmfrequenz von 50 Hz entspricht.
Über die Variable "OnlinestatusCheckEachSekOnline" wird angegeben, in welchem zeitlichen Abstand ein "Ping"-Impuls vom Arduino versendet wird. Testweise ist dieser Wert auf 10 Sekunden gesetzt, künftig soll er den Wert 60 tragen, so dass der Onlinestatus jede Minute abgefragt werden kann.
Dieser Wert wird dabei situationsbedingt nur dann verwendet, sofern der vorausgegangene Onlinecheck erfolgreich war und eine Rückantwort eingegangen ist.
War der letzte Check negativ (keine Rückantwort vom Empfänger), wird stattdessen der Wert der Variablen "OnlinestatusCheckEachSekOffline" verwendet. Der Hintergrund ist, dass der Arduino nach einer Verbindungstrennung in kürzeren Intervallen ein "Ping"-Signal aussenden soll, damit der Status schneller korrigiert wird, sobald die Verbindung wieder steht. Vermutlich kann dieser Wert auch langfristig mit 2 (Sekunden) besetzt werden.
Die Variable "OnlinestatusCheckTimeoutSek" gibt an, wieviele Sekunden vom Aussenden der "Ping"-Nachricht bis zur "Pong"-Antwort der Zentrale maximal vergehen dürfen, bis der Status von "Online" auf "Offline" wechselt.
Mit den hier angegebenen Werten kam es bei ersten Tests zwischen Arduino und Loxone im Schnitt über mehrere Stunden hinweg zu keinen Paketverlusten, was für die Testumgebung ein gutes Setting darstellt. Im späteren Dauerbetrieb sollte der Wert auf mehrere Sekunden erhöht werden, um einen größeren Puffer einzubauen.
Danach folgen weitere Variablen, die unter anderem auch zur Berechnung bzw. Umrechnung der in Sekunden angegebenen Parameterwerte in die Laufzeitumgebung des Arduino genutzt werden.
So wird aus dem in Sekunden angegebenen Wert "OnlinestatusCheckEachSekOnline" (10) durch die Multiplizierung mit der angegebenen "Programmfrequenz" (50) die im weiteren Programmcode verwendete Variable "OnlinestatusCheckOnline" (10 x 50 = 500) gebildet, sodass durch die noch folgende Logik im loop-Teil nur bei jedem 500. Programmdurchlauf (also alle 10 Sekunden) ein Ping-Signal ausgesendet wird.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
// PIN Settings
#define Bewegungsmelder 2
#define OnlinestatusLED 4
// Variable Declaration
int Programmfrequenz = 50; // loop-Durchlauf pro Sekunde (ca.)
int HelligkeitssensordIdleSek = 2; // Minimale Pause zwischen zwei Helligkeitbenachrichtigungen in Sek
int HelligkeitssensorSchwellwert = 10; // Schwellwert fuer Helligkeitsbenachrichtigungen (empfohlen 5-20)
int OnlinestatusCheckEachSekOnline = 10; // Ping in Sek wenn letzter Status Online war
int OnlinestatusCheckEachSekOffline = 2; // Ping in Sek wenn letzter Status Offline war
int OnlinestatusCheckTimeoutSek = 1; // Status auf Offline setzen wenn Rueckmeldung nicht innerhalb x Sek
char BewegungsmelderState = 0;
int Helligkeitssensor = 0;
int HelligkeitssensorCounter = 0;
int HelligkeitssensorObergrenze = 0;
int HelligkeitssensorUntergrenze = 0;
char msg[25];
int HelligkeitssensordIdle = HelligkeitssensordIdleSek * Programmfrequenz;
int OnlinestatusSendCounter = 0;
int OnlinestatusReceiveCounter = 0;
char OnlinestatusLoxone = 0;
int OnlinestatusCheckOnline = OnlinestatusCheckEachSekOnline * Programmfrequenz;
int OnlinestatusCheckOffline = OnlinestatusCheckEachSekOffline * Programmfrequenz;
int OnlinestatusCheckTimeout = (OnlinestatusCheckTimeoutSek + OnlinestatusCheckEachSekOnline) * Programmfrequenz;
// Network Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 3, 19);
IPAddress gateway(192, 168, 3, 1);
IPAddress subnet(255, 255, 255, 0);
// Local UDP port to listen on
unsigned int localPort = 7002;
// Recipient IP
IPAddress RecipientIP(192, 168, 3, 11);
// Recipient UDP Port
unsigned int RecipientPort = 7001;
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
// An EthernetUDP instance to send and receive packets over UDP
EthernetUDP Udp;
|
Teil 2 - Setup
Im Setup-Teil wird im Vergleich zum vorhergehenden Szenario lediglich die neu verwendete grüne Status-LED an Pin 4 als "pinMode" mit dem Attribut "OUTPUT" definiert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
void setup()
{
// for debug only
Serial.begin(9600);
// start Ethernet
Ethernet.begin(mac,ip);
// Start UDP
Udp.begin(localPort);
// Bewegungsmelder
pinMode(Bewegungsmelder, INPUT);
//OnlinestatusLED
pinMode(OnlinestatusLED, OUTPUT); // LED an Pin4
// send UDP Ready
sendUDP("UDP Ready");
}
|
Teil 3 - Programmablauf (loop)
Der nun recht umfangreiche loop-Teil kümmert sich nun um das Aussenden und Empfangen der UDP-Mitteilungen sowie deren Auswertung.
Zuerst werden zwei if-Bedingungen für das situationsbezogene zeitliche Versenden der "Ping"-Nachricht definiert.
Die erste if-Abfrage wird getriggert, sobald der in jedem loop-Durchlauf um den Wert 1 erhöhte Zähler "OnlinestatusSendCounter" mit dem oben durch den Nutzer festgelegten "OnlinestatusCheckOnline" übereinstimmt und weiterhin der Wert von "OnlinestatusReceiveCounter", welcher die Zeit seit dem letzten Versenden der Ping-Nachricht berechnet, nicht mit dem vom Nutzer angegebenen bzw. berechneten Wert von "OnlinestatusCheckTimeout" übereinstimmt.
Die zweite Abfrage ist für den Fall gedacht, dass die letzte Ping-Anfrage im Nirvana gelandet ist. In diesem Fall ist der Unterscheid zur vorherigen if-Abfrage, dass nun "OnlinestatusReceiveCounter" und "OnlinestatusCheckTimeout" übereinstimmen.
Sobald eine der if-Bedignungen erfüllt ist, wird der "Ping" ausgesendet und der Durchzählwert von "OnlinestatusSendCounter" resettet.
Nachdem die Ping-Nachricht beim Empfänger eintrifft, werden zwei kurz hintereinander getaktete "Pong"-Rückmeldungen von der Smart-Home-Zentrale mit den Werten "000" und "001" in Richtung Arduino zurückgesendet (Details dazu weiter unten im Programmcode).
Beim Eintreffen der ersten Nachricht (000) wird der Wert von "OnlinestatusReceiveCounter" auf 0 zurückgesetzt und bei der zweiten Nachricht (000) der Statuswert "OnlinestatusLoxone" auf 1 gesetzt.
Weiterhin wird die installierte grüne LED an Pin 4 mit der Anweisung "digitalWrite(OnlinestatusLED, HIGH);" mit Strom versorgt.
Dieser "Umweg" mit zwei Nachrichten erschien notwendig, da der UDP-Empfangspuffer des Arduino nur einmal kurz die Variable "OnlineStatusReceiveCounter" resetten soll.
Würde der Empfangspuffer, der durch die erste Nachricht mit "000" gefüllt ist, direkt im Anschluss nicht mit dem Wert "001" überschrieben werden, würde bei jedem neuen Programmdurchlauf weiterhin "000" im Puffer stehenbleiben, so dass immer wieder der Variablenwert von "OnlineStatusReceiveCounter" zurückgesetzt werden würde und dieser nicht mehr hochzählen könnte, sofern nicht zufällig eine anderslautende eingehende UDP-Nachricht den UDP-Puffer überschreibt. Vermutlich lässt sich dieser eher unsaubere Workaround auch viel eleganter lösen, jedoch mangelt es mir derzeitig an dem dafür notwendigen Hintergrundwissen.
Mit "if (OnlinestatusReceiveCounter < OnlinestatusCheckTimeout)" wird weiterhin geprüft, ob der Zähler "OnlinestatusreceiverCounter" kleiner ist als der hinterlegte Timeout durch "OnlinestatusCheckTimeout". Sofern das der Fall ist, wird der Wert von "OnlinestatusReceiverCounter" um 1 erhöht.
Dadurch wird erreicht, dass das Hochzählen automatisch gestoppt wird, sobald der Timeout stattfindet.
Sobald der Timeout einmal erreicht ist (letzte if-Abfrage des Loops), wird der Status von "OnlinestatusLoxone" auf 0 gesetzt und die LED mit dem Befehl "digitalWrite(OnlinestatusLED, LOW);" ausgeschaltet.
Wer das Ganze nicht sofort durchblickt, knappt sich am besten eine Tasse Kaffee und spielt die einzelnen Punkte des Loops noch einmal gedanklich durch.
Es hat auch einige Zeit gedauert und Nerven gekostet, bis dieser Lösungsweg in der vorliegenden Form zuverlässig lief. Wer Verbesserungen zum Code einbringen möchte, kann gerne die Kommentarfunktion nutzen. Ich bin mit C und UDP-Empfangspuffern nicht wirklich fit, vermutlich lässt sich das Ganze noch viel eleganter umsetzen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
void loop()
{
checkUDP();
// Bewegungsmelder (Send)
if (digitalRead(Bewegungsmelder) == LOW && BewegungsmelderState != 0)
{
sendUDP("WZ.Bewegungsmelder: 0");
BewegungsmelderState = 0;
}
if (digitalRead(Bewegungsmelder) == HIGH && BewegungsmelderState != 1)
{
sendUDP("WZ.Bewegungsmelder: 1");
BewegungsmelderState = 1;
}
// Helligkeitssensor (Send)
Helligkeitssensor=analogRead(A0);
HelligkeitssensorCounter = HelligkeitssensorCounter + 1;
if (Helligkeitssensor >= HelligkeitssensorObergrenze || Helligkeitssensor <= HelligkeitssensorUntergrenze)
{
if (HelligkeitssensorCounter >= HelligkeitssensordIdle)
{
sprintf(msg, "WZ.Helligkeitssensor: %d", Helligkeitssensor);
Serial.println(msg);
sendUDP(msg);
HelligkeitssensorObergrenze = Helligkeitssensor + HelligkeitssensorSchwellwert;
HelligkeitssensorUntergrenze = Helligkeitssensor - HelligkeitssensorSchwellwert;
HelligkeitssensorCounter = 0;
}
}
// Onlinestatus-Ping (Send)
OnlinestatusSendCounter = OnlinestatusSendCounter + 1;
if (OnlinestatusSendCounter == OnlinestatusCheckOnline && OnlinestatusReceiveCounter != OnlinestatusCheckTimeout)
{
Serial.println("SendUDP: Ping");
sendUDP("Ping");
OnlinestatusSendCounter = 0;
}
if (OnlinestatusSendCounter == OnlinestatusCheckOffline && OnlinestatusReceiveCounter == OnlinestatusCheckTimeout)
{
Serial.println("SendUDP: Ping");
sendUDP("Ping");
OnlinestatusSendCounter = 0;
}
// Onlinestatus-Pong (Receive)
if (!strcmp(packetBuffer, "000"))
{
OnlinestatusReceiveCounter = 0;
}
if (!strcmp(packetBuffer, "001"))
{
OnlinestatusLoxone = 1;
digitalWrite(OnlinestatusLED, HIGH);
}
if (OnlinestatusReceiveCounter < OnlinestatusCheckTimeout)
{
OnlinestatusReceiveCounter = OnlinestatusReceiveCounter + 1;
}
if (OnlinestatusReceiveCounter == OnlinestatusCheckTimeout)
{
OnlinestatusLoxone = 0;
digitalWrite(OnlinestatusLED, LOW);
}
delay(1000/Programmfrequenz);
}
|
Teil 4 - UDP-Sendefunktion
Die Sendefunktion für die UDP-Nachrichten bleibt im Vergleich zum vorangegangenen Szenario unverändert.
|
// Function to send UDP packets
void sendUDP(String text)
{
Udp.beginPacket(RecipientIP, RecipientPort);
// Udp.write("Test");
Udp.print(text);
Udp.endPacket();
}
|
Teil 5 - UDP-Empfangsfunktion
Die Empfangsfunktion für die UDP-Nachrichten ist der Gegenpart zur der soeben in Teil 4 angesprochenen Sendefunktion und wird abschließend deklariert.
Wer möchte, kann den auskommentierten Teil am Ende der Funktion für Testzwecke aktivieren, damit beim Empfang einer neuen eingehenden UDP-Nachricht der Wert "ACK" an den Sender zurückübermittelt wird.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// Function to check for new incoming UDP packets
void checkUDP()
{
// if there's data available, read a packet
int packetSize = Udp.parsePacket();
if(packetSize)
{
// read the packet into packetBufffer
Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
// For debug only
// Write packetBuffer to serial
Serial.print("ReceiveUDP: ");
Serial.println(packetBuffer);
// send "ACK" as reply
//Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
//Udp.write("ACK");
//Udp.endPacket();
}
}
|
Einrichtung des Smart-Home-Servers
In der Loxone-Config werden nun ebenfalls zwei Komponenten benötigt. Zum einen der "Virtueller UDP Eingang Befehl", welcher die Nachricht des Arduino mit dem Wert "Ping" entgegennimmt und zum anderen der "Virtuellen Ausgang Befehl", welcher die beiden Nachrichten "000" und "001" in Richtung Arduino zurücksendet.
In Eingangsrichtung wird der bereits im HowTo Teil 2 eingeführte "Virtuelle Eingang" namens "WZ.Arduino" mit dem Empfangsport "7001" genutzt. Ihm untergliedert wird nun der "Virtuelle Eingang Befehl" namens "Ping", welcher mit der Option "Als Digitaleingang verwenden" angelegt wird. Die "Befehlserkennung" lautet dabei schlicht "Ping".
Der Gegenpart ist der "Virtueller Ausgang" mit der "Adresse" "/dev/udp/192.168.3.19/7002". Hier werden die zugewiesene IP des Arduino "192.168.3.19" und dessen UDP-Port "7002" angegeben, damit die Pakete auch zum Empfänger gelangen.
Ihm unterstellt wird der "Virtuelle Ausgang Befehl" namens "Pong", der im Falle von "Befehl bei Ein" den Wert "000" und im Falle von "Befehl bei Aus" den Wert "001" kurz nacheinender zurück an den Arduino überträgt.
Da der UDP-Empfangspuffer des Arduino eher rudimentärer Natur ist, sollte er grundsätzlich nur mit Stringwerten gefüttert werden, die alle die selbe Länge (in diesem Fall die Länge von 3 Zeichen) aufweisen.
Anfangs hatte ich bspw. abwechselnd "Pong" und "Reset" zurückgesendet. Sobald jedoch der neu eintreffende Wert "Pong" den bereits im UDP-Empfangspuffer stehenden Wert "Reset" überschreiben sollte, stand plötzlich "Pongt" im Puffer, da sich die Strings in der Länge unterscheiden und anscheinend ein kurzer String einen bereits im Puffer befindlichen längeren String nicht komplett überschreibt. Eine wichtige Erkenntnis, die auf jeden Fall berücksichtigt werden muss, um nicht in unnötige Probleme zu laufen.
Ein zusätzlicher virtueller "Treppenlichtschalter", welcher am "Ping"-Signal angeschlossen ist, gibt auf Seiten von Loxone schließlich noch Aufschluss über den aktuellen "Onlinestatus" des Arduino.
Ein Treppenlichtschalter bietet sich dabei gerade für Tests an, da durch seinen "Sanduhreffekt" sehr schnell deutlich wird, wann der letzte "Ping" erfolgt ist und wie lange es noch bis zum potenziellen Timeout dauert.
Die Ausschaltzeit wurde dabei testweise auf 11 Sekunden (nur eine Sekunde höher als die Standard-Ping-Zeit des Arduino) gesetzt. Dieser sollte jedoch künftig hochgesetzt werden, um das Timeout sinnvollerweise zu erhöhen.
Aus meinem täglichen Leben
Ursprünglich wollte ich nur kurz beschreiben, wie eine UDP-Nachricht an den Arduino gesendet und eine einfache LED mithilfe des Befehls "digitalWrite(OnlinestatusLED, HIGH);" geschaltet werden kann.
Da ich jedoch schon von Anfang an eine zuverlässige Möglichkeit gesucht habe, um schnell prüfen zu können, ob aktuell ein Datenaustausch zwischen Arduino und Smart-Home-Zentrale möglich ist, habe ich kurzerhand obiges Szenario umgesetzt. Nichtsahnend, dass die Umsetzung doch etwas länger dauert und mehr logische Abfragen benötigt, als ursprünglich erwartet. Gerade der UDP-Empfangspuffer hat mir dabei etwas Kummer bereitet.
Bis auf diese Tatsache, dass aktuell eine "doppelte Rückmeldung" vom Arduino erwartet wird, finde ich das Gesamtkonzept jedoch schon recht rund.
Zukünftig lässt sich der Onlinestatus auch noch für viel spannendere Dinge nutzen als "nur" den aktuellen Verbindungsstatus per LED zu kontrollieren.
Dadurch, dass künftig bspw. auch Verbraucher über Relais am Arduino per Smart-Home-Zentrale geschaltet werden sollen (HowTo folgt im nächsten Blogpost), lässt sich der Onlinestatus gerade auch für situationsbedingte Schaltvorgänge in Abhängigkeit der Netzwerkverfügbarkeit nutzen.
Besteht eine Verbindung zwischen Arduino und Smart-Home-Server (Loxone oder FHEM), leitet ein am Arduino angeschlossener Taster den Tastendruck regulär an Loxone weiter.
Dort wird der Befehl ausgewertet und der am Arduino betriebene Aktor (z.B. Beleuchtung) erst dann geschaltet, sofern es die Zentral zulässt (z.B. bei geringer Helligkeit).
Besteht jedoch gerade keine Verbindung zur Zentrale, kann der Tastendruck des Arduino per Fallback über die Programmregel "wenn Onlinestatus = 0" den Aktor direkt schalten.
Dadurch wird die aus meiner Sicht derzeit noch größte Schwachstelle vieler zentraler Lösungen auf smarte Weise umgangen , die auf dem Konzept einer Smart-Home-Zentrale basieren (dazu gehört gerade auch Loxone).
Ein an der Smart-Home-Zentrale angebundener Arduino, welcher als ein solches "Gateway" eingesetzt wird, kann auf diese Weise mit einer Grundintelligenz ausgestattet werden, die trotz temporärer Nichtverfügbarkeit der Zentrale zumindest rudimentäre Aktionen (Licht an, Rollos hoch) umsetzen kann.
Ein spannendes Zusatzfeature, welches ich bisher noch gar nicht auf dem Schirm hatte und das aus meiner Sicht einen wertvollen Zusatznutzen generiert, auch wenn die Infrastruktur so konzipiert ist, dass die Zentrale dauerhaft erreichbar ist.
Manchmal ist sie es, egal ob gewollt (Neustart, Update) oder nicht (Fehlkonfiguration, Absturz, Stromausfall, Austausch) doch einmal nicht.
Was hältst du von dieser durch den Arduino ermöglichten Fallback-Lösung? Stimme einfach ab und hinterlasse einen Kommentar.
Nachdem im vorangegangenen HowTo Teil 4 der Blogserie Arduino im Smart Home eine Status-LED über den Arduino angesteuert wurde, folgt nun im direkten Anschluss die netzwerkseitige Anbindung eines weiteren digitalen Aktors.
Durch den Einsatz von günstigen Schaltrelais lassen sich dabei auch leistungshungrige Verbraucher, wie bspw. LED-Lampen, ein- und ausschalten, die sich aufgrund höherer Spannungen und Stromstärken nicht direkt an den Pins des Arduino betreiben lassen.
Welche Komponenten dazu notwendig sind und wie der Aufbau im Fall eines 24 V LED-Spot aussieht, ist Inhalt des nachfolgenden Artikels.
Relaisschaltung per Arduino
In diesem Beispiel wird das Relaismodul aus dem Funduino Set 8 (Affiliate-Link) verwendet, mit dem ein Verbraucher mit bis zu 10 A geschaltet werden kann.
Das deutsche Stromnetz aus der "Steckdose" liefert eine Wechselspannung von knapp 220 V, was bedeutet, dass theoretisch Verbraucher bis zu 2.200 W (220 V x 10 A) über das Relais betrieben werden können. Weiterhin sind auch andere (Mehrfach-)Relaismodule erhältlich, die je nach Modell bis zu acht Verbraucher (Affiliate-Link) gleichzeitig ansteuern können und umgerechnet oft weniger als ein Euro pro Kanal kosten.
Mittlerweile sind zudem noch größere Schaltrelais-Module mit 16 Kanälen (Affiliate-Link) verfügbar.
Bevor es an die Installation von Verbrauchern an den Relais geht, sollte man sich jedoch im Vorfeld intensiv mit dem Thema Elektrizität auseinandersetzen, da es gefährlich werden kann, sobald man unbedarft an die Sache herangeht.
Hinweis zum Umgang mit elektrischen Strömen
Bei Arbeiten an Elektroinstallationen, die vorgegebene Grenzwerte für Kleinspannung von 50 V AC (Wechselspannung) bzw. 120 V DC (Gleichspannung) überschreiten, besteht Lebensgefahr! Sofern auf einen Schutz gegen Berühren (Isolation) verzichtet wird, dürfen weiterhin die Grenzwerte von 25 V AC (Wechselspannung) bzw. 60 V DC (Gleichspannung) nicht überschritten werden.
Arbeiten oberhalb der Grenzen von 25 V AC (Wechselspannung) bzw. 60 V DC (Gleichspannung) sollen und dürfen deshalb nur von ausgebildetem Fachpersonal ausgeführt werden.
Wer höhere externe Spannungen als die vom Arduino-Board bereitgestellten 9 V DC (Gleichspannung) nutzen möchte, muss sich deshalb im Vorfeld genau über die Grenzwerte im Klaren sein, da sonst Lebensgefahr bestehen kann.
Weiterhin sollten die Pins des Arduino auf keinen Fall direkt (ohne Einsatz von passenden Relais) mit externen Stromquellen verbunden werden, die 9 V DC (Gleichspannung) überschreiten.
Der Arduino scheint zwar bis 24 V DC (Gleichspannung) in gewissem Maße "abgesichert" zu sein, ein Dauerbetrieb solcher Spannungen ist jedoch nicht vorgesehen und schädigt die Hardware dauerhaft. AC (Wechselspannung) darf nicht direkt am Arduino betrieben werden, da er dafür nicht ausgelegt ist.
Oben genannte Grenzwerte haben ihre Berechtigung, an die sich jeder unbedingt halten sollte. Also Finger weg vom Strom direkt aus der "Steckdose", welche gewöhnlich 220 V AC (Wechselspannung) liefert.
24 V LED-Spot am Schaltrelais installieren
Aus oben genannten Gründen wird an dieser Stelle auf die Ansteuerung von Verbrauchern mit 220 V AC (Wechselspannung) verzichtet
und stattdessen die Anbindung eines 10 W LED-Spot von revoart mit der laut obigen Grenzwerten vertretbaren Spannung von 24 Volt DC (Gleichspannung) verdeutlicht.
Das Relais übernimmt dabei die Aufgabe, die vom Arduino anliegende Steuerspannung in Höhe von 5 V nutzbar zu machen, um einen abhängigen Laststromkreis zu schalten, über den eine höhere Verbrauchsspannung fließen kann, welche für den Betrieb des LED-Spots verwendet werden kann.
Das Prinzip basiert dabei auf der galvanische Trennung, sodass beide elektrischen Ströme voneinander getrennt sind.
Wer mehr Details nachlesen möchte, kann das Funktionsprinzip mechanischer Relais auf Wikipedia genauer studieren.
Der LED-Spot bezieht seine Betriebsspannung von 24 V DC (Gleichstrom) über eine separate Stromquelle, einem Mean Well Schienennetzteil mit max. 10 A (Affiliate-Link),
welches für den gleichzeitigen Betrieb mehrerer Verbraucher bis zu 240 W Gesamtleistung verwendet werden kann (bis zu 24 der hier verwendeten 10 W LED-Spots).
Der Minuspol "-V" des Netzteils wird über eine Lüsterklemme direkt mit dem entsprechenden Anschluss der LED-Lampe verbunden.
Der Pluspol "+V" des Netzteils wird über das Schaltrelais mit der LED-Lampe verbunden, sodass dieses den Stromfluss je nach Anwenderwunsch herstellen bzw. trennen kann.
Die Zuleitung vom Netzteil "+V" wird mit der mittleren Schraubklemme (Anschluss A) des Schaltrelais verbunden.
Erfolgt die "Weiterleitung" zur LED-Lampe über die rechts davon angebrachte Schraubklemme (Anschluss B), schließt der Kontakt, solange vom Arduino keine Steuerspannung anliegt (Öffner/Ruhekontakt/Normally Closed).
Wird die weiterführende Leitung zur LED-Lampe hingegen nicht mit der rechten, sondern mit der linken Schraubklemme (Anschluss C) verbunden, kehrt sich die Logik um.
Wenn eine Steuerspannung vom Arduino angelegt wird, fließt Strom durch das Relais und die LED-Lampe leuchtet (Schließer/Arbeitskontakt/Normally Open).
Benötigte Komponenten
Für die Ansteuerung des LED-Spots werden einige Komponenten benötigt, welche (wie beim vorangegangen Szenario auch) für unter 30 Euro erhältlich sind:
Arduino Uno (Affiliate-Link)
Arduino Ethernet Shield (Affiliate-Link)
Steckbrücken (Affiliate-Link)
Breadboard (Affiliate-Link)
1-Kanal Schaltrelais (Affiliate-Link)
9 V Netzteil (Affiliate-Link)
Wer die vorangegangenen Szenarien als Ausgangspunkt nutzt, benötigt für das folgende Setup lediglich die beiden letztgenannten Komponenten obiger Liste, die mit knapp 10 Euro zu Buche schlagen.
Das Schaltrelais ist dabei bereits im Lernset
Funduino UNO 8 (Affiliate-Link) enthalten.
Das 9 V Netzteil, welches den Arduino mit Strom versorgt, ist jetzt zwingend notwendig, da das Schaltrelais bei "angezogenem" Kontakt mehr Strom konsumiert als durch die bisher genutzte Stromversorgung des Arduio über USB (5 V) geliefert wird.
Wird kein separates Netzeil verwendet, fällt die Spannung aufgrund des angeschlossenen Relais an den Pins des Arduino auf knapp 4 V ab, was sich auch auf andere Sensoren auswirkt.
Der Bewegungsmelder liefert dann bspw. fälschlicherweise ein "Motion"-Signal, obwohl keine Bewegung stattfindet.
Weiterhin wird noch ein Verbraucher und eine Stromquelle, wie im Fall des verwendeten 24 V LED-Spot, ein passenden Netzteil mit genügend Leistung benötigt.
Vorbereitung der Hardware
Das bereits für die vorherigen Szenarien eingesetzte Breadboard wird mit einigen Steckbrücken erweitert, um die Verbindung mit dem Schaltrelais herstellen zu können.
Neben +5 V (rot) und GND (schwarz), die über die beiden unteren Kontaktereihen des Breadboard weitergereicht werden, wird weiterhin Pin 5 des Arduino als Signalkabel (blau) für die Ansteuerung des Schaltrelais verwendet.
Erstellung des Arduino-Programmcodes
Genutzt wird die bereits in HowTo Teil 4 erstellte Programmlogik, welche teilweise wieder etwas angepasst wurde und nun erweitert wird.
Der komplette Sketch kann nachfolgend auch direkt als Arduino-Datei heruntergeladen werden: sketch_relais.ino (40 Downloads)
Teil 1 - Grundeinstellungen und Variablendeklaration
Die einzige Erweiterung, die in Teil 1 des Arduino-Programmcodes notwendig ist, definiert das Schaltrelais an Pin 5. Der restliche Code bleibt unverändert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
// PIN Settings
#define Bewegungsmelder 2
#define OnlinestatusLED 4
#define Schaltrelais 5
// Variable Declaration
int Programmfrequenz = 50; // loop-Durchlauf pro Sekunde (ca.)
int HelligkeitssensordIdleSek = 5; // Minimale Pause zwischen zwei Helligkeitbenachrichtigungen in Sek
int HelligkeitssensorSchwellwert = 1; // Schwellwert fuer Helligkeitsbenachrichtigungen (empfohlen 5-20)
int OnlinestatusCheckEachSekOnline = 30; // Ping in Sek wenn letzter Status Online war
int OnlinestatusCheckEachSekOffline = 5; // Ping in Sek wenn letzter Status Offline war
int OnlinestatusCheckTimeoutSek = 3; // Status auf Offline setzen wenn Rueckmeldung nicht innerhalb x Sek
char BewegungsmelderState = 0;
int Helligkeitssensor = 0;
int HelligkeitssensorCounter = 0;
int HelligkeitssensorObergrenze = 0;
int HelligkeitssensorUntergrenze = 0;
char msg[25];
int HelligkeitssensordIdle = HelligkeitssensordIdleSek * Programmfrequenz;
int OnlinestatusSendCounter = 0;
int OnlinestatusReceiveCounter = 0;
char OnlinestatusLoxone = 0;
int OnlinestatusCheckOnline = OnlinestatusCheckEachSekOnline * Programmfrequenz;
int OnlinestatusCheckOffline = OnlinestatusCheckEachSekOffline * Programmfrequenz;
int OnlinestatusCheckTimeout = (OnlinestatusCheckTimeoutSek + OnlinestatusCheckEachSekOnline) * Programmfrequenz;
// Network Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 3, 19);
IPAddress gateway(192, 168, 3, 1);
IPAddress subnet(255, 255, 255, 0);
// Local UDP port to listen on
unsigned int localPort = 7002;
// Recipient IP
IPAddress RecipientIP(192, 168, 3, 11);
// Recipient UDP Port
unsigned int RecipientPort = 7001;
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
// An EthernetUDP instance to send and receive packets over UDP
EthernetUDP Udp;
|
Teil 2 - Setup
Im Setup-Teil wird im Vergleich zum vorhergehenden Szenario lediglich das neu verwendete Schaltrelais an Pin 5 als "pinMode" mit dem Attribut "OUTPUT" definiert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
void setup()
{
// for debug only
Serial.begin(9600);
// start Ethernet
Ethernet.begin(mac,ip);
// Start UDP
Udp.begin(localPort);
// Bewegungsmelder
pinMode(Bewegungsmelder, INPUT);
//OnlinestatusLED
pinMode(OnlinestatusLED, OUTPUT); // LED an Pin4
//Schaltrelais
pinMode(Schaltrelais, OUTPUT); // Schaltrelais an Pin5
// send UDP Ready
sendUDP("UDP Ready");
}
|
Teil 3 - Programmablauf (loop)
Der loop-Teil kümmert sich nun um die Auswertung der eingehenden UDP-Mitteilungen "051" und "050".
Der Eingang der ersten Mitteilung wird über "if (!strcmp(packetBuffer, "051"))" abgefragt. Sofern der Wert "051" im UDP-Empfangspuffer aufzufinden ist, schaltet der Arduino über den Befehl "digitalWrite(Schaltrelais, HIGH);" das Schaltrelais ein.
Der umgekehrte Fall mit "050" und einem Ausschaltvorgang folgt im Code mit analogem Aufbau.
Weiterhin wurde noch mit der Anpassung von "Helligkeitssensor=(analogRead(A0)-100)/8;" bewirkt, dass der Helligkeitssensor einen verbesserten Wertebereich zwischen 0 und 100 (vorher 100 bis 800) für die Auswertung liefert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
void loop()
{
checkUDP();
// Bewegungsmelder (Send)
if (digitalRead(Bewegungsmelder) == LOW && BewegungsmelderState != 0)
{
sendUDP("WZ.Bewegungsmelder: 0");
BewegungsmelderState = 0;
}
if (digitalRead(Bewegungsmelder) == HIGH && BewegungsmelderState != 1)
{
sendUDP("WZ.Bewegungsmelder: 1");
BewegungsmelderState = 1;
}
// Helligkeitssensor (Send)
Helligkeitssensor=(analogRead(A0)-100)/8;
HelligkeitssensorCounter = HelligkeitssensorCounter + 1;
if (Helligkeitssensor >= HelligkeitssensorObergrenze || Helligkeitssensor <= HelligkeitssensorUntergrenze)
{
if (HelligkeitssensorCounter >= HelligkeitssensordIdle)
{
sprintf(msg, "WZ.Helligkeitssensor: %d", Helligkeitssensor);
Serial.println(msg);
sendUDP(msg);
HelligkeitssensorObergrenze = Helligkeitssensor + HelligkeitssensorSchwellwert;
HelligkeitssensorUntergrenze = Helligkeitssensor - HelligkeitssensorSchwellwert;
HelligkeitssensorCounter = 0;
}
}
// Onlinestatus-Ping (Send)
OnlinestatusSendCounter = OnlinestatusSendCounter + 1;
if (OnlinestatusSendCounter == OnlinestatusCheckOnline && OnlinestatusReceiveCounter != OnlinestatusCheckTimeout)
{
Serial.println("SendUDP: Ping");
sendUDP("Ping");
OnlinestatusSendCounter = 0;
}
if (OnlinestatusSendCounter == OnlinestatusCheckOffline && OnlinestatusReceiveCounter == OnlinestatusCheckTimeout)
{
Serial.println("SendUDP: Ping");
sendUDP("Ping");
OnlinestatusSendCounter = 0;
}
// Onlinestatus-Pong (Receive)
if (!strcmp(packetBuffer, "000"))
{
OnlinestatusReceiveCounter = 0;
}
if (!strcmp(packetBuffer, "001"))
{
OnlinestatusLoxone = 1;
digitalWrite(OnlinestatusLED, HIGH);
}
if (OnlinestatusReceiveCounter < OnlinestatusCheckTimeout)
{
OnlinestatusReceiveCounter = OnlinestatusReceiveCounter + 1;
}
if (OnlinestatusReceiveCounter == OnlinestatusCheckTimeout)
{
OnlinestatusLoxone = 0;
digitalWrite(OnlinestatusLED, LOW);
}
// Schaltrelais
if (!strcmp(packetBuffer, "051"))
{
digitalWrite(Schaltrelais, HIGH);
}
if (!strcmp(packetBuffer, "050"))
{
digitalWrite(Schaltrelais, LOW);
}
delay(1000/Programmfrequenz);
}
|
Teil 4 - UDP-Sendefunktion
Die Sendefunktion für die UDP-Nachrichten bleibt im Vergleich zum vorangegangenen Szenario unverändert.
|
// Function to send UDP packets
void sendUDP(String text)
{
Udp.beginPacket(RecipientIP, RecipientPort);
// Udp.write("Test");
Udp.print(text);
Udp.endPacket();
}
|
Teil 5 - UDP-Empfangsfunktion
Auch die Empfangsfunktion für die UDP-Nachrichten bleibt im Vergleich zum vorangegangenen Szenario unverändert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// Function to check for new incoming UDP packets
void checkUDP()
{
// if there's data available, read a packet
int packetSize = Udp.parsePacket();
if(packetSize)
{
// read the packet into packetBufffer
Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
// For debug only
// Write packetBuffer to serial
Serial.print("ReceiveUDP: ");
Serial.println(packetBuffer);
// send "ACK" as reply
//Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
//Udp.write("ACK");
//Udp.endPacket();
}
}
|
Einrichtung des Smart-Home-Servers
Analog zum "Virtuellen Ausgang Verbinder" im vorherigen HowTo Teil 4 wird nun das "Schaltrelais" in die Loxone Config eingefügt.
Das Element sendet entsprechend "051" zum Arduino, sofern der vorgelagerte "EIB-Taster" ein Ein-Signal (1) liefert und "050", sobald das Signal auf Aus (0) wechselt.
Aus meinem täglichen Leben
Mithilfe der hier gezeigten Anbindung lässt sich der LED-Spot bequem über die Loxone-Visualisierung ein- und ausschalten.
Zu Testzwecken habe ich das Szenario auch noch etwas erweitert, sodass der LED-Spot eingeschaltet wird, sofern über den Arduino eine Bewegung (siehe
HowTo Teil 2) erkannt wird und die Helligkeit unterhalb eines festgelegen Schwellwerts (siehe
HowTo Teil 3) liegt.
Gerade am Anfang hatte ich das oben bereits kurz angesprochene Problem von Fehlauslösungen des Bewegungsmelders aufgrund der höheren Leistungsaufnahme des Relais, welches beim Betrieb des Arduino über USB (5 V) ungewollte Spannungsabsenkungen der auf den Pins angeschlossenen Komponenten bewirkt. Mithilfe eines separaten
9 V Netzteils (Affiliate-Link) mit genug Leistung konnte dieses Fehlverhalten jedoch behoben werden.
Das einzige Problem, welches künftig noch adressieren werden soll, ist das Verhalten des Relais bei einem Neustart des Arduino bspw. infolge einer vorangegangenen Stromtrennung.
Denn dabei erhält das Relais ein kurzes ungewolltes Spannungssignal, wodurch auch der LED-Spot kurz einschaltet. Sofern ich herausgefunden habe, wie sich dieses Verhalten verhindern lässt, folgt ein Update.
Dabei bin ich natürlich für jeden Tipp dankbar, der mich diesbezüglich weiterbringt.
Insgesamt läuft die prototypische Installation bisher ohne jegliche Hänger. Mal sehen, ob das so bleibt, sobald ein PWM-Aktor das Szenario im nachfolgenden HowTo erweitert.
Quelle:
Jörg Hofman
hat im April 2011 meintechblog.de gegründet, um seine Technikbegeisterung und Erkenntnisse mit anderen zu teilen.
Mittlerweile veröffentlicht er regelmäßig Howtos in den Bereichen Smart Home und Home Entertainment.
http://www.meintechblog.de/2015/06/arduino-im-smart-home-howto-teil-1-das-steckt-dahinter/
DIN A4 ausdrucken
*********************************************************
Impressum: Fritz Prenninger, Haidestr. 11A, A-4600 Wels, Ober-Österreich, mailto:[email protected]
ENDE