Homeduino …der universelle LAN/WLAN-Arduino für die Hausautomation mit I/O-Shield 1.0

[google-translator] Wichtiger Hinweis: Es gibt mittlerweile eine neue Softwareversion:   Homduino 4.0

Achtung: Mittlerweile gibt es das Homeduino Shield 2.0  siehe hier:
https://www.stall.biz/?project=homeduino-der-universelle-lanwlan-arduino-fur-die-hausautomation-mit-io-shield-2-0-2

1  Ausgangssituation
Die Verwendung des Arduino im Hausnetz bietet sich insbesondere deshalb an, weil es eine Vielzahl von preisgünstigen Sensoren und Aktoren gibt und zudem eine riesige Entwicklergemeinde hierfür leistungsfähige Software entwickelt. Natürlich lassen sich eigenständige Steuerungen damit entwickeln, aber im Hinblick auf Hausautomation ist die Einbindung in ein Hausnetz besonders sinnvoll und zukunftssicher. Die folgenden Lösungsansätze konzentrieren sich auf Kombinationen mit der Homematic oder einem RaspberryPi als Steuerungsrechner, aber das System ist so universell ausgelegt, dass auch Integrationen mit anderen Systemen leicht möglich sind.

2  Hardware des Homeduino
Im Folgenden wird  kochrezeptartig das verwendete System beschrieben, so dass auch Anfänger relativ leicht einen Nachbau erfolgreich realisieren können.

Zutatenliste:
1x Arduino MEGA 2560 r3 (bei ebay in China für unter 10€ zu bekommen)
1x Ethernet Shield W5100 (bei ebay in China für unter 6€ zu bekommen)

und optional:

