Wohnzimmer Steuerung mit Arduino und MQTT

Ich habe vor einiger Zeit mal angefangen den Arduino Mega und das Ethernet Shield von Sainsmart zu einem kleinen Controller für das Wohnzimmer aufzubauen. Es soll zum Schluss folgende aufgaben übernehmen:

  • Schalten von 434 Mhz Funk-Schalt Steckdosen
  • Ansteuerung einer kleinen RGB-LED leiste für die Vitrine (meine alte Dioder Leiste)
  • Senden von IR-Signalen
  • Messen der Temperatur im Raum

Dazu hatte ich alle Komponenten einzeln getestet und mit kleinen versuche die einzelnen Bibliotheken kennen gelernt. Für den Bestellten 434 Mhz Sender verwende ich die RC-Switch Bibliothek. Um die IR-Signale zu senden benutze ich die erweiterte IR-Bibliothek CY´s IRib. Das Messen der Temperaturen erfolgt durch die Dallas Temperature Control Bibliothek wie schon in meinen anderern Beiträgen. Die RGB-Leiste steuere ich über die PWM PINs des Arduino selber. Für die Steuerung verwende ich die MQTT PubSubClient Bibliothek. Die Verwendung von MQTT und dem Arduino hatte ich auch schon früher Beschrieben.

Der Aufbau

Für die ersten Tests hatte ich am Anfang alles auf einem Steckbrett getestet. Der Aufbau ist für jede Funktion weiter gewachsen.

image-385

434 Mhz Empfänger

Der Empfänger ist extra am 12v des Netzteils angeschlossen. Der Sender darf laut Datenblatt an 1,5V – 12V betrieben werden. Am Anfang hatte ich den Sender an 5V aber an 12V ist die Sendeleistung wesentlich besser und die Funksteckdosen schalten zuverlässiger. Am Arduino ist der Dateneingang an PIN 40.

IR-LIB

Die Infrarot Diode ist von meiner alten Microsoft MCE Fernbedienung. Am USB-Empfänger waren kleine IR-Dioden für das schalten eines Satelliten Receivers dabei. Es sind aber auch andere IR-Dioden möglich. Man findet zu den Dioden und den Aufbau der Schaltung auf der Seite der Bibliothek sehr gute Anleitungen.
Am Arduino MEGA verwende ich den PIN 46. Dieser ist nicht frei wählbar, den er ist von den verwendeten Timer abhängig. Am besten guckt man im Ordner der IRLib Bibliothek nach der Datei “IRLibTimer.h”. Wenn man diese mit einem Texteditor öffnet findet man Abfragen zum Typ des Boards. Innerhalb der Sektionen der Boards kann man den PIN bzw. den dazugehörigen Timer wählen. Wenn man mehrere Bibliotheken in Verwendung hat die einen Timer benötigen, ist es sehr wichtig das man unterschiedliche Timer benutzt. Ich verwende Timer5 und muss deswegen PIN 46 benutzen.

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
//#define IR_SEND_TIMER1 11
//#define IR_SEND_TIMER2 9
//#define IR_SEND_TIMER3 5
//#define IR_SEND_TIMER4 6
#define IR_SEND_TIMER5 46

Mann muss ein wenig aufpassen den wenn man den Timer ändert, wird dieser für ein anderes Sketch auch verwendet.

Beim Anschluss habe ich erst eine Transistorschaltung vor der Diode um die Leistung zu erhöhen. Dies hat aber in Zusammenhang mit der LED-Leiste zu einer hohen Last geführt und der Arduino hat sich aufgehängt. Deswegen habe ich die Diode ohne Vorwiderstand direkt angeschlossen. Die genaue Schaltung im Kopf der Diode kenne ich nicht und mit Vorwiderstand war das senden der Befehle erfolgreich. Eine normale IR-Diode braucht sicher ein Vorwiderstand.

Temperatur Sensoren

Die Temperatur Sensoren sind wie in meinen anderen Beiträgen angeschlossen. Am MEGA verwende ich aber PIN 33.

