Arduino Projekt: Funksteckdose steuern

Eine Funksteckdose wird meist mit einer Fernbedienung ausgeliefert. Wie man eine Funksteckdose mit einem Wemos D1 mini steuert und die Steckdose in das Intranet / Internet einbindet möchte ich in diesem Tutorial erläutern.

Funksteckdose mit Fernbedienung.
Funksteckdose mit Fernbedienung.

Hinweis : Die Steckdose selbst gibt 230V an Spannung aus, dieses ist gefährlich und kann zu schweren Verletzungen führen.
Daher bleibt das Gehäuse von einer Erweiterung unberührt.

 

Den Wemos D1 mini habe ich gleichnamigen Tutorial WEMOS D1 Mini – Übersicht ausführlich behandelt.

WEMOS D1 Mini
WEMOS D1 Mini

Ziel

Das Ziel dieses Tutorials soll es sein eine Funksteckdose mit einem Arduino anzusteuern (an / aus). Dazu soll in der ersten Ausbaustufe ein Taster mit Pulldown Widerstand die Steckdose An und Aus schalten. In der zweiten Ausbaustufe soll dieses über eine Webseite gelöst werden. Diese Webseite kann man je nach vorhandener Infrastruktur in das Internet einbinden.

Benötigte Komponenten

Für einen „fliegenden“ Aufbau benutze ich gerne Breadboards diese gibt es in verschiedenen Größen und haben den Vorteil das der Aufbau ohne Löten zu erledigen ist.

  • min. 1 Funksteckdose (mit Fernbedienung),
  • 433 MHz Sender & Empfänger,
  • 400 PIN Breadboard ,
  • Breadboardkabel,
  • Wemos D1 mini

433 MHz Sender & Empfänger

Der 433MHz Sender & Empfänger Modul besteht aus zwei Modulen.

433MHz Sender & Empfänger
433MHz Sender & Empfänger

Wie diese beiden Module funktionieren habe ich im Tutorial Arduino Tutorial 37: 433 MHz Sender & Empfänger beschrieben.

Benötigte Bibliothek

Für die Entwicklung des Sketches verwende ich die Bibliothek RCSwitch welche vom Git Repository des Entwicklers geladen werden kann.

Wie man diese Bibliothek in die Arduino IDE einbindet habe ich unter Arduino IDE, Einbinden einer Bibliothek erläutert.

Ermitteln der benötigten Daten von der Funksteckdose

Bevor man nun die Funksteckdose in den Zustand „an“ bzw. „aus“ versetzen kann muss man erst einmal die Daten auslesen. Dazu wird ein 433 MHz Empfänger benötigt.

Quellcode

Den nachfolgenden Sketch habe ich von den Beispielen der Bibliothek übernommen und aus den zwei Dateien in eine zusammengefasst.

#include <RCSwitch.h>

RCSwitch rcSwitch = RCSwitch();

void setup() {
  Serial.begin(9600);
  rcSwitch.enableReceive(0);  // Receiver on interrupt 0 => that is pin #2
}

void loop() {
  if (rcSwitch.available()) {
  Serial.println("<--- Beginn");
  output(rcSwitch.getReceivedValue(), rcSwitch.getReceivedBitlength(), rcSwitch.getReceivedDelay(), rcSwitch.getReceivedRawdata(),rcSwitch.getReceivedProtocol());
  rcSwitch.resetAvailable();
  Serial.println("<--- End");
  Serial.println();
  }
}


static const char* bin2tristate(const char* bin);
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength);