1x WLAN-Repeater/Bridge möglichst mit integriertem USB-Netzteil
(ich verwende den Phicomm M1 , bei Amazon für 12,50€)
1x I/O-Anschluss-Board, entweder selbst bauen oder Bausatz/Platine bei mir anfragen.
(Beschreibung  der ersten Entwicklungsversion hier    http://homematic-forum.de/forum/viewtopic.php?f=31&t=18871#p156004 )

Mittlerweile gibt es ein verbessertes neues I/O-Anschluss-Board mit großenteils fertiggestellter Platine.
Beschreibung hier: https://www.stall.biz/?project=vielseitiges-io-shield-board-2-0-fur-fast-alle-arduinos

Kauf-Interessierte können mich  per email (Kontakt -Button)  ansprechen.
Der Teil-Bausatz kostet 26€ plus 3,90€ Versand nach Deutschland.

 

komponenten

3  Eigenschaften des Homeduino
Mit Verwendung des optionalen I/O-Shields ist ein universeller Anschluss von Sensoren und Aktoren möglich, wie sie für die Heimautomation erforderlich sind. Dazu gehören einfache Anschlussmöglichkeiten für 1-Wire-Sensoren, NTC-Temperaturfühler, Schalter /Reedschalter, Ultraschallsensoren, analogen Gebern, IR-Signalempfängern, 435Mhz-Fernsteuerungen, Displays usw. Darüber hinaus sind natürlich auch alle Arten von Niedervoltrelais bis 24V ohne zusätzliche Treiber anschließbar und auch Niedervolt -Verbraucher bis etwa 2A sind direkt steuerbar. Der elektrische Anschluss erfolgt mittels professioneller 40-poliger WAGO-Klemmleiste, damit ein zuverlässiger Betrieb ohne die beim Arduino häufig anzutreffenden „fliegenden“ Breadboard-Aufbauten möglich ist!

Folie2

 

 

shield_in_hand
Insgesamt stehen mit dem verwendeten I/O-Shield 14 als Ein- oder Ausgänge nutzbare Pins zur Verfügung. Darüberhinaus hat der MEGA 2560 noch weitere I/Os, die aber nur mit zusätzlichen speziellen Anschlüssen verfügbar gemacht werden können. Hier wurde bewusst die Anzahl der I/Os auf 14 begrenzt, damit der Homeduino nicht mit zuvielen Funktionen „überfrachtet“ wird. Stattdessen sollten sehr umfangreiche Steuerungsaufgaben besser auf mehrere Homeduinos verteilt werden. Und zusätzlich kann das IO-Shield auch für die „kleinen“ Arduinos wie der UNO verwendet werden.

Also unser Homeduiono hat mit dem optionalen I/O-Shield bis zu…

>> 6 analoge Eingänge:
– 0 bis +5V oder 0 bis +10V , per Jumper kanalweise umschaltbar
– verwendbar auch als schnelle  digitale I/O mit  für jeden Kanal einzeln einstellbarer Triggerschwelle (!)
– mit einzeln per Jumper zuschaltbaren 10kOhm Pullup-Widerständen z.B. für Standard-NTC- Thermofühler

>> 8 digitale I/Os
– Jeder I/O mit Status LED
– jeder digitale Eingang mit 4k7-Pullup z.B. für 1-Wire-Sensoren
– jeder digitale Ausgang mit Hochstrom-Mosfet -Treiber für Ansteuerung von NV-Relais etc.

Die Anschlussbelegung zeigt folgendes Bild:

board_io_shield
3  LAN/WLAN-Integration im Heimnetz

Der ursprüngliche Plan für den Homeduino war die Verwendung des Arduino YUN oder eines anderen Arduinos mit eigenem WLAN-Shield. Aber nach ersten Versuchen mit dem YUN wurde klar, dass man für diese Lösung auch die  recht komplizierte WLAN-Programmierung mit  in das Homeduino-Sketch  integrieren muss.  Auch ist wegen der direkten Nähe zum heimischen Router oftmals eine drahtgebundene LAN-Kommunikation nicht nur einfacher sondern auch kostengünstiger und zuverlässiger realisierbar.  Nach Abwägung aller  Vor- und Nachteile wurde deshalb eine Lösung mit standardmässigem Ethernet-Shield und einem zusätzlichen eigenständigen WLAN-Adapter oder Repeater realisiert:

Die Basis-Kommunikation mit dem Homeduino erfolgt also über das Ethernet-Shield. Dabei kann man wählen, ob mittels LAN-Leitung und direktem Anschluss an den Router die Daten drahtgebunden (wired) übertragen werden, oder ob mit einem zusätzlichen WLAN-Repeater o.ä. eine drahtlose Anbindung des Arduino an das Heimnetz erfolgen soll. Dies hängt, wie schon gesagt,  natürlich davon ab, ob der Homeduino evtl. in der Nähe des Routers platziert werden kann oder eben nicht.

Als WLAN-Repeater/Router  eignet sich ein PHICOMM M1 besonders gut, weil er nicht nur sehr kostengünstig ist und alle notwendigen Betriebsarten beherrscht, sondern weil er ein integriertes 5V-USB-Netzteil hat (5V, 0,5A). Damit lässt sich der Homeduino wunderbar  mitversorgen, wenn er nicht gerade viele zusätzliche und stromhungrige Verbraucher hat. Das nachfolgende Bild zeigt, wie die einzelnen Komponenten verknüpft werden. Der Homeduino wird einfach mit einer kurzen LAN-Leitung und einer kurzen USB-Leitung mit dem PHICOMM verbunden. Das ist hardwareseitig schon alles!

Softwaremässig müssen die Komponenten dann entsprechend der individuellen Heimnetz-Gegebenheiten eingestellt werden.  Der Phicomm hat von Haus aus die IP :  192.168.0.1   , was leider nicht zu dem Nummerkreis meiner Fritzbox (192.168.178.1) passt. Deshalb muss der PHICOMM-Router zuerst auf eine Adresse im eigenen Heimnetz (z.B. 192.168.178.3)  eingestellt werden (siehe Bedienungsanleitung).

 

 

Folie13

Die Einstellung der weiteren Parameter im PHICOMM ist dann sehr einfach, indem man den sog. Client-Betrieb aktiviert. Zusätzlich ist noch das WLAN-Kennwort des Heimnetz-Routers einzugeben. Das ist schon alles !

Folie14

Wer zusätzlich  noch gerne das eigene WLAN-Netz bezüglich der Reichweite erweitern  möchte, der kann auch statt des Client-Modus den Repeater-Betrieb wählen. Das funktioniert auch sehr gut.

 

4  Software des Homeduino
Die Software des Homeduino, also gewissermassen das Betriebssystem, wurde so gestaltet, dass die Software für alle geplanten Mess- und Steuerungsaufgaben fertig konfiguriert ist. Eine individuelle Anpassung ist kaum notwendig (nur einige Parameter werden individuell gesetzt).
Mit  einfachen  Befehlen wird die Funktion der I/Os bestimmt und programmiert. Bei der Gestaltung der Befehle wurde grosser Wert darauf gelegt, dass man bereits mit einem beliebigen Browser eine Steuerung der I/Os erreichen kann. Die nachfolgende Befehlsliste zeigt eigentlich sehr eindrucksvoll, wie und was man mit dem Homeduino alles steuern und messen kann:

Befehlsliste des Homeduino:  ( mit homeduino IP: 192.168.178.58)

arduino IP: 192.168.178.58

IP-Adresse/?Befehl:Param1:Param2: ...

192.168.178.58/?setpin:4:5:               >> Pins D4,D5 auf HIGH setzen und Pins als Output setzen 

192.168.178.58/?resetpin:7:4:8:           >> Pins D7,D4,D8 auf LOW setzen und Pinsals Output setzen 

192.168.178.58/?digitalin:5:4:            >> Pins D5,D4 lesen und Pins als Input setzen 

192.168.178.58/?analogin:0:5:             >> Pins A0,A5 lesen und Pins auf Analoginput setzen 

192.168.178.58/?pwm_out:4:96:             >> PWM-Signal mit Tastverhältnis 96% an Digitalpin D4 ausgeben 

192.168.178.58/?onewire:6:0:5:1:          >> An D6 die 1-Wire Sensoren Nr.0, Nr.5 und Nr.0 einlesen 

192.168.178.58/?1wire:7:                  >> An D7 den 1-Wire Sensor einlesen 

192.168.178.58/?1wire_address:8:          >> An D8 alle Adressen der 1-Wire Sensoren auslesen 

192.168.178.58/?rf_send:4:4523029:24:     >> An D4 das RF-Telegramm 4523029 mit 24bit-Kodierung ausgeben 

192.168.178.58/?rf_receive:               >> An D3 auf rf-Signal 3s warten und RF-Telegramm anzeigen 

192.168.178.58/?ir_send:nec:1086136543:32 >> An D9 das IR-Telegramm 1086136543 mit 36 bit laenge ausgeben 

192.168.178.58/?ir_receive:               >> An D2 auf IR-Signal 3s warten und IR-Telegramm anzeigen 

192.168.178.58/?ir_rawstore:5:            >> 3sec empfangen und IR-Signal auf Speicherplatz 5 wegspeichern

192.168.178.58/?ir_rawsend:5:             >> sendet IR-Signal von Speicherplatz 5 

192.168.178.58/? 

192.168.178.58/? 

192.168.178.58/?w_data:0:1425:            >> Homeduino-Integervariablen "w_data[0]" mit Wert 1525 setzen 

192.168.178.58/?r_data:4:5:               >> Homeduino-Integervariablen "w_data[4]" und "w_data[5]" auslesen 

192.168.178.58/?dist:6:                   >> Entfernung in cm mit Ultraschallsensor an Pin D6 einlesen 

192.168.178.58/?w_msg:abcdef              >> "abcdef" in Homeduino-String "message" speichern 

192.168.178.58/?set_time:174393838:       >> Homeduino-Zeit (Sekunden seit 1.1.1970) setzen/auslesen 

192.168.178.58/?display:0:3:meldung       >> zeigt auf Display in Position 0 in Zeile 3 den Text "meldung" 

192.168.178.58/?display:                  >> loescht Display komplett

192.168.178.58/?barometer                 >> zeigt Daten vom Barometer-Sensor BMP180 >> 

192.168.178.58/?r_msg:                    >> Homeduino-String "message" auslesen 

192.168.178.58/?ntc_in:0:5:               >> NTC-Temperaturen von Pin A0 und A5 lesen 

192.168.178.58/?help:                     >> Anzeige der Befehlsliste 

192.168.178.58/?ver:                      >> Anzeige der Firmware-Version 

 

 

Die Befehlsliste ist beliebig erweiterbar, bis der Arbeitspeicher des MEGA 2560 erschöpft ist. Aber zur Zeit sind noch viele Reserven vorhanden. ( Begonnen habe ich mit dem UNO, bin dann aber relativ schnell an die Kapazitätsgrenze gestossen!) Die einzelnen Befehle können mit dem Browser abgesetzt werden oder aber von einem Steuerungsrechner wie z.B. der Homematic oder einem Raspberry oder, oder …

5  Programmierung des Arduino
Die „Firmware“ des Homeduinos ist leider nicht ganz so einfach „reinzuladen“, weil erst die Arduino-Entwicklungsumgebung (IDE) mit allen notwendigen Libraries installiert werden muss. Erst dann kann die Homeduino-Software compiliert und hochgeladen werden.

Also hier die „Schritt für Schritt“-Installation:

1. hier die verwendete  Arduino-Version runterladen:  http://downloads.arduino.cc/arduino-1.5.7-windows.exe  und normal  installieren. Getestet habe ich Version 1.5.7 , dabei wurde der USB-Treiber mit installiert. Die Installationsdateien liegen bei Windows standardmässig im Verzeichnis : „c:\Program Files (x86)\Arduino\“

2. in den Unterordner „libraries“ folgende zusätzliche libraries als Unterverzeichnisse kopieren:

3. folgendes Datenpaket holen, entpacken und das Verzeichnis „DallasTemperature“ als Unterverzeichnis im Verzeichnis „libraries“ wegspeichern:
http://www.hacktronics.com/code/DallasTemperature.zip

4. folgendes Datenpaket holen, entpacken und das Verzeichnis „OneWire“ als Unterverzeichnis im Verzeichnis „libraries“ wegspeichern:
http://www.hacktronics.com/code/OneWire.zip

5. folgendes Datenpaket holen, entpacken und das Verzeichnis „RCSwitch“ als Unterverzeichnis im Verzeichnis „libraries“ wegspeichern:
https://rc-switch.googlecode.com/files/RCSwitch.zip

6. folgendes Datenpaket holen, entpacken und das Verzeichnis „Arduino-IRremote-master“ umbenennen und als Unterverzeichnis „IRremote“ im Verzeichnis „libraries“ wegspeichern:
https://github.com/shirriff/Arduino-IRremote/archive/master.zip

7. folgendes Datenpaket holen, entpacken und Verzeichnis“Time“ , „TimeAlarms“ und „DS1307RTC“ im Verzeichnis „libraries“ wegspeichern:
http://playground.arduino.cc/uploads/Code/Time.zip
Leider gibt es mit dieser library noch Compilierfehler. Deshalb mit einem Editor die Datei  DateStrings.cpp  im Time-Verzeichnis öffnen und den Programmcode mit dem verbesserten Programmcode aus dieser Datei ersetzen: https://github.com/dhiltonp/hexbright/blob/master/libraries/Time/DateStrings.cpp. Man kann auch die vorhandenen Datei DateStrings.cpp durch die verbesserte neue ersetzen.

8. folgendes Datenpaket holen, entpacken und Verzeichnis“LiquidCrystal“  im Verzeichnis „libraries“ wegspeichern:
https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/LiquidCrystal_V1.2.1.zip
vorher ggf. „alte“ LiquidCrystal-library löschen.

9. folgendes Datenpaket holen, entpacken und daraus das Unterverzeichnis“SFE_BMP180″  im Verzeichnis „libraries“ wegspeichern:
https://github.com/sparkfun/BMP180_Breakout/archive/master.zip

10. ein Verzeichnis „c:\arduino_sketchbook einrichten und in der Arduino-Entwicklungsumgebung diesen Ordner unter Datei/Voreinstellungen als Speicherort für das Sketchbook festlegen. Natürlich kann man das Verzeichnis auch woanders ablegen.

So sieht das Verzeichnis „libraries“ nach dem Herunterladen aller Bibliotheken aus; gelb markiert sind die neuen hinzugefügten Libraries:
libraries_ordner

Damit ist die Entwicklungsumgebung vorbereitet und kann mit arduino.exe gestartet werden. Das Editor-Fenster geht auf und dann mit  „Copy/Paste“  das folgende Arduino_Sketch in den Editor laden und mit „speichern unter“ erst mal im vorher definierten Sketchbook als homeduino_xy sichern. :

 

[codesyntax lang=“text“ title=“Homeduino Sketch“]

//Versionsbezeichner "homeduino_21.ino / Stand: 2014.09.13"; 
// fuer Arduino Mega 2560 mit Arduino 1.5.6r2
//Verfasser: Eugen Stall
// diese Software erlaubt die Steuerung der Pinfunktionen mit einfachen Browserbefehlen
//verwendete Quellen fuer libraires und Programme siehe Beschreibung und Erläuterungen im Quelltext
//die aktuellste Version ist immer hier:
//https://www.stall.biz/?project=homeduino-der-universelle-lanwlan-arduino-fur-die-hausautomation

#include <Ethernet.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <RCSwitch.h>
#include <IRremote.h>
#include <Time.h>
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
#include <SFE_BMP180.h>
#include <EEPROM.h>

String ver = "homeduino_20.ino / Stand: 2014.09.13"; // Versionsbezeichner

////////////////////////////////////////////////////////////////////////
//Netzwerk-Konfiguration muss individuell hier eingegeben werden
byte ip[] = { 192, 168, 178, 58 }; //das ist die IP des Arduino //<<user-eingabe<<
byte gateway[] = { 192, 168, 178, 1 }; //das ist die IP des Routers //<<user-eingabe<<
byte subnet[] = { 255, 255, 255, 0 }; //wie immer //<<user-eingabe<<
byte mac[] = { 0xDE, 0xAF, 0xEE, 0xEF, 0xEE, 0xDE }; //nur 1x im Netz //<<user-eingabe<<
EthernetServer server(80); //server port 80
 
byte ccu[] = { 192, 168, 178, 50 }; //das ist die IP der CCU //<<user-eingabe<< 
EthernetClient client;
 
//Variablendefinitionen:
boolean reading = false;
boolean valid_command = false;
String command = String(200); // string for fetching data from address
String befehl = String(20);
String parameter = String(20);
String header = String(20);
 
String ip_adresse = String(15);
int param;
long param1;
int param2;
int param3;
String message = String(60);
boolean test = false;
unsigned long currentMillis;
unsigned long time;
unsigned long last_get;
unsigned long akt_zeit;
unsigned long next_update;
 
float tempNTC;
float B_wert = 3950; //aus dem Datenblatt des NTC //<<user-eingabe<<
float Tn = 298.15; //25°Celsius in °Kelvin 
float Rv = 10000; //Vorwiderstand
float Rn = 10000; //NTC-Widerstand bei 25°C
float Rt ; 
 
int data[10];
int datum;
 
int PWM;
 
int onewire_pin;
float temp_tur;
 
int rf_key;
String rfkey;
 
RCSwitch mySwitch = RCSwitch();
 
boolean Ax_alt [6];
boolean ir_enable = 1; // 1 wenn ein ir-receiver an pin D2 verwendet wird
boolean rf_enable = 1; // 1 wenn ein rf-receiver an pin D3 verwendet wird
int schaltschwelle_high[]= {1023,1023,1023,510,510,510}; //schaltschwelle der Analogeingänge , //<<user-eingabe<<
 //wenn analogwert grösser, dann high
int schaltschwelle_low[]= {0,0,0,100,100,100}; //schaltschwelle der Analogeingänge , //<<user-eingabe<<
 //wenn analogwert kleiner, dann low 

int RECV_PIN = 2; 
IRrecv irrecv(RECV_PIN); //2 ist der IR- Empfangspin D2
IRsend irsend; // sendepin ist beim MEGA2650  D9!
decode_results results;
String code_type;
int ir_key;
String irkey;
int decod;
unsigned long val;
int bitss;
unsigned int address;
int rawl; 
String hersteller;
// Storage for the recorded code
int codeType = -1; // The type of code
unsigned long codeValue; // The code value if not raw
unsigned int rawCodes[RAWBUF]; // The durations if raw
int codeLen; // The length of the code
int count;
int STATUS_PIN = 13;
int addr;

SFE_BMP180 pressure;
int altitude = 229.0; // hoehe des barometer-standortes
boolean lcd_text_anzeigen; 

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
char status;
double T,P,p0,a;

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void setup()
{ Serial.begin(9600); //Pins 10,11,12 & 13 fuer ethernet shield verwendet
 Ethernet.begin(mac, ip, gateway, subnet); 
 server.begin(); 
 ip_adresse = String(ip[0]) + "." + String(ip[1]) + "." +String(ip[2]) + "." + String(ip[3]);
 header = "arduino IP: " + ip_adresse + "\n\r";
 
 next_update = now() + 600; // nächste regelabtastung der analogen digitaleingänge alle 600 sec 
 last_get = now() +3;
 mySwitch.enableReceive(1); //receiver on interrupt 1 => that is pin D3
 
 if (ir_enable = true) {irrecv.enableIRIn();irrecv.blink13(true);pinMode(9, OUTPUT); //lED leuchtet während der Abarbeitung der Befehle
 digitalWrite(9, HIGH);} // Start the ir-receiver auf pin D2
 if (rf_enable = true) {mySwitch.enableReceive(1);} //start rf receiver auf pin D3
 
 lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines and turn on backlight
 lcd.backlight();
 }
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void loop()
{ 
 command = ""; //String(100);
 EthernetClient client = server.available();
 if (client) 
 { // an http request ends with a blank line
 boolean currentLineIsBlank = true;
 while (client.connected())
 { if (client.available()) 
 { char c = client.read();
 if (reading && c == ' ') reading =false;
 if (c == '?') reading = true; // beginn der Befehlssequenz 
 if (reading) 
 { //read char by char HTTP request
 if (command.length() < 100) 
 { //store characters to string
 command = command + c;
 }
 } 
 if (c == '\n' && currentLineIsBlank) break;
 if (c == '\n') 
 { currentLineIsBlank = true;} else if (c != '\r') 
 { currentLineIsBlank = false;}
 }
 }
////////////////////////////////////////////////////////////////////////
pinMode(13, OUTPUT); //lED leuchtet während der Abarbeitung der Befehle
digitalWrite(13, HIGH);
 
//jetzt wird das command ausgeführt 
// befehl herausmaskieren
int colonPosition = command.indexOf(':');
befehl = command.substring(1,colonPosition);
command = command.substring((colonPosition+1)); //Rest-command bilden
 
client.print(header);
valid_command = false;
//###########################################################################
if (befehl == "setpin") 
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 pinMode(param, OUTPUT);
 digitalWrite(param, HIGH);
 client.print("Pin D" + parameter + " = 1 port is digital output E\n\r"); 
 }
}
//###########################################################################
if (befehl == "resetpin") 
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 pinMode(param, OUTPUT);
 digitalWrite(param, LOW);
 client.print("Pin D" + parameter + " = 0 port is digital output E\n\r"); 
 }
}
//###########################################################################
if (befehl == "digitalin") 
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 pinMode(param, INPUT);
 digitalWrite(param, HIGH);
 client.print("Pin D" + parameter + " = " + digitalRead(param) + " port is digital input E\n\r");
 }
}
//###########################################################################
if (befehl == "analogin") 
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 client.print("Pin A" + parameter + " = " + analogRead(param) + " port is analog input E\n\r");
 }
}
//###########################################################################
if (befehl == "pwm_out") 
{ valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false;}; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 PWM = command.toInt();
 pinMode(param, OUTPUT);
 analogWrite(param, PWM); 
 client.print("PWM D" + parameter + " = " + PWM + "% duty cycle at output E\n\r");
 
}
 