RGB LED

Beim RGB LED Strip habe ich mich an den Aufbau wie bei meinem Nachtlicht gehalten. Die Stromversorgung kommt auch von einem externen 12V Netzteil. Die 12V werden über drei STP16NF06 MOSFETs gesteuert. Sehr gute Beschreibungen findet man im Internet. Der Aufbau ist oft ein wenig anders, je nachdem wie die Eingänge geschaltet werden. Ich habe jeden Eingang mit eine 10kOhm Widerstand an Messe gelegt. Dadurch ist  der Eingang immer auf “LOW”, bis ich den Eingang mit dem Arduino schalte. Dieser Aufbau funktionierte für mich am besten und zuverlässigsten
Hierbei sei nochmals drauf hingewiesen das die meisten Schaltungen nicht von mir kommen und ich auch keine Garantie auf Richtigkeit gebe. Alles ist auf eigene Gefahr. Generell habe ich im Internet viele Schaltungen gefunden, die fehlerhaft waren oder einfach kleine Fehler im Aufbau haben. Dabei zerstört man leicht Bausteine.

Einbau im Gehäuse

Danach habe ich alles in ein kleines Gehäuse gebaut, damit es geschützt ist. Die Anschlüsse sind alle über Molex Stecker ausgeführt.

Software

openHAB Items

Number wzGrad1 "Temperatur 1 [%.1f °C]" <temperature> (gWohnzimmer) {mqtt="<[localbroker:/openHAB/wzGrad1:state:default]"}
Number wzGrad2 "Temperatur 2 [%.1f °C]" <temperature> (gWohnzimmer) {mqtt="<[localbroker:/openHAB/wzGrad2:state:default]"}

Switch LGTV_Power "Power" <power> (gLGTV) { mqtt=">[localbroker:/openHAB/wzIR/NEC32:command:ON:551494620],>[localbroker:/openHAB/wzIR/NEC32:command:OFF:551527260]" }
String LGTV_Input "Eingang" <input> (gLGTV) { mqtt=">[localbroker:/openHAB/wzIR/NEC32:command:TV:551512980],>[localbroker:/openHAB/wzIR/NEC32:command:HDMI1:551515020],

Color  wzVitrine "TV Vitrinenlicht" <slider> (gVitrine)
Dimmer wzVitrine_All "Helligkeit [%d %%]" <switch> (gVitrine)
Dimmer wzVitrine_R "Rot [%d %%]" <switch> (gVitrine) {mqtt=">[localbroker:/openHAB/wzVitrine/RED:state:*:default]"}
Dimmer wzVitrine_G "Grün [%d %%]" <switch> (gVitrine) {mqtt=">[localbroker:/openHAB/wzVitrine/GREEN:state:*:default]"}
Dimmer wzVitrine_B "Blau [%d %%]" <switch> (gVitrine) {mqtt=">[localbroker:/openHAB/wzVitrine/BLUE:state:*:default]"}

openHAB RGB-LED Regel

import org.openhab.core.library.types.*

var HSBType hsbValue
var int redValue
var int greenValue
var int blueValue
var String RGBvalues

rule Startup
 when
   System started
 then
   redValue = 0
   greenValue = 0
   blueValue = 0

   postUpdate(wzVitrine_R, redValue)
   postUpdate(wzVitrine_G, greenValue)
   postUpdate(wzVitrine_B, blueValue)
   postUpdate(wzVitrine, OFF)
 end

rule "Set wzVitrine value"
 when
   Item wzVitrine changed
 then
   hsbValue = wzVitrine.state as HSBType 

   redValue = hsbValue.red.intValue
   greenValue = hsbValue.green.intValue
   blueValue = hsbValue.blue.intValue

   postUpdate(wzVitrine_R, redValue)
   postUpdate(wzVitrine_G, greenValue)
   postUpdate(wzVitrine_B, blueValue)

   RGBvalues= "Values" + redValue.toString + ";" + greenValue.toString + ";" + blueValue.toString
   logInfo( "wzVitrine", RGBvalues )
 end

Arduino Sketch

Der Arduino Sketch ist im moment immer noch in Bearbeitung. Anbei mein aktueller Stand.


#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

#include <RCSwitch.h>

#include <OneWire.h>
#include <DallasTemperature.h>

#include <IRLib.h>

// debug = 1 Schlatet die Serielle ausgabe ein.
int debug = 0;

// --------------------------------
// Ethernet Server
// http://arduino.cc/de/Reference/Ethernet
// --------------------------------
// MAC Adresse des Ethernet Shields
byte ethMac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x33, 0xE5 };
EthernetClient ethClient;