void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) {

  const char* b = dec2binWzerofill(decimal, length);
  Serial.print("Decimal: ");
  Serial.print(decimal);
  Serial.print(" (");
  Serial.print(length);
  Serial.println(" Bit)");
  Serial.print("Binary: ");
  Serial.println(b);
  Serial.print("Tri-State: ");
  Serial.println(bin2tristate( b));
  Serial.print("PulseLength: ");
  Serial.print(delay);
  Serial.println(" microseconds");
  Serial.print("Protocol: ");
  Serial.println(protocol);
  
  Serial.println("Raw data: ");
  Serial.print("\t");
  for (unsigned int i=0; i<= length*2; i++) {
    Serial.print(raw[i]);
    Serial.print(",");
    if(i!= 0 && (i%5)==0){
       Serial.println();
       Serial.print("\t");
    }
  }
  Serial.println();
}

static const char* bin2tristate(const char* bin) {
  static char returnValue[50];
  int pos = 0;
  int pos2 = 0;
  while (bin[pos]!='\0' && bin[pos+1]!='\0') {
    if (bin[pos]=='0' && bin[pos+1]=='0') {
      returnValue[pos2] = '0';
    } else if (bin[pos]=='1' && bin[pos+1]=='1') {
      returnValue[pos2] = '1';
    } else if (bin[pos]=='0' && bin[pos+1]=='1') {
      returnValue[pos2] = 'F';
    } else {
      return "not applicable";
    }
    pos = pos+2;
    pos2++;
  }
  returnValue[pos2] = '\0';
  return returnValue;
}

static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
  static char bin[64]; 
  unsigned int i=0;

  while (Dec > 0) {
    bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
    Dec = Dec >> 1;
  }

  for (unsigned int j = 0; j< bitLength; j++) {
    if (j >= bitLength - i) {
      bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
    } else {
      bin[j] = '0';
    }
  }
  bin[bitLength] = '\0';
  
  return bin;
}

Ausgabe auf dem seriellen Monitor

Wenn das oben genannte Sketch auf dem Arduino hochgeladen wurde, so kann man nun beim betätigen der Taste auf der Fernbedienung folgenden Inhalt auf dem seriellen Monitor auslesen.

Daten beim einschalten der Funksteckdose:

<--- Beginn
Decimal: 83029 (24 Bit)
Binary: 000000010100010001010101
Tri-State: 000FF0F0FFFF
PulseLength: 359 microseconds
Protocol: 1
Raw data: 
	11144,284,1140,296,1140,288,
	1144,284,1144,288,1136,
	304,1124,300,1132,1008,
	424,1004,428,1000,424,
	1004,432,992,432,996,
	436,1000,440,276,1148,
	288,1140,280,1156,996,
	428,280,1148,1008,428,
	280,1140,232,1772,660,
	1360,72,2776,
<--- End

Daten beim ausschalten der Funksteckdose:

<--- Beginn
Decimal: 83028 (24 Bit)
Binary: 000000010100010001010100
Tri-State: 000FF0F0FFF0
PulseLength: 358 microseconds
Protocol: 1
Raw data: 
	11144,300,1128,308,1124,304,
	1124,304,1128,304,1132,
	308,1120,1012,420,1016,
	408,1016,408,1020,420,
	1012,432,988,428,1012,
	416,996,444,276,1144,
	292,1144,284,1144,1000,
	420,296,1140,1004,432,
	284,1140,1004,432,284,
	1136,1008,436,
<--- End

Es gibt nun 2 Möglichkeiten die Funksteckdose mit den emfangenen Daten zu steuern.

Tri-State

Mit dem Hexadezimalen Wert „Tri-State“, der Pulse Länge sowie dem Wert für Protokoll kann man die Funksteckdose wiefolgt steuern:

#include <RCSwitch.h>
RCSwitch rcSwitch = RCSwitch();

const int senderPin = 15;  // An Pin 15
const int protocol = 1;
const int pulseLength = 358;
const int wait = 1000;

void setup() {
  rcSwitch.enableTransmit(senderPin);
  rcSwitch.setPulseLength(pulseLength);
  rcSwitch.setProtocol(protocol);
}

void loop() {
  rcSwitch.sendTriState("000FF0F0FFFF");
  delay(wait);

  rcSwitch.sendTriState("000FF0F0FFF0");
  delay(wait);
}

Binär