//###########################################################################
//Quellen: https://github.com/shirriff/Arduino-IRremote
if ((befehl == "ir_receive")&& (ir_enable == true)) //
 {valid_command = true; 
 decode_results results;
 irrecv.enableIRIn(); // Start the receiver
 unsigned long time_rf0 = millis();
 unsigned long time_rf1 = millis();
 
 while ((time_rf1 - time_rf0) < 3000)
 { time_rf1 = millis(); 
   if (irrecv.decode(&results))
        {dump(&results);
         client.print(hersteller );
         //client.print(decod);
         client.print("-code: ");
         client.print(val);
         client.print("  bits: "); 
         client.print(bitss);
         if ( address >0) {client.print(" opt.adress: ");
                           client.print(address);}
         client.print("   raw pulses: "); 
         client.print(rawl); 
         client.print("  0.5us-ticks\n\r");
         irrecv.resume(); // weitermachen mit empfangen
        } 
 }
 client.print("end ir_receive :" + command + " \n\r"); 
 }
//###########################################################################
//Quellen: https://github.com/shirriff/Arduino-IRremote
if (befehl == "ir_send") 
{ valid_command = true; 
 colonPosition = command.indexOf(':');
 code_type = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 //param = parameter.toInt(); 
 colonPosition = command.indexOf(':');
 parameter = command.substring(0,colonPosition);
 param1 = parameter.toInt(); 
 parameter = command.substring((colonPosition+1));
 param2 = parameter.toInt(); 
 
 if (code_type == "nec") {for (int i = 0; i < 1; i++) {
 irsend.sendNEC(param1, param2); // NEC code
 delay(40);}}
 
 if (code_type == "sony") {for (int i = 0; i < 3; i++) {
 irsend.sendSony(param1, param2); // Sony code
 delay(40);}} 
 
 if (code_type == "rc5") {for (int i = 0; i < 3; i++) {
 irsend.sendRC5(param1, param2); // rc5 code
 delay(40);}} 
 
 if (code_type == "rc6") {for (int i = 0; i < 3; i++) {
 irsend.sendRC6(param1, param2); // rc6 code
 delay(40);}} 
 
 client.print("ir_send mit Sendecode :" + command + " \n\r"); 
} 
//###########################################################################
//Quellen: https://github.com/shirriff/Arduino-IRremote
if (befehl == "ir_rawstore")
 {valid_command = true; 
  colonPosition = command.indexOf(':');
  if (colonPosition > 2) {valid_command = false;}; //speicherplaetze max 2 stellen erlaubt
  parameter = command.substring(0,colonPosition);
  param = parameter.toInt(); 
  
  decode_results results;
  irrecv.enableIRIn(); // Start the receiver
  unsigned long time_rf0 = millis();
  unsigned long time_rf1 = millis();
 
  while ((time_rf1 - time_rf0) < 3000)
    {time_rf1 = millis(); 
     if(irrecv.decode(&results))
       { digitalWrite(STATUS_PIN, HIGH);
         storeCode(&results);  
         //IR-Code im EEPROM speichern, Werte wieder zurueckholen und ausgeben
         addr = 200*param + 2*99;
         codeLen = 256* EEPROM.read(addr) + EEPROM.read(addr+1);
         int k = 1;
         for (int i = 1; i <= (codeLen); i++)//zurückspeichern aus EEPROM
           {int addr = 200*param + 2*(i-1);
            rawCodes[i - 1] = 256* EEPROM.read(addr) + EEPROM.read(addr+1);
            if (i % 2) {client.print(" m");} else {client.print(" s");}
            client.print(rawCodes[i - 1],DEC); 
            k= k+1;
            if (k>10) {k=1; client.print("\n\r");
           }
       }
     client.print("\n\r");
     if (codeLen > 98){client.print("zu grosse und fehlerhafte ");}
     client.print("Codelaenge : ");
     client.print(codeLen);
     client.print("\n\r");
   
     irrecv.resume(); // resume receiver
     digitalWrite(STATUS_PIN, LOW);
    } 
 }
 client.print("end ir_rawstore auf Speicherplatz: " + parameter + " \n\r"); 
}
//###########################################################################
//Quellen: https://github.com/shirriff/Arduino-IRremote
if (befehl == "ir_rawsend") 
 { valid_command = true; 
   colonPosition = command.indexOf(':');
   if (colonPosition > 2) {valid_command = false;}; //speicherplaetze max 2 stellen erlaubt
   parameter = command.substring(0,colonPosition);
   param = parameter.toInt(); 
 
   addr = 200*param + 2*99;
   codeLen= 256* EEPROM.read(addr) + EEPROM.read(addr+1);
   int k = 1;
   for (int i = 1; i <= (codeLen); i++)//zurückspeichern aus EEPROM
     {addr = 200*param + 2*(i-1);
      rawCodes[i - 1] = 256* EEPROM.read(addr) + EEPROM.read(addr+1);
      if (i % 2) {client.print(" m");} else {client.print(" s");}
      client.print(rawCodes[i - 1],DEC); 
      k= k+1;
      if (k>10) {k=1; client.print("\n\r");}
     }
   client.print("\n\r");
   client.print("Codelaenge : ");
   client.print(codeLen);
   client.print("\n\r");
   irsend.sendRaw(rawCodes, codeLen, 38);// Assume 38 KHz
   client.print("ir_rawsend von Speicherplatz :" + parameter + " \n\r"); 
 }

//###########################################################################
// Quellen: http://code.google.com/p/rc-switch/
if (befehl == "rf_send") 
{ valid_command = true; 
 colonPosition = command.indexOf(':');
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 colonPosition = command.indexOf(':');
 parameter = command.substring(0,colonPosition);
 param1 = parameter.toInt(); 
 parameter = command.substring((colonPosition+1));
 param2 = parameter.toInt(); 

 //RCSwitch mySwitch = RCSwitch();
 mySwitch.enableTransmit(param);
 // Optional set pulse length.
 // mySwitch.setPulseLength(320);
 // Optional set protocol (default is 1, will work for most outlets)
 // mySwitch.setProtocol(2);
 // Optional set number of transmission repetitions.
 // mySwitch.setRepeatTransmit(15);
 
 mySwitch.send(param1, param2);
 client.print("rf_send mit Sendecode :" + command + " \n\r"); 
} 
//###########################################################################
//Quellen http://code.google.com/p/rc-switch/ 
if ((befehl == "rf_receive")&& (rf_enable == true)) 
 { valid_command = true; 
 //mySwitch.enableReceive(1); //receiver on interrupt 1 => that is pin D3
 unsigned long time_rf0 = millis();
 unsigned long time_rf1 = millis();
 while ((time_rf1 - time_rf0) < 3000)
 { time_rf1 = millis();
 if (mySwitch.available()) 
 { int value = mySwitch.getReceivedValue();
 if (value == 0) {client.print("Unknown encoding");} 
 else 
 {client.print("Pin D3 received : ");
 client.print (mySwitch.getReceivedValue() );
 client.print (" / ");
 client.print( mySwitch.getReceivedBitlength() );
 client.print("bit Protocol: ");
 client.println( mySwitch.getReceivedProtocol() + " \n\r" );
 }
 mySwitch.resetAvailable();
 }
 } 
 client.print("end rf_receive :" + command + " \n\r"); 
 } 