// --------------------------------
// MQTT Client
// http://knolleary.net/arduino-client-for-mqtt/
// --------------------------------
byte MQTTserver[] = { 192, 168, 2, 9 };
PubSubClient MQTTClient(MQTTserver, 1883, callback, ethClient);

// --------------------------------
// LED Leiste
// --------------------------------
// Pins des RGB LED Strip
int LEDredPIN=5;
int LEDgreenPIN=6;
int LEDbluePIN=3;

// Übermittelte Farbwerte
int LEDredValue = 0;
int LEDgreenValue = 0;
int LEDblueValue = 0;

// Gerade gesetzte Farbe
int LEDredCurrent = 0;
int LEDgreenCurrent = 0;
int LEDblueCurrent = 0;

// Timervariable für eine Verzögerung. Als alternative zu delay was die verarbeitung anhält.
int LEDtimer = 0;
int LEDendTimer = 50; 

// --------------------------------
// RC-Switch
// https://code.google.com/p/rc-switch/
// --------------------------------
RCSwitch RCsender = RCSwitch();
String rcID = ""; // Übermittelte ID
String rcCommand = ""; // Übermittelter Befehl
char rcID1[6]; // ID erster Teil
char rcID2[6]; // ID zweiter Teil

// --------------------------------
// Infrarot
// http://tech.cyborg5.com/2013/03/14/irlib-tutorial-part-1-hardware-set-up/
// Timer PINs Übersicht http://playground.arduino.cc/Main/TimerPWMCheatsheet
// Timer setzen für MEGA 2560 in IRLibTimer.h - #define IR_SEND_TIMER5 46
// --------------------------------
IRsend My_Sender;
int IRprot = 0;
long IRcode = 0;
int IRbit = 0;

// --------------------------------
// Temperatur
// http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
// http://www.pjrc.com/teensy/td_libs_OneWire.html
// --------------------------------
#define ONE_WIRE_BUS 33
OneWire oneWire(ONE_WIRE_BUS);

#define TEMPERATURE_PRECISION 9
DallasTemperature sensors(&oneWire);
DeviceAddress TEMPDeviceAddress; // Variable zum zwischenspeichern der Adresse eines Sensors
unsigned long TEMPtimer;
unsigned long TEMPendTimer = 300000; // Schleifendurchläufe bis neue Abfrage startet
float TEMPSensor1 = 0;
float TEMPSensor2 = 0;
char TEMPChar[10]; // Hilsfvariable zu Konvertierung
String TEMPAsString; // Ausgelesene Temperatur als String
int TEMPDeviceCount = 0;