Bei einigen Funksteckdosen wird der Wert „Tri-State“ nicht ausgegeben daher muss dann auf den Binären Wert zurückgegriffen werden. Dazu wird die Funktion „rcSwitch.send(<<BINARY_WERT>>);“ statt „rcSwitch.sendTriState(<<TRI_STATE_WERT>>);“ verwendet.

#include <RCSwitch.h>
RCSwitch rcSwitch = RCSwitch();

const int senderPin = 15;  // An Pin 15
const int protocol = 1;
const int pulseLength = 358;
const int wait = 1000;

void setup() {
  rcSwitch.enableTransmit(senderPin);
  rcSwitch.setPulseLength(pulseLength);
  rcSwitch.setProtocol(protocol);
}

void loop() {
  rcSwitch.send("000000010100010001010101"); 
  //rcSwitch.sendTriState("000FF0F0FFFF");
  delay(wait);

  rcSwitch.send("000000010100010001010100");
  //rcSwitch.sendTriState("000FF0F0FFF0");
  delay(wait);
}

Ausbaustufe I – „einfach“

In der Ausbaustufe I möchte ich nun einen einfachen Taster (mit Pulldown Widerstand) an den Wemos D1 mini anschließen um dann auf Tastendruck die Funksteckdose ein bzw. aus zuschalten.

433MHz Funksender mit Taster am Wemos D1 mini.
433MHz Funksender mit Taster am Wemos D1 mini.

Schaltung

Der Aufbau der Schaltung änder sich nur gering da hier der Taster mit Pulldown Widerstand hinzugefügt wird.

Aufbau der Schaltung, Ausbaustufe I mit Taster auf dem Breadboard.
Aufbau der Schaltung, Ausbaustufe I mit Taster auf dem Breadboard.

Video

Arduino - 433MHz Funksteckdose steuern "Ausbaustufe 1"

Quellcode

#include <RCSwitch.h>
RCSwitch rcSwitch = RCSwitch();

const int btnUp = 13; //Taster auf PIN 13
int statusBtn = 0;

const int senderPin = 15;  // An Pin 15
const int protocol = 1;
const int pulseLength = 358;
const int wait = 450;

void setup() {
  Serial.begin(9600);
  rcSwitch.enableTransmit(senderPin);
  rcSwitch.setPulseLength(pulseLength);
  rcSwitch.setProtocol(protocol);

  pinMode(btnUp,INPUT); //Setzen des Eingangssignals des Tasters
}

void loop() {
  int btnStatus = digitalRead(btnUp); //Lesen des Status des Tasters.
  if(btnStatus == HIGH){
    statusBtn = statusBtn ==HIGH?LOW:HIGH;
    
    //Wenn der Taster auf HIGH ist dann die Funksteckdose EIN schalten.
    if(statusBtn == HIGH){ 
      rcSwitch.send("000000010100010001010101"); 
    } else {
      rcSwitch.send("000000010100010001010100"); 
    }
  }
}

Download

 

Ausbaustufe II – „Webseite“

Der aufmerksame Leser meines Blogs wird sich sicherlich an das Tutorial zum Wemos D1 erinnern, dort habe ich eine LED über eine Webseite gesteuert. Wenn man nun dieses Sketch als Grundlage nimmt muss man „nur noch“ die Funktion für die Funksteckdose und den 433MHz sender implementieren (und dieses haben wir ja schon in der Ausbaustufe 1 abgehandelt).

Im weiteren verwende ich den Wemos D1 mini, dieser kleine Microcontroller hat den Vorteil das dieser auf das 400 PIN Breadboard passt und noch ordentlich Platz für weitere Module vorhanden ist.

Wemos D1 & Wemos D1 mini
Wemos D1 & Wemos D1 mini

Aufbau

Für dieses Beispiel werden folgende Komponenten benötigt:

  • 1x Wemos D1 mini
  • 1x 433MHz Funksender
  • 1x LED, 5mm, blau,
  • 1x 220 Ohm Widerstand
  • Breadboardkabel
  • 400 PIN Breadboard