//########################################################################### 
if (befehl == "onewire") 
{ valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 onewire_pin = parameter.toInt();
//Setup onewire//////////////////////////////////////////////////////////////////////
//long intervall_onewire =10000; //onewire-Operation alle 10sec
//long lastTime_onewire =0;
float tempC[10]; // 10 Onewire-Sensoren werden maximal verwendet
 
OneWire oneWire(onewire_pin); 
DallasTemperature sensors(&oneWire);
DeviceAddress TempSensor[] = //Adress-Array definieren
{ 
 { 0x28, 0x37, 0x35, 0xB6, 0x05, 0x00, 0x00, 0x8D }, //<<user-eingabe<<
 { 0x28, 0xA5, 0x0A, 0xDD, 0x05, 0x00, 0x00, 0xBD }, //<<user-eingabe<< 
 { 0x28, 0x31, 0x60, 0xDD, 0x05, 0x00, 0x00, 0x7C }, //<<user-eingabe<<
 { 0x28, 0xA2, 0x4B, 0xB5, 0x05, 0x00, 0x00, 0x90 }, //<<user-eingabe<<
 { 0x10, 0xC7, 0xBA, 0xDD, 0x01, 0x08, 0x00, 0x52 }, //<<user-eingabe<<
 { 0x10, 0x8E, 0xB8, 0xDD, 0x01, 0x08, 0x00, 0x32 }, //<<user-eingabe<<
 { 0x10, 0xC7, 0xBA, 0xDD, 0x01, 0x08, 0x00, 0x52 }, //<<user-eingabe<<
 { 0x10, 0x8E, 0xB8, 0xDD, 0x01, 0x08, 0x00, 0x32 }, //<<user-eingabe<<
 { 0x10, 0xC7, 0xBA, 0xDD, 0x01, 0x08, 0x00, 0x52 }, //<<user-eingabe<<
 { 0x10, 0x8E, 0xB8, 0xDD, 0x01, 0x08, 0x00, 0x32 }, //<<user-eingabe<<
};
 // Start up the library
 sensors.begin();
 // aufloesung 10 bit
 sensors.setResolution(TempSensor[0], 10);
 sensors.setResolution(TempSensor[1], 10);
 sensors.setResolution(TempSensor[2], 10);
 sensors.setResolution(TempSensor[3], 10);
 sensors.setResolution(TempSensor[4], 10);
 sensors.setResolution(TempSensor[5], 10); 
 sensors.setResolution(TempSensor[6], 10);
 sensors.setResolution(TempSensor[7], 10);
 sensors.setResolution(TempSensor[8], 10);
 sensors.setResolution(TempSensor[9], 10);
 
//Setup onewire//////////////////////////////////////////////////////////////////////
 while (command.length() > 1 ) 
 { colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 sensors.requestTemperatures();
 tempC[param] = sensors.getTempC(TempSensor[param]);
 client.print("onewire T" + parameter + " = " + tempC[param] + " Celsius / pin D" + onewire_pin + " as input \n\r");
 } 
} 
//###########################################################################
//Quellen: http://tushev.org/articles/arduino/item/52-how-it-works-ds18b20-and-arduino
if (befehl == "1wire") /// Unterprogramm fuer 1wire Abfrage von einzelnen Sensoren
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 
 OneWire ds(param); 
 #define DS18S20_ID 0x10
 #define DS18B20_ID 0x28 
 byte i;
 byte present = 0;
 byte data[12];
 byte addr[8];
 if (!ds.search(addr)) { ds.reset_search(); temp_tur = -1000; } //find a device
 if (OneWire::crc8( addr, 7) != addr[7]) {temp_tur = -1000; }
 if (addr[0] != DS18S20_ID && addr[0] != DS18B20_ID) {temp_tur = -1000;}
 if (temp_tur > -1000) 
 { ds.reset(); 
 ds.select(addr); 
 ds.write(0x44, 1); // Start conversion
 delay(850); // Wait some time...
 present = ds.reset(); 
 ds.select(addr);
 ds.write(0xBE); // Issue Read scratchpad command
 for ( i = 0; i < 9; i++) { data[i] = ds.read(); } // Receive 9 bytes
 temp_tur = ( (data[1] << 8) + data[0] )*0.0625; // Calculate temperature value 18B20
 //temp_tur = ( (data[1] << 8) + data[0] )*0.5    // Calculate temperature value 18S20
 }
 client.print("1wire T" + parameter + " = " + temp_tur + " Celsius / pin D" + param + " as input \n\r");
 }
}
//###########################################################################
//Quellen:http://fluuux.de/2012/09/arduino-adressen-aller-ds1820-ermitteln/
if (befehl == "1wire_address") /// Unterprogramm fuer Auslesen der Sensoradresse
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 
 OneWire ds(param);
 byte address[8];
 int i=0;
 byte ok = 0, tmp = 0;
 client.print("--Suche gestartet--\n\r");
 while (ds.search(address))
 {tmp = 0; 
 if (address[0] == 0x10) { client.print("Device is a DS18S20 : "); tmp = 1;} //0x10 = DS18S20
 else { if (address[0] == 0x28) { client.print("Device is a DS18B20 : "); tmp = 1; } //0x28 = DS18B20
 }
 if (tmp == 1) //display the address, if tmp is ok 
 {if (OneWire::crc8(address, 7) != address[7]) { client.print("but it doesn't have a valid CRC!\n\r"); }
 else { for (i=0;i<8;i++) //all is ok, display it
 { 
 client.print("0x");
 if (address[i] < 9) { client.print("0");}
 client.print(address[i],HEX);
 if (i<7) { client.print(", ");}
 }
 client.print("\n\r");
 ok = 1;
 }
 }//end if tmp
 }//end while
 if (ok == 0){client.print("Keine Sensoren gefunden\n\r"); }
 client.print("--Suche beendet--\n\r");
 }
} 
//###########################################################################
if (befehl == "w_data") 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 datum = command.toInt();
 data[param] = datum;
 client.print("w_data" + parameter + " = " + datum + " set w_data E\n\r");
}
//###########################################################################
if (befehl == "r_data") 
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false;break;}; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 client.print("r_data" + parameter + " = " + data[param]+ " Wert der Variablen E\n\r");
 }
}
//###########################################################################
if (befehl == "dist") // messung mit ultraschallsensor an "beliebigen pin
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt(); 
 
 long duration, cm; 
 pinMode(param, OUTPUT);
 digitalWrite(param, LOW);
 delayMicroseconds(2);
 digitalWrite(param, HIGH);
 delayMicroseconds(5);
 digitalWrite(param, LOW);
 pinMode(param, INPUT);
 duration = pulseIn(param, HIGH);
 cm = duration /29/2; 
 delay(100);
 
 client.print("ultrasonic an Pin D" + parameter + " = " + cm + " cm E\n\r");
 }
}
//###########################################################################
if (befehl == "w_msg") 
{ message = command;
 valid_command = true; 
 client.print("w_msg :" + message + "\n\r");
} 
//###########################################################################
if (befehl == "r_msg") 
{ valid_command = true; 
 client.print("r_msg :" + message + "\n\r");
} 
//###########################################################################
if (befehl == "ntc_in") 
{ while (command.length() > 1 ) 
 { valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; break; }; //kanalnummern max 2 stellen erlaubt
 parameter = command.substring(0,colonPosition);
 command = command.substring((colonPosition+1));
 param = parameter.toInt();
 
 Rt = Rv/((1024.0/analogRead(param))- 1.0);
 tempNTC = (B_wert * Tn / ( B_wert + (Tn * log(Rt/Rn)))) -Tn +25.0 ;
 client.print("NTC an A" + parameter + " = " + tempNTC + " gradCelsius E\n\r");
 } 
} 
//###########################################################################
if (befehl == "set_time")
{ valid_command = false; 
 if (command.length() == 0) {time = now();parameter = String(time); valid_command = true;}
 if (command.length() == 11) 
 {valid_command = true;
 parameter = command.substring(0,10);
 time = parameter.toInt(); 
 setTime(time);
 time = now();
 parameter = String(time);}
 client.print("homeduino zeit /s ist: " + parameter + " \n\r");
} 

//###########################################################################
//Quellen: https://github.com/sparkfun/BMP180_Breakout/archive/master.zip
//library: https://github.com/sparkfun/BMP180_Breakout/tree/master/software/Arduino/libraries/SFE_BMP180
if (befehl == "barometer") 
{ valid_command = true; 
  colonPosition = command.indexOf(':');
  if (colonPosition > 4) {valid_command = false;}; //maximal 4 stellen erlaubt
   parameter = command.substring(0,colonPosition);
   param = parameter.toInt(); 
 
  if (pressure.begin()) 
     { //client.print("BMP180 gestartet\n\r");
      delay(1000);
      char status;
      double T,P,p0,a;
      // Start a temperature measurement:
  // If request is successful, the number of ms to wait is returned.
  // If request is unsuccessful, 0 is returned.
  
  client.print("Meereshoehe NN : ");
  client.print(parameter);
  client.print(" m\n\r"); 
  
  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.
    status = pressure.getTemperature(T);
    if (status != 0)
    { // Print out the measurement:
      client.print("Temperatur     : ");
      client.print(T,1);
      client.print(" gradC \n\r");  
      
      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.
      status = pressure.startPressure(3);
      if (status != 0)
      { // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        { // Print out the measurement:
          client.print("Druck absolut  : ");
          client.print(P,2);
          client.print(" mb\n\r"); 

          // The pressure sensor returns abolute pressure, which varies with altitude.
          // To remove the effects of altitude, use the sealevel function and your current altitude.
          // This number is commonly used in weather reports.
          // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
          // Result: p0 = sea-level compensated pressure in mb

          p0 = pressure.sealevel(P,param); //Messung
          
          client.print("Druck bei NN   : ");
          client.print(p0,2);
          client.print(" mb\n\r"); 
     
        }
        else {client.print("error");}
      }
      else {client.print("error"); }
    }
    else {client.print("error"); }
  }
  else {client.print("error"); }

 }  
     else
       {client.print("BMP180 nicht da\n\r");} 
} 
//###########################################################################
//Quelle source code:  http://arduino-info.wikispaces.com/LCD-Blue-I2C#v3
// library hier :https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/LiquidCrystal_V1.2.1.zip
if (befehl == "display") 
{ valid_command = true; 
 colonPosition = command.indexOf(':');
 if (colonPosition > 2) {valid_command = false; }; //spalten max 2 Stellen erlaubt
 if (command.length() < 2) {lcd.clear();} //display loeschen nur mit befehl /?display:
 parameter = command.substring(0,colonPosition);
 param2 = parameter.toInt(); //spalte ist param2
 command = command.substring((colonPosition+1));
 colonPosition = command.indexOf(':');
 if (colonPosition > 1) {valid_command = false; }; //zeilen max 2 Stellen erlaubt
 parameter = command.substring(0,colonPosition);
 param3 = parameter.toInt(); //zeile ist param3
 command = command.substring((colonPosition+1));
 command.replace("%20", " ");//hier http-leerzeichen ersetzen
 //langere strings werden in 20-zeichen-haeppchen zerlegt
 //weil display sonst zeile ueberspringt. fehler in library ??
 int m = 0; //laufvariable
 String zeilennummer;
 while (command.length() > 20)
 {String zeile = command.substring(0,20);
  command = command.substring(20);
  lcd.setCursor(0,(param3 + m));
  zeilennummer = String(param3 + m);
  lcd.print(zeile);
  client.print("lcd_display zeile " + zeilennummer + ": " + zeile + " \n\r");
  m = m+1;
  param2 = 0;
 }
 zeilennummer = String(param3 + m);
 lcd.setCursor(param2,param3 + m);
 lcd.print(command);
 client.print("lcd_display zeile " + zeilennummer + ": " + command + " \n\r"); 

} 
//###########################################################################
if (befehl == "help") 
{ valid_command = true; 
 client.print("IP-Adresse/?Befehl:Param1:Param2: ...\n\r");
 client.print( 
   ip_adresse + "/?setpin:4:5:               >> Pins D4,D5 auf HIGH setzen und Pins als Output setzen \n\r" 
 + ip_adresse + "/?resetpin:7:4:8:           >> Pins D7,D4,D8 auf LOW setzen und Pinsals Output setzen \n\r" 
 + ip_adresse + "/?digitalin:5:4:            >> Pins D5,D4 lesen und Pins als Input setzen \n\r"
 + ip_adresse + "/?analogin:0:5:             >> Pins A0,A5 lesen und Pins auf Analoginput setzen \n\r");
 client.print( 
   ip_adresse + "/?pwm_out:4:96:             >> PWM-Signal mit Tastverhältnis 96% an Digitalpin D4 ausgeben \n\r"
 + ip_adresse + "/?onewire:6:0:5:1:          >> An D6 die 1-Wire Sensoren Nr.0, Nr.5 und Nr.0 einlesen \n\r"
 + ip_adresse + "/?1wire:7:                  >> An D7 den 1-Wire Sensor einlesen \n\r"
 + ip_adresse + "/?1wire_address:8:          >> An D8 alle Adressen der 1-Wire Sensoren auslesen \n\r");
 client.print( 
   ip_adresse + "/?rf_send:4:4523029:24:     >> An D4 das RF-Telegramm 4523029 mit 24bit-Kodierung ausgeben \n\r"
 + ip_adresse + "/?rf_receive:               >> An D3 auf rf-Signal 3s warten und RF-Telegramm anzeigen \n\r"
 + ip_adresse + "/?ir_send:nec:1086136543:32 >> An D9 das IR-Telegramm 1086136543 mit 36 bit laenge ausgeben \n\r"
 + ip_adresse + "/?ir_receive:               >> An D2 auf IR-Signal 3s warten und IR-Telegramm anzeigen \n\r");
 client.print( 
   ip_adresse + "/?ir_rawstore:5:            >> 3sec empfangen und IR-Signal auf Speicherplatz 5 wegspeichern\n\r"
 + ip_adresse + "/?ir_rawsend:5:             >> sendet IR-Signal von Speicherplatz 5 \n\r"
 + ip_adresse + "/? \n\r"
 + ip_adresse + "/? \n\r");
 client.print( 
   ip_adresse + "/?w_data:0:1425:            >> Homeduino-Integervariablen \"w_data[0]\" mit Wert 1525 setzen \n\r"
 + ip_adresse + "/?r_data:4:5:               >> Homeduino-Integervariablen \"w_data[4]\" und \"w_data[5]\" auslesen \n\r"
 + ip_adresse + "/?dist:6:                   >> Entfernung in cm mit Ultraschallsensor an Pin D6 einlesen \n\r"
 + ip_adresse + "/?w_msg:abcdef              >> \"abcdef\" in Homeduino-String \"message\" speichern \n\r");
 client.print( 
   ip_adresse + "/?set_time:174393838:       >> Homeduino-Zeit (Sekunden seit 1.1.1970) setzen/auslesen \n\r"
 + ip_adresse + "/?display:0:3:meldung       >> zeigt auf Display in Position 0 in Zeile 3 den Text \"meldung\" \n\r" 
 + ip_adresse + "/?display:                  >> loescht Display komplett\n\r" 
 + ip_adresse + "/?barometer:229             >> zeigt Daten vom Barometer-Sensor BMP180 bezogen auf Meereshoehe 229m >> \n\r"); 
 client.print( 
   ip_adresse + "/?r_msg:                    >> Homeduino-String \"message\" auslesen \n\r"
 + ip_adresse + "/?ntc_in:0:5:               >> NTC-Temperaturen von Pin A0 und A5 lesen \n\r" 
 + ip_adresse + "/?help:                     >> Anzeige der Befehlsliste \n\r" 
 + ip_adresse + "/?ver:                      >> Anzeige der Firmware-Version \n\r");
 
 }