//================================================================================================================
void setup()
//================================================================================================================
{

 if (debug == 1) {
 Serial.begin(9600);
 Serial.println("Wohnzimmer 2.04");
 }

// --------------------------------
// LED Leiste
// --------------------------------
 // Setzen der PINS als Ausgang
 pinMode(LEDbluePIN, OUTPUT);
 pinMode(LEDredPIN, OUTPUT);
 pinMode(LEDgreenPIN, OUTPUT);

 // Bei start Farbe Blau setzen
 analogWrite(LEDredPIN, 0);
 analogWrite(LEDgreenPIN, 0);
 analogWrite(LEDbluePIN, 10);

// --------------------------------
// Ethernet Server
// --------------------------------
 // Initialisierung des Ethernets
 if (Ethernet.begin(ethMac) == 0) {
 // Wenn DHCP fehlschlägt dann rot setzen und aufhören
 analogWrite(LEDredPIN, 100);
 analogWrite(LEDgreenPIN, 0);
 analogWrite(LEDbluePIN, 0);
 while (true);
 }
 else {
 // Wenn DHCP OK ist dann grün setzen
 LEDgreenValue = 10;

 if (debug == 1) {
 Serial.print("IP-Adresse:");
 Serial.println(Ethernet.localIP());
 }

 }

// --------------------------------
// RC-Switch
// --------------------------------
 RCsender.enableTransmit(40);
 RCsender.setRepeatTransmit(15);

// --------------------------------
// Temperatur
// --------------------------------
 sensors.begin();
 TEMPDeviceCount = sensors.getDeviceCount();
 TEMPtimer = TEMPendTimer + 1;

 for(int i=0 ; i < TEMPDeviceCount; i++) {
 if(sensors.getAddress(TEMPDeviceAddress, i)) {
 sensors.setResolution(TEMPDeviceAddress, TEMPERATURE_PRECISION);
 }
 }

 if (debug == 1) {
 Serial.print("Temperatur Sensoren: ");
 Serial.println(TEMPDeviceCount, DEC);
 }

} // void setup()

//================================================================================================================
void loop()
//================================================================================================================
{
// --------------------------------
// MQTT Client
// --------------------------------
 // Aufbau der Verbindung mit MQTT falls diese nicht offen ist.
 if (!MQTTClient.connected()) {
 MQTTClient.connect("arduinoWZVitrine");
 // Abonieren von Nachrichten mit dem angegebenen Topics
 // MQTTClient.subscribe("/openHAB/wzVitrine/RED/#");
 // MQTTClient.subscribe("/openHAB/wzVitrine/GREEN/#");
 // MQTTClient.subscribe("/openHAB/wzVitrine/BLUE/#");
 MQTTClient.subscribe("/openHAB/wzVitrine/#");

 // RC Steckdosen Commands
 MQTTClient.subscribe("/openHAB/wzRC/#");

 // IR Signale
 // http://192.168.2.21/ir&1&551494620&32
 MQTTClient.subscribe("/openHAB/wzIR/NEC32/#");

 }

// --------------------------------
// LED Leiste
// --------------------------------
 if (LEDtimer <= LEDendTimer) LEDtimer++;
 else {
 LEDtimer = 0;

 if (LEDredValue < LEDredCurrent) LEDredCurrent--;
 else if (LEDredValue > LEDredCurrent) LEDredCurrent++;

 if (LEDgreenValue < LEDgreenCurrent) LEDgreenCurrent--;
 else if (LEDgreenValue > LEDgreenCurrent) LEDgreenCurrent++;

 if (LEDblueValue < LEDblueCurrent) LEDblueCurrent--;
 else if (LEDblueValue > LEDblueCurrent) LEDblueCurrent++;
 }

 analogWrite(LEDredPIN, LEDredCurrent);
 analogWrite(LEDgreenPIN, LEDgreenCurrent);
 analogWrite(LEDbluePIN, LEDblueCurrent);

// --------------------------------
// RC Steckdosen
// --------------------------------

 if (rcID.length() == 10) {
 if (debug == 1) {
 Serial.println("ID : " + rcID);
 }
 rcID.toCharArray(rcID1,6);
 rcID = rcID.substring(5,10);
 rcID.toCharArray(rcID2,6);

 if (rcCommand == "ON") RCsender.switchOn(rcID1, rcID2);
 if (rcCommand == "OFF") RCsender.switchOff(rcID1, rcID2);
 rcID = "";
 } // if (rcID.length() == 10)

// --------------------------------
// Infrarot
// --------------------------------
// IRprot = 1; IRbit = 32; IRcode = msgString.toInt();
 if (IRprot > 0 && IRbit > 0 && IRcode > 0) {
 if (debug == 1) {
 Serial.println("IRpro: " + String(IRprot));
 Serial.println("IRbit: " + String(IRbit));
 Serial.println("IRcode: " + String(IRcode));
 }
 My_Sender.send(IRprot, IRcode, IRbit);
 IRprot = 0;
 IRbit = 0;
 IRcode = 0;
 }
// 

// --------------------------------
// Temperatur
// --------------------------------
 if (TEMPtimer <= TEMPendTimer) TEMPtimer++;
 else {
 TEMPtimer = 0;
 sensors.requestTemperatures();

 if ( TEMPDeviceCount >= 1 ) {
 TEMPSensor1 = sensors.getTempCByIndex(0);
 dtostrf(TEMPSensor1,1,2,TEMPChar);
 MQTTClient.publish("/openHAB/wzGrad1",TEMPChar);
 if (debug == 1) {
 TEMPAsString = String(TEMPChar);
 Serial.println("Temp1: " + TEMPAsString);
 }
 } // TEMPSensor 1

 if ( TEMPDeviceCount >= 2 ) {
 TEMPSensor2 = sensors.getTempCByIndex(1);
 dtostrf(TEMPSensor2,1,2,TEMPChar);
 MQTTClient.publish("/openHAB/wzGrad2",TEMPChar);
 if (debug == 1) {
 TEMPAsString = String(TEMPChar);
 Serial.println("Temp2: " + TEMPAsString);
 }
 } // TEMPSensor 2

 } // else TEMPtimer

// --------------------------------
// MQTT Client Loop
// --------------------------------
 MQTTClient.loop(); // Schleife für MQTT

}