Aufbau der Schaltung mit Wemos D1 mini und dem 433MHz Sendemodul.
Aufbau der Schaltung mit Wemos D1 mini und dem 433MHz Sendemodul.

Die Komponenten werden wie auf der folgenden Grafik verbunden.

Modul / PIN Anschluss
 433MHz Funksender
VCC  5V
GND GND
Data digitaler PIN D8
LED
Kathode (abgeflachte Seite) GND
Annode digitaler PIN D5
Funksender mit LED
Funksender mit LED

Quellcode

#include <RCSwitch.h>
#include <ESP8266WiFi.h>

const char* ssid = "****"; //SSID aus dem Router
const char* password = "*****"; //Passwort für den Zugang zum WLAN

const String htmlOK = "HTTP/1.1 200 OK";
const String htmlContentType = "Content-Type: text/html";
const String htmlBegin = "<!DOCTYPE HTML><html>";
const String htmlLinks = "<head><link rel='stylesheet' href='http://progs.draeger-it.blog/wemosd1/d1.css'/><link rel='shortcut icon' href='http://progs.draeger-it.blog/wemosd1/favicon.ico' /></head><body>";
const String htmlEnd = "</body></html>";
const String htmlBreakLine = "</br>";
 
int ledPin = D5; //digitaler PIN 5 des Wemos D1 an welchem die LED angeschlossen ist.
int ledStatus = LOW; //aktueller Status der LED (default / start  -> AUS)

const int senderPin = 15;  // An Pin 15
const int protocol = 1;
const int pulseLength = 358;
const int wait = 450;

RCSwitch rcSwitch = RCSwitch();

WiFiServer server(80); //Port auf welchem der Server laufen soll.
 
void setup() {
  Serial.begin(115200); //Baudrate für die Serielle Geschwindigkeit.
  delay(10); //10ms. Warten damit die Seriele Kommunikation aufgebaut wurde.

  rcSwitch.enableTransmit(senderPin);
  rcSwitch.setPulseLength(pulseLength);
  rcSwitch.setProtocol(protocol);
  
  pinMode(ledPin, OUTPUT); //Den LEDPin als ausgang setzen.
  digitalWrite(ledPin, ledStatus); //Die LED initial auf den Status "AUS" setzen.
   
  Serial.print("Aufbau der Verbindung zu: "); //Ausgabe der SSID auf der Seriellen Schnittstelle.
  Serial.println(ssid);
  
  WiFi.begin(ssid, password); //Initialisieren der Wifi Verbindung.
 
  while (WiFi.status() != WL_CONNECTED) { //Warten bis die Verbindung aufgebaut wurde.
    delay(500);
    //Einen Punkt auf der Seriellen Schnittstelle ausgeben so das der Benutzer erkennt dass, das Sketch noch läuft.
    Serial.print("."); 
  }
  //Bei erfolgreicher Verbindung wird der folgende Text ausgeben.
  Serial.print("Mit ");
  Serial.print(ssid);
  Serial.print("erfolgreich verbunden!");
 
  
  server.begin(); // Starten des Servers.
  Serial.println("Server gestartet"); //Ausgabe auf der Seriellen Schnittstelle das der Server gestartet wurde.
 
  // Ausgabe der IP Adresse 
  Serial.print("Adresse : http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");
}

/**
 * Die Funktion gibt den HTML Kopf auf dem Client aus.
 * Dieses wird für jeden Respond verwendet.
 **/
void printHtmlHeader(WiFiClient client){
  client.println(htmlOK);
  client.println(htmlContentType);
  client.println("");
  client.println(htmlBegin);
  client.println(htmlLinks); 
}