//########################################################################### 
if (befehl == "ver") 
{ valid_command = true; 
 client.print(ver + "\n\r");
} 
//###########################################################################
if (valid_command == false) {client.print("no valid command !\n\r");}
//###########################################################################
client.println(); 
 
//###########################################################################
 // delay(100); // give the web browser time to receive the data
 client.stop(); // close the connection:
 }
//###########################################################################
pinMode(13, OUTPUT); //lED leuchtet während der Abarbeitung der Befehle
digitalWrite(13, LOW);
//hierhin kommen eigenständige Steuerung-_Programme, die dauernd zyklisch durchlaufen werden, 
//wenn aktuell keine http-Anfrage abgearbeitet wird:
//////////////////////////////////////////////////////////////////////// 
// IR empfang 
if (ir_enable == true) 
 {if (irrecv.decode(&results)) // IR-Signal da?
 { dump(&results); 
 ir_decode(); //Dekodieren
 irrecv.resume();
 Serial.println(" ir_key : " + irkey ); 
 if (ir_key < 255 )
 {if (client.connect(ccu, 8181)) 
 { String befehl = "GET /xy.exe?antwort=dom.GetObject('homeduino_ir').State(" + irkey + ")";
 client.println(befehl);
 client.println();
 client.stop();
 }
 } 
 }
 }
//###########################################################################
//////////////////////////////////////////////////////////////////////// 
// RF empfang 
if (rf_enable == true) 
 { if (mySwitch.available()) // RF-Signal da?
 { int value = mySwitch.getReceivedValue();
 if (value == 0) {Serial.print("Unknown encoding");} 
 else { Serial.print("Pin D3 received Code : ");
 Serial.print (mySwitch.getReceivedValue() );
 Serial.print (" / ");
 Serial.print( mySwitch.getReceivedBitlength() );
 Serial.print("bit Protocol: ");
 Serial.println( mySwitch.getReceivedProtocol() + " \n\r" );
 rf_decode(); //Dekodieren
 mySwitch.resetAvailable();
 Serial.println(" rf_key : " + rfkey ); 
 if (rf_key < 255 )
 {if (client.connect(ccu, 8181)) 
 { String befehl = "GET /xy.exe?antwort=dom.GetObject('homeduino_rf').State(" + rfkey + ")";
 client.println(befehl);
 client.println();
 client.stop();
 }
 }
 }
 }
 } 
//###########################################################################
// hier werden alternativ die analogeingänge als digitaleingänge verwendet, 
// und bei änderung die entsprechenden gespiegelten HM-Systemvariablen "homeduino_ax" 
// in der ccu entweder bei änderung der eingangssignale oder 
// aber immer alle 10min aktualisiert. 
// umschaltung zwischen analog- und digital-modusmit der variablen variablen ana_as_digital 
int i = 0;
int messwert;
String kanal;
String logikpegel;
String befehl;
akt_zeit = now();
 
if (akt_zeit > next_update)
 { next_update = next_update +600; // nächste zwangsaktualisierung in 10min
 while (i < 6) {Ax_alt[i] = !Ax_alt[i]; i=i+1; } // der altzustand wird komplementiert
 i = 0;
 }
 
if (akt_zeit > (last_get+5)) //sicherstellen, dass nicht häufiger als alle 5sec aktualisiert wird
{
 if (client.connect(ccu, 8181)) 
 { while (i < 6) 
 { messwert = analogRead(i); 
 if ((messwert < schaltschwelle_low[i]) && (Ax_alt[i] == 1 )) //bei aenderung des logikpegels, dann aenderungsmitteilung senden 
 { 
 Ax_alt[i] = 0;
 logikpegel = "0";
 kanal = String(i);
 befehl = "GET /xy.exe?antwort=dom.GetObject('homeduino_a" + kanal +"').State(" + logikpegel + ")"; 
 last_get = now(); 
 client.println(befehl);
 client.println();
 Serial.println("kanal: " + kanal + " logikpegel : " + logikpegel + "\n\r" );
 }
 if ((messwert > schaltschwelle_high[i])&& (Ax_alt[i] == 0 )) 
 { 
 Ax_alt[i] = 1;
 logikpegel = "1";
 kanal = String(i);
 befehl = "GET /xy.exe?antwort=dom.GetObject('homeduino_a" + kanal +"').State(" + logikpegel + ")"; 
 last_get = now(); 
 client.println(befehl);
 client.println();
 Serial.println("kanal: " + kanal + " logikpegel : " + logikpegel + "\n\r" );
 } 
 
 i = i+1; 
 } 
 client.stop(); 
 }
}
//###########################################################################
}
//##################### ende Hauptprogramm #############################




//#################### Unterprogramme nachfolgend ######################################

//########################################################################################
//Unterprogramm zur Befehlserkennung der IR-Signale 
//
void rf_decode() 
{switch(mySwitch.getReceivedValue())
 {
 case 4523029: rf_key = 1; break;
 
 case 4523028: rf_key = 2; break;
 
 case 4539413: rf_key = 3; break;
 
 case 4539412: rf_key = 4; break;
 
 case 4527125: rf_key = 5; break;
 
 case 4527124: rf_key = 6; break;
 
 case 4543509: rf_key = 7; break;
 
 case 4543508: rf_key = 8; break;
 
 case 87296: rf_key = 9; break;
 
 case 12670208: rf_key = 10; break;
 
// bis 254 Codes möglich
 
 default: rf_key = 255;
 }
 rfkey = String(rf_key);
 
} 
 
//########################################################################################
//Unterprogramm zur Befehlserkennung der IR-Signale 
//
void ir_decode() 
{switch(results.value)
 {
 case 1086165103: ir_key = 1; break;
 
 case 1086128383: ir_key = 2; break;
 
 case 1086161023: ir_key = 3; break;
 
 case 1086144703: ir_key = 4; break;
 
 case 1086177343: ir_key = 5; break;
 
 case 1086136543: ir_key = 6; break;
 
 case 1086169183: ir_key = 7; break;
 
 case 16779273: ir_key = 8; break;
 
 case 16812169: ir_key = 9; break;
 
 case 33718399: ir_key = 10; break;
 
// bis 254 Codes möglich
 
 default: ir_key = 255;
 }
 irkey = String(ir_key);
 
}
//########################################################################################
//Quelle: Beispielprogramm aus der IRremote library
// Dumps out the decode_results structure. 
// Call this after IRrecv::decode()
// void * to work around compiler issue
void dump(void *v) {
decode_results *results = (decode_results *)v;
//void dump(decode_results *results) {

//werte als public variable speichern
val =(results->value);
bitss = (results->bits);
address = 0;
rawl = (results->rawlen);
decod =(results->decode_type);
switch(decod)
 { case 1: hersteller = "nec"; break;
   case 2: hersteller = "sony"; break;
   case 3: hersteller = "rc5"; break;
   case 4: hersteller = "rc6"; break;
   case 5: hersteller = "dish"; break;
   case 6: hersteller = "sharp"; break;
   case 7: hersteller = "panasonic"; address =(results->panasonicAddress) ;break;
   case 8: hersteller = "jvc"; break;
   case 9: hersteller = "sanyo"; break;
   case 10: hersteller = "mitsubishi"; break;
   case 11: hersteller = "samsung"; break;
   case 12: hersteller = "lg"; break;
   case -1: hersteller = "unknown"; break;
   default: ir_key = 255;
 }
 }

//##############################################################
// Stores the code for later playback Most of this code is just logging
void storeCode(decode_results *results)
{count = results->rawlen;
 codeLen = results->rawlen - 1;
 if (codeLen > 98) {codeLen =99;} //nur codelaengen bis 98 zulaessig
 // To store raw codes: Drop first value (gap) Convert from ticks to microseconds
 // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
 int k = 1;
 int addr;
 for (int i = 1; i <= codeLen; i++) 
 { if (i % 2) {rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS; Serial.print(" m");}// Mark
     else {rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS; Serial.print(" s");}// Space
   Serial.print(rawCodes[i - 1], DEC);
     
   //in EEPROM speichern 200bytes je IR-Code_Speicherplatz
   addr = 200*param + 2*(i-1);
   val = rawCodes[i - 1]/256;
   EEPROM.write(addr, val);  //schreibe High-Byte
   EEPROM.write(addr+1, rawCodes[i - 1] - val);  //schreibe Low-Byte
   k= k+1;
   if (k>10) {k=1; Serial.print("\n\r");}
 }
  //jetzt noch codeLen im EEPROM ablegen
   addr = 200*param + 2*99;
   val = codeLen/256;
   EEPROM.write(addr, val);  //schreibe High-Byte
   EEPROM.write(addr+1, codeLen - val);  //schreibe Low-Byte
   Serial.print("\n\r");
   Serial.print("Codelaenge : ");
   Serial.print(codeLen);
   Serial.print("\n\r");
}

[/codesyntax]

 

In der Arduino-Entwicklungsumgebung das verwendete Board MEGA2560, den Prozessor ATMega1560 und den verwendeten seriellen Port einstellen.

Dann zuerst mal schauen, ob jetzt die Homeduino-Software fehlerfrei kompiliert wird. (mit dem o.k-Haken-Button !). Wenn das fehlerfrei erfolgt, dann ist die Entwicklungsumgebung schon mal in Ordnung :))