//================================================================================================================
// Callback Funktion von MQTT. Die Funktion wird aufgerufen
// wenn ein Wert empfangen wurde.
//================================================================================================================
void callback(char* topic, byte* payload, unsigned int length) {

 TEMPtimer = 0; // Wenn eine Nachricht kommt wird der Timer
 // für die Temperatur auf 0 gesetzt um den Ablauf nicht zu Verzögern

 // Zähler
 int i = 0;
 // Hilfsvariablen für die Convertierung der Nachricht in ein String
 char message_buff[100];

 // Kopieren der Nachricht und erstellen eines Bytes mit abschließender \0
 for(i=0; i<length; i++) {
 message_buff[i] = payload[i];
 }
 message_buff[i] = '\0';

 // Konvertierung der nachricht in ein String
 String msgString = String(message_buff);
 String topString = String(topic);

 if (debug == 1) {
 Serial.println("Topic: " + topString);
 Serial.println("Msg : " + msgString);
 }

 // --------------------------------
 // LED Leiste
 // --------------------------------
 // Überprüfung des Topics und setzen der Farbe je nach übermittelten Topic
 if (topString == "/openHAB/wzVitrine/RED") LEDredValue = round(msgString.toInt() * 2.55);
 if (topString == "/openHAB/wzVitrine/GREEN") LEDgreenValue = round(msgString.toInt() * 2.55);
 if (topString == "/openHAB/wzVitrine/BLUE") LEDblueValue = round(msgString.toInt() * 2.55);

 // --------------------------------
 // RC Steckdose
 // --------------------------------
 // Wenn das Topic mit "/openHAB/wzRC/" anfängt dann ID und Message ermitteln und schalten
 if (topString.startsWith("/openHAB/wzRC/")) {
 rcID = topString.substring(topString.lastIndexOf('/') + 1);
 rcCommand = msgString;
 } // if (topString.startsWith("/openHAB/wzRC/"))

// --------------------------------
// Infrarot
// --------------------------------
//Topic: /openHAB/wzIR/NEC32
//Msg : 551494620
 if (topString.startsWith("/openHAB/wzIR/")) {
 if (topString.substring(topString.lastIndexOf('/') + 1) == "NEC32") {
 IRprot = 1;
 IRbit = 32;
 IRcode = msgString.toInt();
 }
 }

} // void callback(

One Comment

  1. Pingback: Mit HUZZAH(ESP8266) und MQTT eine 433MHz Steckdose schalten – Blue-PC

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

58 − = 55