void loop() {
  //Prüfen ob sich ein Client verbunden hat, wenn nicht die Loop "verlassen"
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Wenn sich ein Client verbunden hat solange warten bis Daten gesendet werden.
  Serial.println("Neuer Client verbunden.");
  while(!client.available()){
    delay(1);
  }
 
  //Lesen der Anfrage vom Client
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();

  //Wenn in der Anfrage die Zeichenkette "/toggle" vorkommt dann...
  if (request.indexOf("/toggle") != -1) {
    if(ledStatus == HIGH){
      ledStatus = LOW;
      rcSwitch.send("000000010100010001010100"); 
    } else {
      ledStatus = HIGH;
      rcSwitch.send("000000010100010001010101");
    }

    digitalWrite(ledPin, ledStatus);
    Serial.print("Funksteckdose Status: ");
    Serial.println(ledStatus);
  } 
 //Gibt den Html Header auf der Antwort aus.
 printHtmlHeader(client);
  
  //Ab hier wird die Webseite zusammengesetzt.
  client.println("<div class='mainWrapper'>"); 
  client.print("Die Funksteckdose ist : ");
 
  String value = "-undefined-";
  
  //Die Adresse für die Bilder
  const String imgStartUrl = "http://progs.draeger-it.blog/wemosd1/";
  String imgUrl = imgStartUrl + "light_on.png";
  
  if(ledStatus == HIGH) {
    value = "AN";
  } else {
    value = "AUS";
    imgUrl = imgStartUrl + "light_off.png";
  }
  client.print(value);  
  
  client.println(htmlBreakLine);
  client.println(htmlBreakLine);
 
  client.println("<img src='"+imgUrl+"' widht='64' height='64'/>");

  client.println(htmlBreakLine);
  
  client.print("<div class='headline'>Klicke <a href=\"/toggle\">hier</a> um die Funksteckdose ");
  client.print(value=="AN"?"aus":"an");
  client.print(" zuschalten.</div>");
  client.println("");
  client.println("</div>"); 
  client.println(htmlEnd);
 
  delay(1); //1ms. Pause
}

Ansicht der Seite im Mozilla FireFox

Webseite zum steuern der Funksteckdose
Webseite zum steuern der Funksteckdose

Video

Funksteckdose mit 433MHz Sendemodul und dem Wemos D1 mini steuern

Download

 

 