Dann in diesem  Homeduino-Sketch die gewünschte feste IP-Adresse im Adressraum des eigenen Routers editieren. Darüberhinaus die Parameter in den Zeilen, die mit  „<<user-eingabe<<“ gekennzeichnet sind, nach den eigenen Bedürfnissen einstellen. Weitere Erläuterungen hierzu weiter unten!

Jetzt noch diesen Sketch sichern als „homeduino_x“ im Ordner „c:\arduino_sketchbook wegspeichern.

Dann mit dem Button „->“ das Programm übersetzen und  in den Homeduino laden.
(Wenn keine Kommunikation über das USB-Kabel erfolgt, dann ggf. über „Werkzeug/Port“ den richtigen seriellen Port des PC einstellen. )
Damit ist der Homeduino programmiert und kann über das Ethernet abgefragt oder gesteuert werden.

Zur ersten Funktionsprüfung gibt man am besten in der Adressleiste des Browsers den help-Befehl ein :

<arduino_IP>/?help:         ( in meiner Umgebung heißt der Befehl: 192.168.178.58/?help:   )

und erhält dann die oben bereits gezeigte Befehlsliste.

Das Programm ist noch in der Entwicklung und wird laufend verbessert und erweitert.
Bitte auf die Versionsnummer und Datum achten!

 

6  Integration in die Hausautomation
Das folgende Bild zeigt die typische Beschaltung des I/O-Shields bei Realisierung von digitalen Ein- und Ausgängen. Die Ausgänge D2 bis D9 sind direkt die Ausgänge des Mikroprozessors und sind dementsprechend wenig belastbar. Deshalb sind 8 leistungsfähige MOSFET-Treiber auf dem I/O-Shield untergebracht, welche  auch „stromhungrige“ Lasten (nach Masse) schalten können. Externe Versorgungsspannungen bis 24V sind dafür verwendbar, um entsprechende Relais, Lampen, LEDs etc. schalten zu können. Die zugehörigen Ausgänge auf dem I/O-Shield sind die mit einem Stern gekennzeichneten Pins D2* bis D9*.

Werden Die Pins D2 bis D9 als Eingänge verwendet, um beispielsweise Schaltersensoren abzufragen, dann sind ggf. mit den Jumpern JP3 entsprechende Pullup-Widerstände (4k7) einzuschalten. Folie1
6.1 Digitale Ausgänge schalten
Das Ein- und Ausschalten der digitalen Ports D2 bis D9 erfolgt per Browser mit den Befehlen …

<ip>/?setpin:2:5:6:8:          >> setzt Pins D2, D5, D6; D8  auf HIGH
<ip>/?resetpin:2:5:6:8:     >> setzt Pins D2, D5, D6; D8  auf LOW

und wird im Browser mit einer entsprechenden Rückmeldung bestätigt.

Aus der Homematic heraus kann die gleiche Aktion mit folgenden HM-Skripten erfolgen: Dazu ist vorher die logische Systemvariable homeduino_fehler zu definieren, welche im Skript gesetzt wird und anzeigt, ob eine erfolgreiche Kommunikation mit dem Homeduino erfolgt.

Mit diesem Skript werden zum Beispiel alle Pins D2 bis D9 auf 1 gesetzt:

[codesyntax lang=“text“ title=“HM Skript zum Setzen der digitalen Ausgänge auf HIGH „]

var url = "192.168.178.58/?setpin:2:3:4:5:6:7:8:9:";
!Stand 17.07.2014 ##############################
string stdout;
string stderr;
system.Exec("wget -q -O - '"#url#"'", &stdout, &stderr);
string arduino_xml = stdout;
!WriteLine(arduino_xml);
integer laenge = arduino_xml.Length();
boolean status = 0;
if (laenge == 0) {dom.GetObject("homeduino_fehler").State(true);quit;} !beenden , wenn laenge =0
dom.GetObject("homeduino_fehler").State(false);

[/codesyntax]

 

… und hiermit alle Pins D2 bis D9  auf 0 gesetzt:

[codesyntax lang=“text“ title=“HM Skript zum Setzen der digitalen Ausgänge auf LOW „]

var url = "192.168.178.58/?resetpin:2:3:4:5:6:7:8:9:";
!Stand 17.07.2014 ##############################
string stdout;
string stderr;
system.Exec("wget -q -O - '"#url#"'", &stdout, &stderr);
string arduino_xml = stdout;
!WriteLine(arduino_xml);
integer laenge = arduino_xml.Length();
boolean status = 0;
if (laenge == 0) {dom.GetObject("homeduino_fehler").State(true);quit;} !beenden , wenn laenge =0
dom.GetObject("homeduino_fehler").State(false);

[/codesyntax]

Das folgende  einfache WebUI-Testprogramm soll die Arbeitsweise beim Setzen und Rücksetzen der Pins verdeutlichen. Im Programm werden beispielsweise alle 2 min die beiden Skripte zeitversetzt aufgerufen, welche die Pins dann einschalten und nach 15 sec wieder  ausschalten.

 

Webui_toggle

 

6.2 Digitale Eingange abfragen
Das Einlesen  der digitalen Ports D2 bis D9 erfolgt per Browser mit dem Befehl …
<ip>/?readpin:2:5:6:8:          >> liest  Pins D2, D5, D6; D8  und zeigt den Status im Browser mit einer entsprechenden Meldung.

Für das Einlesen in die Homematic sind vorher entsprechende boolsche Systemvariable für jeden abzufragenden Port anzulegen. Im folgenden Beispiel sind dies …
homeduino_D6; homeduino_D7; homeduino_D8; homeduino_D9; und natürlich  homeduino_fehler

 

[codesyntax lang=“text“ title=“HM Skript zur Statusabfrage der digitalen Eingänge“]

var url = "192.168.178.58/?digitalin:6:7:8:9:";
!Stand 17.07.2014 ###################################
!hier ist die Abfrage mit system.Exec
string stdout;
string stderr;
system.Exec("wget -q -O - '"#url#"'", &stdout, &stderr);
string arduino_xml = stdout;
!WriteLine(arduino_xml);
 
integer laenge = arduino_xml.Length();
if (laenge == 0) {dom.GetObject("homeduino_fehler").State(true);quit;} !beenden , wenn laenge =0
dom.GetObject("homeduino_fehler").State(false);

while (laenge >38)
 { integer wort_position = arduino_xml.Find("D");
    arduino_xml = arduino_xml.Substr(wort_position+1, (laenge - wort_position-1));
    laenge = arduino_xml.Length();
    string daten = arduino_xml.Substr(0, 6);
    !WriteLine("daten:" + daten);
    string pin = arduino_xml.Substr(0,2);
    integer pinn = pin.ToInteger();
    pin = pinn.ToString();
    !WriteLine("pin:" + pin);
    string daten = arduino_xml.Substr(4, 2);
    !WriteLine("daten:" + daten);
    integer pegel = daten.ToInteger();
    boolean status = false;
    if (pegel > 0) {status = true;}
    pin = "homeduino_D" +pin;
    !WriteLine(pin);
    !WriteLine(status);
    dom.GetObject(pin).State(status);
 }

[/codesyntax]

 

6.3 Analoge Eingänge abfragen
Mit dem I/O-Shield können die verfügbaren sechs Analogeingänge des Homeduinos in drei analogen Betriebsarten verwendet werden. Die Einstellung erfolgt mit den Jumpern JP1 und JP2.
– kein Jumper gesetzt: Eingangsspannungsbereich ist 0 (000)  bis +5V (1023)
– JP1 gesetzt: 10KOhm-Pullup-Widerstand eingeschaltetet, so dass entsprechende Sensoren z.B. NTCs  verwendet werden können: Messbereich 0 bis +5V
– JP2 gesetzt: Eingangsspannungsbereich ist 0 (000)  bis +10V (1023)

Folie2

 

Das Einlesen  der analogen Eingänge A0  bis A5  erfolgt per Browser mit dem Befehl …
<ip>/?analogin:0:4:5:          >> liest  Pins A0;A4;A5  und zeigt den Wert  im Browser mit einer entsprechenden Meldung.

Für das Einlesen in die Homematic sind vorher entsprechende  Systemvariable vom Typ Zahl für jeden abzufragenden Eingang  anzulegen. Im folgenden Beispiel sind dies …
homeduino_A0; homeduino_A4; homeduino_A5;

[codesyntax lang=“text“ title=“HM Skript zum Einlesen der analogen Eingänge“]

var url = "192.168.178.58/?analogin:0:4:5:";
!###################################
!hier ist die Abfrage mit system.Exec
string stdout;
string stderr;
system.Exec("wget -q -O - '"#url#"'", &stdout, &stderr);
string arduino_xml = stdout;
!WriteLine(arduino_xml);
 
integer laenge = arduino_xml.Length();
if (laenge == 0) {quit;}                !beenden , wenn laenge =0
while (laenge >38)
 { integer wort_position = arduino_xml.Find("A");
    arduino_xml = arduino_xml.Substr(wort_position+1, (laenge - wort_position-1));
    laenge = arduino_xml.Length();
    string daten = arduino_xml.Substr(0, 6);
    !WriteLine("daten:" + daten);
    string pin = arduino_xml.Substr(0,2);
    integer pinn = pin.ToInteger();
    pin = pinn.ToString();
    !WriteLine("pin:" + pin);
    string daten = arduino_xml.Substr(4, 4);
    !WriteLine("daten:" + daten);
    integer pegel = daten.ToInteger();
    if (pegel >999 ) {pegel  = 999;}
    pin = "homeduino_A" +pin;
    !WriteLine(pin);
    !WriteLine(pegel);
    dom.GetObject(pin).State(pegel);
 }

[/codesyntax]

 

6.4 Analoge Eingänge mit einstellbarer Triggerschwelle

Für die Erkennung von wichtigen Ereignissen wie Rauchmeldungen oder Alarmmeldungen kann man eine zyklische Abfrage (z.B. jede Minute) durch die Homematic vergessen, weil die Reaktion sofort erfolgen muß. Deshalb sind schnelle Trigger- und Auslösemöglichkeiten extrem wichtig.
Beim Homeduino wurden deshalb für jeden analogen Eingang individell einstellbare HIGH- und LOW-Triggerschwellen programmiert, die bei Über- oder Unterschreiten per Direktzugriff die für jeden Analogeingang korrespondierende Systemvariable in der Homematic sofort setzt oder rücksetzt. Das hat riesige Vorteile , wenn man zum Beispiel analoge Sensoren hat, die bei Erreichen bestimmter Werte sofort eine Reaktion auslösen sollen. Ein analoger Regenmelder  oder  ein Rauchmelder wären solche Geräte.

Die Einstellung der Schaltschwellen kann nicht per Browserbefehl erfolgen , sondern im Homeduino Sketch.  Dazu wird das folgende Integer-Array entsprechend mit Werten eingestellt: (hier der betreffende Auszug aus dem Homeduino Sketch)

int schaltschwelle_high[]= {250,1023,1023,1023,1023,510};                      //Schaltschwelle High der Analogeingänge

int schaltschwelle_low[]= {200,0,0,0,0,100};                                                //Schaltschwelle  LOW der Analogeingänge

In dem Beispiel sind die Triggerschwellen für den Analogeingang AD0 auf die Werte   200 (LOW) und 250 (HIGH) eingestellt.  Das heißt, dass bei Eingangswerten kleiner 200 das Triggersignal LOW ist und bei Analogwerten größer 250 entsprechend HIGH ist. Die Analogeingänge 1 bis 4 haben in dem Besipiel mit den Werten 0 und 1023 die Triggerfunktion ausgeschaltet, weil das Analogsignal ja nicht kleiner als 0  und nicht größer als 1023 wird. Der Analogeingang AD5 hat die Triggerschwellen 100 bzw. 510.

Aber wie kommt nun das Triggersignal in die Homematic ??

Ganz einfach! Es werden nur für die Analogeingänge, welche die Triggerfunktionalität bekommen sollen, einfache logische Systemvariablen angelegt. Diese müssen die Namen haben  homeduino_a0  bis  homeduino_a5.
Ohne irgendwelche zusätzlichen Skripte werden diese Systemvariablen dann automatisch und sofort gesetzt oder zurückgesetzt, wenn die entsprechenden Triggerschwellen über- oder unterschritten werden.

Damit kann man nun nahezu verzugsfrei irgendwelche Aktoren schalten, wenn an den analogen Eingängen die Triggerschwellen überschritten werden. Hier ein einfaches Programm, das eine Lampe mit dem analogen Signal am Analogeingang A1 ein- oder ausschaltet:

WebUI_trigger


6.5 Analoges PWM-Signal ausgeben

Für manche Anwendungen benötigt man ein pulsweitenmoduliertes Signal (PWM) oder analoge Spannungen . Die Generierung von solchen PWM-Signalen ist mit demHomeduino sehr einfach möglich. An den digitalen Ausgängen kann das PWM-Signal abgefgriffen werden, um beispielsweise angeschlossene LEDs oder Lampen zu dimmen. Aber man kann mit diesem Signal auch variable Gleichpannungen erzeugen. Dazu ist ein einfacher geeignet dimensionierter Tiefpass (RC-Glied) notwendig, womit man eine analoge Ausgangsspannung von 0 bis 5V erzeugen kann. Abhängig von der Auslegung des RC-Gliedes ist ein hochohmiger nachfolgender Messverstärker zur Entkopplung notwendig.

Direkt mit dem Pulsweitensignal (PWM) lassen sich  Lampen oder LEDs modulieren bzw. dimmen. Die PWM-Frequenz ist etwa 500Hz!

Folie3

6.6 Temperaturmessung mit NTC
Eine Temperaturmessung mit einem Thermistor oder NTC-Widerstanssensor ist besonders einfach, weil keinerlei Zusatzbauteile in Verbindung mit dem I/O-Shield benötigt werden. Der Sensor sollte ein 10 kOhm-Typ sein. In Kombination mit dem mittels Jumper JP1 zugeschalteten Vorwiderstand von ebenfalls 10KOhm entsteht ein Spannungsteiler, dessen Spannung einem analogen Eingang zugeführt wird.

Die Berechnung der Temperatur in °C erfolgt im Homeduino mit der exponentellen Widerstandskurve des NTC-Widerstandes. Die dabei verwendeten Kennwerte und Rechenfunktionen sind dem zugehörigen Programmteil des Homeduino-Sketch  zu entnehmen. Für die typischen Standard-NTC-Sensoren sind meistens  keine Anpassungen notwendig.

Die verwendete Berechnungsformel ist :   tempNTC = (B_wert * Tn / ( B_wert + (Tn * log(Rt/Rn)))) -Tn ;  mit   B_wert = 3950; //aus dem Datenblatt des NTC

Folie12

Das Einlesen  der Temperaturen   erfolgt per Browser mit dem Befehl …
<ip>/?ntc_in:4:5:          >> liest  Temperaturen der NTCs an den Pins A4* und A5*  und zeigt den Temperaturwert Wert  im Browser mit einer entsprechenden Meldung.

Für das Einlesen in die Homematic sind vorher entsprechende  Systemvariable vom Typ Zahl für jeden abzufragenden Eingang  anzulegen. Im folgenden Beispiel sind dies …
homeduino_A4; homeduino_A5;

 

[codesyntax lang=“text“ title=“HM Skript zum Einlesen der Messwerte von NTC-Temperatursensoren“]

var url = "192.168.178.58/?ntc_in:4:5:";
!###################################
!hier ist die Abfrage mit system.Exec
string stdout;
string stderr;
system.Exec("wget -q -O - '"#url#"'", &stdout, &stderr);
string arduino_xml = stdout;
!WriteLine(arduino_xml);
 
integer laenge = arduino_xml.Length();
if (laenge == 0) {quit;}                !beenden , wenn laenge =0
while (laenge >38)
 { integer wort_position = arduino_xml.Find("A");
    arduino_xml = arduino_xml.Substr(wort_position+1, (laenge - wort_position-1));
    laenge = arduino_xml.Length();
    string daten = arduino_xml.Substr(0, 6);
    !WriteLine("daten:" + daten);
    string pin = arduino_xml.Substr(0,2);
    integer pinn = pin.ToInteger();
    pin = pinn.ToString();
    !WriteLine("pin:" + pin);
    string daten = arduino_xml.Substr(4, 5);
    !WriteLine("daten:" + daten);
    integer pegel = daten.ToFloat();
 
    pin = "homeduino_A" +pin;
    !WriteLine(pin);
    !WriteLine(pegel);
    dom.GetObject(pin).State(pegel);
 }

[/codesyntax]

 

6.7 Temperaturmessung mit 1Wire-Sensoren DS 18B20
Die 1-Wire-Sensoren von Dallas DS18B20 sind ideal für die Temperaturmessung, weil sie bereits kalibriert sind und eine digitale Temperaturinformation abgeben. Sie können einzeln an einen beliebigen digitalen Eingang geschaltet werden oder aber auch zu Gruppen bis 20(?) Sensoren parallelgeschaltet. Hierzu gibt es im Internet eine Vielzahl an Informationen, die hier aber nicht nochmal dargestellt werden müssen.  Erfahrungsmässig ist ein dreipoliger Anschluss der Sensoren (+5V, Masse, Signal) oft robuster und weniger störanfällig, als eine zweiadrige Sensorkopplung. Der  zweiadrige Betrieb ( plus und Masse zusammen geschaltetet)  funktioniert aber bei nicht allzu langen Leitungen auch ganz gut.  Die Sensoren können beliebig an alle verfügbaren  digitalen Ports D2 bis D9 angeschlossen werden.

Folie7

Die Software erkennt in dieser Betriebsart bei Abfrage mit dem Browser automatisch die Sensoradresse und gibt direkt den Temperaturwert aus. Ein Ermittlung der individuellen Sensoradresse ist in diesem Fall nicht notwendig. Wichtig ist das Zuschalten des 4k7-Pullup-Widerstandes mit den Jumpern  JP3 entsprechend dem verwendeten Dateneingang.

Das Einlesen  der Temperaturen   erfolgt per Browser mit dem Befehl …
<ip>/?1wire:2:3:          >> liest  Temperaturen der einzelnen 1-Wire Sensoren an den Pins D2 und D3 und zeigt den Temperaturwert (in °C) im Browser mit einer entsprechenden Meldung.

1wire_browser

Für das Einlesen in die Homematic sind vorher entsprechende  Systemvariable vom Typ Zahl für jeden abzufragenden Eingang  anzulegen. Im folgenden Beispiel sind dies …
homeduino_W2; homeduino_W3;

[codesyntax lang=“text“ title=“HM Skript“]

var url = "192.168.178.58/?1wire:2:3:";
!###################################
!hier ist die Abfrage mit system.Exec
string stdout;
string stderr;
system.Exec("wget -q -O - '"#url#"'", &stdout, &stderr);
string arduino_xml = stdout;
!WriteLine(arduino_xml);
 
integer laenge = arduino_xml.Length();
if (laenge == 0) {quit;}                !beenden , wenn laenge =0
while (laenge >38)
 { integer wort_position = arduino_xml.Find("T");
    arduino_xml = arduino_xml.Substr(wort_position+1, (laenge - wort_position-1));
    laenge = arduino_xml.Length();
    string daten = arduino_xml.Substr(0, 6);
    !WriteLine("daten:" + daten);
    string pin = arduino_xml.Substr(0,2);
    integer pinn = pin.ToInteger();
    pin = pinn.ToString();
    !WriteLine("pin:" + pin);
    string daten = arduino_xml.Substr(4, 5);
    !WriteLine("daten:" + daten);
    integer pegel = daten.ToFloat();
 
    pin = "homeduino_W" +pin;
    !WriteLine(pin);
    !WriteLine(pegel);
    dom.GetObject(pin).State(pegel);
 }

[/codesyntax]

Folie8

Möchte man mehrere 1Wire-Sensoren parallelschalten und an einen Port anschliessen,  dann muss vorher die Adresse jedes einzelnen Sensors bekannt sein oder ermittelt werden.  Die Ermittlung der Adresse eines oder mehrerer  Sensoren kann einfach per Befehlseingabe im Browser erfolgen:

<ip>/?1wire_address:5:              >> zeigt  im Browser die Adressen der 1Wire-Sensoren an Pin D5

1wire_address

Diese Informationen der einzelnen parallel geschalteten Sensoren  müssen dann in ein spezielles Datenfeld im Homeduino-Sketch eingetragen werden. Das Homeduino-Sketch ist für bis zu 10 Sensoren ausgelegt, die parallelgeschaltzet  an einem der Ports D2 bis D9 angeschlossen sind. Das folgende Beispiel zeigt ausschnittartig die Adressen meiner verwendeten 1Wire-Sensoren im HM-Skript:

[codesyntax lang=“text“]

OneWire oneWire(onewire_pin); 
DallasTemperature sensors(&oneWire);
DeviceAddress TempSensor[] = //Adress-Array definieren
{ 
 { 0x28, 0x37, 0x35, 0xB6, 0x05, 0x00, 0x00, 0x8D }, //<<user-eingabe<<
 { 0x28, 0xA5, 0x0A, 0xDD, 0x05, 0x00, 0x00, 0xBD }, //<<user-eingabe<< 
 { 0x28, 0x31, 0x60, 0xDD, 0x05, 0x00, 0x00, 0x7C }, //<<user-eingabe<<
 { 0x28, 0xA2, 0x4B, 0xB5, 0x05, 0x00, 0x00, 0x90 }, //<<user-eingabe<<
 { 0x10, 0xC7, 0xBA, 0xDD, 0x01, 0x08, 0x00, 0x52 }, //<<user-eingabe<<
 { 0x10, 0x8E, 0xB8, 0xDD, 0x01, 0x08, 0x00, 0x32 }, //<<user-eingabe<<
 { 0x10, 0xC7, 0xBA, 0xDD, 0x01, 0x08, 0x00, 0x52 }, //<<user-eingabe<<
 { 0x10, 0x8E, 0xB8, 0xDD, 0x01, 0x08, 0x00, 0x32 }, //<<user-eingabe<<
 { 0x10, 0xC7, 0xBA, 0xDD, 0x01, 0x08, 0x00, 0x52 }, //<<user-eingabe<<
 { 0x10, 0x8E, 0xB8, 0xDD, 0x01, 0x08, 0x00, 0x32 }, //<<user-eingabe<<
};

[/codesyntax]

Die Messung bzw. Abfrage der Temperaturen kann dann mit dem Browser mit folgendem Befehl erfolgen:

/?onewire:8:0:1:2:3:                       >> An Digitalpin D8 werden die 1-Wire Sensoren Nr.0 bis  Nr 3 eingelesen

und man erhält das folgende Ergebnis:

1wire_result

Für das Einlesen in die Homematic sind vorher entsprechende  Systemvariable vom Typ Zahl für jeden abzufragenden Sensor  anzulegen. Im folgenden Beispiel sind dies …

fehlt noch!

 

6.8 Infrarot-FB-Receiver (Fernbedienungscodes empfangen) , IR-Gateway

Die Realisierung einer Infrarot-Fernbedienung ist mit dem Homeduino besonders einfach. Man benötigt dafür lediglich einen IR-Empfänger, der als fertiges Modul schon alles Notwendige integriert hat. Leider gibt es auf dem Markt ein Unzahl von verschiedenen Codes und Trägerfrequenzen für die Modulation des IR-Signals. Aber meistens wird eine Trägerfrequenz von 38KHz verwendet, so dass entsprechende IR-Module sinnvollerweise für diese Frequenz ausgelegt sein sollten.
Ich habe den Typ HS0038B verwendet; der kostet weniger als 1 €. Aber es gibt noch eine Vielzahl von Alternativen, die sicher auch gut funktionieren. Immer aber die unterschiedliche Pinbelegung berücksichtigen !
Der Anschluss erfolgt über 3 Leitungen an das Homeduino-IO-Shield wie auf dem nachfolgenden Bild gezeigt.

Achtung: Nur der Eingang D2 ist hierfür geeignet !!

Folie11

 

Die Anbindung an die Homematic ist relativ einfach! Hier die Schritte:

1.  Dazu muß im Homeduino Sketch die IR-Funktion auch freigeschaltet sein. Hierzu wird die folgende Zeile  so verwendet :

boolean ir_enable = 1;   // 1 wenn ein ir-receiver an pin D2 verwendet wird

2.  Dann legt man in der Homematic die Systemvariable homeduino_ir vom Typ Zahl an

3.  Im Homeduino Sketch werden dann die IR-Codes abgelegt, die beim Empfang dann dekodiert werden und als Zahl sofort an die Systemvariable homeduino_ir übermittelt wird. Hier ist der betreffende Auszug aus dem Homeduino Sketch:

//Unterprogramm zur Befehlserkennung der IR-Signale
//
void ir_decode()
{switch(results.value)
{
case 1086165103: fb_key = 1; break;

case 1086128383: fb_key = 2; break;

case 1086161023: fb_key = 3; break;

case 1086144703: fb_key = 4; break;

case 1086177343: fb_key = 5; break;

case 1086136543: fb_key = 6; break;

case 1086169183: fb_key = 7; break;

case 1086152863: fb_key = 8; break;

case 1086185503: fb_key = 9; break;

case 1086132463: fb_key = 10; break;

// bis 254 Codes möglich

default: fb_key = 255;
}
fbkey = String(fb_key);

}

Die IR-Codes sind dezimal 10-stellige Zahlen, die jeweils einer Tastenkombination der IR-Fernbedienung zugeordnet ist. Ich habe in diesem Beispiel 10 Tasten programmiert, aber man kann bis über 200 Tasten programmieren. Aber wer will das schon 😉

Wie kommen wir nun an die IR-Codes meiner Fernbedienung(en) ??

Dazu  verwendet man einen Browser und benutzt den Befehl:

192.168.178.58/?ir_receive: >> An D2 auf IR-Signal 3s warten und IR-Telegramm anzeigen

Wenn die so ermittelten IR-Codes in das Homeduino Sketch eingetragen sind, kann man nun ganz einfach HM-Programme schreiben, um mit der IR-Fernbedienung beispielsweise eine Lampe zu schalten :

webUI_ir_fb

So kann man nun mehrere Fernbedienungen „anlernen“  und mit diesen dann alle möglichen Homematic-Funktionen genauso wie mit der HM-Fernbedienung schalten und walten .

6.9 Infrarot-LED-Transmitter (Fernbedienungscodes senden)

Umgekehrt möchte man vielleicht auch andere Geräte, die bisher nur mit einer IR-Fernbedienung eingeschaltet werden konnten, direkt über Infrarot von der Homematic steuern. Mit einer oder zwei Infrarot-LEDs geht das perfekt. Die Hardware muß entsprechend den beiden nächsten Bildern verschaltet werden und die LED auf den/die Empfänger gerichtet werden.

Folie10

Folie9

Wegen der Vielzahl von verschiedenen firmenspezifischen Normen ist das Aussenden eines IR-Signals zum Betätigen irgendwelcher Funktionen per Infrarot eine schwierige Angelegenheit. Die entsprechenden Sendecodes  mit Bitlänge kann man wie im Abschnitt vorher ermitteln  und kann dann entweder mit dem Browser und dem Befehl…

192.168.178.58/?ir_send:nec:1086136543:32    >> An D9 das IR-Telegramm 1086136543 mit 36 bit laenge  ausgeben

den IR-Code aussenden oder man macht dies aus der Homematic heraus mit einem HMSkript. Zusätzlich zu dem eigentlichen IR-Code sind noch Informationen des Herstellers (NEC funktioniert meistens) und die Länge des Senetelegramms (meistens 32 bit) in dem Befehl zu berücksichtigen. Am besten läßt sich der ausgesendet Code der individuellen Fernbedienung mit dem Hilfsprogramm IRrecvDump auf der seriellen Konsole ausgeben. Das Programm findet man bei den Beispielen unter IRremote. In diesem Programm zu Beginn die Pinnummer der IR-Receivers eintragen :   int RECV_PIN = 2;

Das zugehörige HM-Skript zum Aussenden eines IR-Codes ist einfach:

 

 

[codesyntax lang=“text“ title=“HM Skript zum Aussenden von IR-Codes“]

var url = "192.168.178.58/?ir_send:nec:1086136543:32:";
!Stand 29.07.2014 ##############################
string stdout;
string stderr;
system.Exec("wget -q -O - '"#url#"'", &stdout, &stderr);
string arduino_xml = stdout;
!WriteLine(arduino_xml);
integer laenge = arduino_xml.Length();
boolean status = 0;
if (laenge == 0) {dom.GetObject("homeduino_fehler").State(true);quit;} !beenden , wenn laenge =0
dom.GetObject("homeduino_fehler").State(false);

[/codesyntax]

 

 

6.10  „Unbekannte“ Infrarot-Signale  im RAW-Modus senden und empfangen

verwendete Befehle:   ir-rawstore und ir_rawsend

 

Beschreibung fehlt noch

 

 

 

6.11  Drahtlose Funkfernbedienung  ( u.a. zur Ansteuerung von Funkschaltsteckdosen )
Für TV und Multimedia mit direkter Sichtverbindung zwischen Bediener  und Gerät sind natürlich IR-Fernbedienungen die erste Wahl. Für die drahtlose Steuerung von Steckdosen , Lampen etc werden aber fast nur funkgesteuerte Fernbedienungen (meist 433MHz) verwendet. Dafür gibt es im Internet äusserst preiswerte Empfänger und Sender , die entsprechend den folgenden Bildern an das Homeduino-IO-Shield angeschaltet werden. (Weltweit Suchen bei ebay nach „rf receiver transmitter arduino“) . Ein komplettes Kit bestehend aus Empfänger und Sender kostet nur ungefähr 1.50 € !!

Entsprechend der beiden nächsten Bilder werden Empfänger und Sender angeschlossen. Und natürlich muß im Homeduino Sketch auch diese Funktion freigeschaltet sein mit:

boolean rf_enable = 1;                 // 1 wenn ein rf-receiver an pin D3 verwendet wird

Folie5

Folie4

Die Programmierung erfolgt analog zur Programmierung der IR-Fernbedienung . Die sog. RF-Codes werden ermittelt  mit dem Browserbefehl:

192.168.178.58/?rf_receive:           >> An D3 auf rf-Signal 3s warten und RF-Telegramm anzeigen

Diese  RF-Codes werden dann eingetragen in das Homeduino Sketch:

//Unterprogramm zur Befehlserkennung der IR-Signale
//
void ir_decode()
{switch(results.value)
{
case 1086165103: fb_key = 1; break;

case 1086128383: fb_key = 2; break;

case 1086161023: fb_key = 3; break;

case 1086144703: fb_key = 4; break;

case 1086177343: fb_key = 5; break;

case 1086136543: fb_key = 6; break;

case 1086169183: fb_key = 7; break;

case 1086152863: fb_key = 8; break;

case 1086185503: fb_key = 9; break;

case 1086132463: fb_key = 10; break;

// bis 254 Codes möglich

default: fb_key = 255;
}
fbkey = String(fb_key);

}

In der Homematic wird nun eine Systemvariable homeduino_rf vom Type Zahl angelegt, die den empfangenen Code mit der entsprechenden Zahl signalisiert.

Das WebUI-Programm zur Steuerung von Lampen etc. ist genauso wie bei der IR-Fernbedienung.

Auch die Aussendung von RF-Codes zur Ansteuerung von Funksteckdosen erfolgt genauso wie oben beim Infrarot schon beschrieben.

 

6.12 Ultraschall-Enfernungsmessung

Beschreibung fehlt noch!

Folie6

6.13 LCD-Display mit I2C

Funktion schon integriert. Beschreibung fehlt noch!  Befehle  dafür:  display

 

6.14  Barometer Sensor BMP 180

Funktion schon integriert. Beschreibung fehlt noch!  Befehle  dafür:  barometer

 

 

7  Bauanleitung  für das universelle I/O-Shield

Mittlerweile gibt es ein verbessertes neues I/O-Anschluss-Board mit großenteils fertiggestellter Platine.
Beschreibung hier: https://www.stall.biz/?project=vielseitiges-io-shield-board-2-0-fur-fast-alle-arduinos

Kauf-Interessierte können mich  per email (Kontakt -Button)  ansprechen.
Der Teil-Bausatz kostet 26€ plus 3,90€ Versand nach Deutschland.

Haftungs- und Sicherheitshinweise

Beim Nachbau müssen natürlich alle wichtigen einschlägigen Sicherheitsvorschriften für den Umgang mit gefährlichen Spannungen  eingehalten werden. Fundierte theoretische und praktische Fachkenntnisse der Elektrotechnik und für den Umgang mit gefährlichen Spannungen sind unverzichtbar!!

Durch eine unsachgemäße Installation gefährden Sie ihr Leben und das Leben ihrer Mitmenschen! Darüberhinaus riskieren Sie erhebliche Sachschäden , welche durch Brand etc. hervorgerufen werden können ! Für alle Personen- und Sachschäden durch falsche Installation etc. ist nicht der Hersteller sondern nur der Betreiber verantwortlich.

Ich verweise hier unbedingt auf  die  „Sicherheitshinweise und Haftungsausschluss„-Seite dieses Blogs.

 

 

 

 

 

 

 

 

Skills

Posted on

14. September 2014