10 Gedanken zu „Arduino Projekt: Funksteckdose steuern

  • April 26, 2018 um 17:00
    Permalink

    Hallo Stefan,

    danke für die Anleitung!

    Mein Problem: Ich erhalte beim mehrmaligen Einschalten meiner Funksteckdose verschiedene binäre Codes. Und wenn ich einen davon sende, schaltet die Dose nicht. Was tun?

    sg

    Antwort
    • April 27, 2018 um 17:18
      Permalink

      Hallo,

      bitte prüfe doch welche Einstellung auf der Steckdose gewählt ist. Dort kannst du in der Regel durch einen Schiebeschalter den „Port“ wählen.
      Dann musst du auf der Fernbedienung noch die „richtige“ Taste drücken.

      Welches Gerät verwendest du denn? (Marke, Modellnummer)

      Gruß,

      Stefan

      Antwort
  • Mai 13, 2018 um 14:24
    Permalink

    Hallo,

    Ich habe deine Anleitung exakt verfolgt, jedoch passiert bei mir nichts.

    Ich hab alles ganz normal angeschlossen, habe auch schon alle Pins durchprobiert,
    jedoch erhalte ich keine Ausgabe auf meinem Seriellen Monitor, wenn ich eine Taste
    meiner Funkfernbedienung drücke.
    Was mir aufgefallen ist, dass wenn ganz schlicht ich eine LED einschalten möchte, muss ich bei „pinMode(, OUTPUT)“ den Pin auf D0, D1, …. setzen.
    Mit dieser Erkenntnis habe ich auch in Zeile 5 deines Codes die 0 auf „D0“ geändert,
    (Was wahrscheinlich keinen Sinn macht aber nun gut) und wie zu erwarten passierte nichts.

    Hast du eine Idee, woran dies liegen könnte, dass bei mir keine Ausgabe kommt ?

    MFG

    Antwort
      • Juni 13, 2018 um 19:33
        Permalink

        Hallo nochmal,

        ich benutze den „Wemos D1 mini“, so wie du eigentlich.

        Ein Update habe ich.
        Ich habe es geschafft, den Sender mit dem Empfänger kommunizieren zu lassen.
        Soweit so gut. Den Sender habe ich an einen „Funduino Mega2560“ angeschlossen, den Empfänger an den eben genannten ESP8266. Ich bekomme auf dem Wemos ohne Probleme die vom Mega2560 gesendeten Daten. Wenn ich jetzt aber wie blöd auf meinen Fernbedienungen rumdrücke, passiert nichts. Es werden keine Daten Empfangen. Sowohl von der Fernbedienung der Steckdosen, als auch der des Rollladens. Beides basiert eigentlich auf 433mhz. Bzw. auf 433,92mhz. Aber stellt das …,92mhz wirklich ein Problem dar? Ich habe mich eigentlich schlau gemacht und es hieß, es sollte passen. Oder irre ich mich gewaltig?

        Gruß,

        Seba M

        Antwort
  • Mai 19, 2018 um 17:16
    Permalink

    Wirklich toll und super beschrieben wie es funktioniert! Habe für mein Gartenhaus Funksteckdosen und habe dein Tutorial gleich umgesetzt. Nach ein paar kleineren Problemen mit der Schaltung die ich selbst beheben konnte, hat dann alles funktioniert.
    Danke für das Tutorial 🙂

    Antwort
  • Juni 18, 2018 um 10:06
    Permalink

    Hallo Stefan,

    Danke für die schöne Anleitung. An einer Stelle hast Du, glaube ich, einen Fehler. Folgende Zeilen müssen vertauscht werden:

    rcSwitch.setPulseLength(pulseLength);
    rcSwitch.setProtocol(protocol);

    Grund: setProtocol überschreibt die Pulslänge wieder, siehe https://github.com/sui77/rc-switch/issues/117

    Wenn die Pulslänge nicht allzusehr daneben liegt ist es vermutlich oft egal. Bei mir habe ich lange nachdem Fehler gesucht und es dann auf sdiese Art gelöst gekriegt.

    Felix

    Antwort
    • Juni 18, 2018 um 12:58
      Permalink

      Hi Felix,

      danke für den Hinweis. Auf den Fehler bin ich jedoch nicht gestoßen da bei mir alles Funktioniert hat.

      Gruß,

      Stefan

      Antwort
  • Dezember 30, 2018 um 09:41
    Permalink

    Hallo Stefan,
    ein wirklich gelungene Anleitung – das Schalten von meinen alten Schaltsteckdosen funktionierte auf Anhieb und ich war total angefixt!
    Leider hing sich mein Wemos nach einigen Minuten bis Stunden sporadisch auf, das ließ sich abschließend nur durch Reset oder Stecker ziehen beseitigen – und so habe ich mich auf Fehlersuche begeben und Folgendes rausgefunden:
    //Lesen der Anfrage vom Client
    String request = client.readStringUntil(‚\r‘);
    Dein obiger Programmcode ließ sich durch eine einfache nmap-Anfrage aus dem Tritt bringen,
    vermutlich bleibt client.readStringUntil beliebig lange auf Empfang wenn es sich nicht um eine html-Anfrage handelt. Nach Einbau eines Timeouts kehrte der Wemos wieder in den Empfangsmodus zurück. Evtl. kannst Du einen solchen timeout auch in Deinem Beispiel integrieren?
    Gruß
    Ralf

    Antwort
  • September 14, 2019 um 11:21
    Permalink

    Hallo Stefan,
    Du bist die Erlösung stundenlager Googlearbeit! Perfektes auslesen in allen Formaten!!
    Ein dickes DANKE!!

    Antwort

Schreibe einen Kommentar

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