Raspberry Pi und Funksteckdosen

By | 3. Dezember 2016

Hallo und willkommen zu meinem kleinen Tutorial zum Thema „Smart-Home“. Im Folgenden beschreibe ich, wie man mit handelsüblichen Funksteckdosen sein Zuhause ein wenig „smarter“ machen kann. Hierzu verwende ich zusätzlich noch ein Raspberry Pi 2.

Vorwort:

Als kleine Vorgeschichte zu meinem Vorhaben kann ich sagen, dass ich einen riesigen, alten Röhrenfernseher im Schlafzimmer stehen habe. Man ersetzt ihn aber auch nicht durch einen Neuen, weil „solange der noch läuft bleibt der da stehen“. Problematik an der Sache: Ich schlafe häufig vor dem Fernseher ein, und die Nächte in denen ich um 3 Uhr Morgens vom Fernseher geweckt werde und ich den dann erst ausmache häufen sich halt mit der Zeit. Einen Sleep-Timer besitzt dieser Fernseher leider nicht, also musste eine Lösung her. Steckdosen mit Zeitschaltuhr sind leider mehr schlecht als recht, weil mich das mühselige Einstellen genervt hat. Auch schlafe ich nicht jeden Tag zur selben Zeit ein.

Idee:

Die Idee kam mir, als ich im Baumarkt Funksteckdosen entdeckt hatte. Warum nicht einfach den Fernseher durch einen Computer mit Funkmodul ausschalten lassen? Die Idee hat sehr schnell fruchtbaren Boden gefunden und die Idee „Computer“ wurde schnell durch „Raspberry Pi“ ersetzt. In diesem Tutorial möchte ich euch nachfolgendes Schritt-für-Schritt erklären:

  • Was benötige ich?
  • Funkmodul mit dem Raspberry Pi verbinden
  • Funksteckdosen einstellen
  • Serveranwendung zum Funken in Java programmieren

Fertig sieht das ganze bei mir Zuhause nun so aus:

Raspberry Pi 2 mit Funkmodul

Raspberry Pi 2 mit Funkmodul

Als Gehäuse dient mir ein altes Festplattengehäuse. Es gibt aber auch optisch ansprechendere Gehäuse zu kaufen (siehe Einkaufsliste weiter unten)

Umsetzung:

1.) Einkaufsliste:

Für die Umsetzung benötigen wir ein bisschen Hardware. Ich habe hier einmal eine Liste meiner Hardware, die ich ich für dieses Tutorial verwende, mit entsprechenden Amazon-Link zusammengestellt:

  1. Raspberry Pi 2 Model B (Amazon Einzel) (Amazon Komplettes Set)
  2. Aukru 433 MHz Funk- Sende und Empfängermodul (Amazon)
  3. Brennenstuhl Funkschaltset RCS-1000 N Comfort, 1507450 (Amazon)
  4. Aukru Kabel Steckbrücken weiblich-weiblich (Amazon)
  5. Ein Stück Draht (dient später als Antenne)

AchtungAnmerkung: Zum Zeitpunkt der Erstellung dieser Anleitung ist das Raspberry Pi 3 erschienen! Das neue Modell ist deutlich günstiger und sollte keine gravierenden Änderungen aufweisen, sodass sich diese Anleitung auch damit umsetzen lässt. Dennoch möchte ich hier meine Hand nicht für ins Feuer legen! (Amazon Raspberry Pi 3)

2.) Installation Raspberry Pi 2:

Ich verwende auf meinem Raspberry Pi 2 die Distribution „Raspbian“. Ich werde in dieser Anleitung aber die Installation nicht beschreiben, da dies den Rahmen sprengen würde. Ich möchte an dieser Stelle lieber auf die offizielle Seite der Raspberry Pi Foundation verweisen, die super Anleitungen und ein einfaches Installationspaket bereitstellen. Das Installationspaket heißt „NOOBS“ und steht hier zum Download bereit. Eine Anleitung zur Installation von Raspbian mit Hilfe von „NOOBS“ ist hier abrufbar. Falls das Anschließen der Hardware Probleme bereitet, dann findet man hier Hilfe. Sollten trotz der Anleitungen Probleme auftreten, dann helfe ich auch gerne persönlich weiter. Hierzu einfach bei mir per E-Mail melden oder einen Kommentar verfassen.

3.) Funkmodul anschließen:

Wenn euer Raspberry Pi installiert ist und ihr erfolgreich booten konntet, dann ist es nun an der Zeit das Funkmodul anzuschließen. Ihr habt zwei Module geliefert bekommen. Ein Modul ist ein Sender und eins ein Empfänger. Wir benötigen nur das Sendemodul. Das Sendemodul ist (im Gegensatz zum Empfänger) quadratisch und besitzt insgesamt 4 Pins. Die Pins 1 – 3 sind deutlich am Rand zu erkennen und der 4. Pin ist für die Antenne gedacht. Die Pins haben nachfolgende Belegung und sind auch so beschriftet:

  1. DATA (Für Datentransfer) (Steckbrücke Orange)
  2. VCC (Hier soll eine Spannung zwischen 3,3V und 5V anliegen) (Steckbrücke Rot)
  3. GND (Erdung) (Steckbrücke Braun)
  4. ANT (Antenne)

Pin 1 – 3 werden an das Raspberry Pi angeschlossen und werden dementsprechend mit einer Steckbrücke versehen. Die jeweiligen Farben, welche ich verwendet habe sind in der Liste oben verzeichnet. Fertig angeschlossen sieht es nun so aus:

Funkmodul (Sender)

Funkmodul (Sender)

An Pin 4 habe ich bereits ein Stück Draht angelötet, welches als Antenne dient. Dies ist sehr zu empfehlen, da sonst die Sendereichweite = 0 ist und es nicht Sinn der Sache ist nur Steckdosen zu schalten, die unmittelbar in der Nähe sind.

Nun gilt es die 3 anderen Enden der Steckbrücken an das Raspberry Pi anzuschließen. Dies tun wir wie nachfolgend:

  • Wir werden die rote Steckbrücke mit Pin 4 (des Raspberry Pi) verbinden, welcher eine Nennspannung von 5V liefert. Es kann auch Pin 1 (des Raspberry Pi) verwendet werden, jedoch liefert dieser Pin nur eine Nennspannung von 3,3V, was die Sendeleistung verringert. Wer also beispielsweise eine große Wohnung besitzt, der sollte hier Pin 4 verwenden.
  • Die braune Steckbrücke findet ihr Gegenstück am Pin 6, 9, 14, 20 oder 25 (des Raspberry Pi). Alle aufgeführten Pins sind Ground-Pins und können verwendet werden. Ich habe nur das Funkmodul angeschlossen und daher den ersten Pin Nr. 6 (des Raspberry Pi) gewählt.
  • Die orangene Steckbrücke muss mit einem Pin verbunden werden über den wir Daten senden können. Hier müssen wir am Raspberry Pi einen GPIO-Pin nehmen. Hier eignen sich Pin 7, 11, 12, 13, 15, 16, 18 oder 22 (des Raspberry Pi). Da wir im Verlauf dieses Tutorials eine Software verwenden werden, welche nur Pin 11 (des Raspberry Pi) verwendet, ist es essentiell wichtig, dass wir ebenfalls diesen Pin nehmen. Also belegen wir Pin 11 (des Raspberry Pi) mit unserer orangenen Steckbrücke.

Nachfolgend ein Plan zur Orientierung wie die Pins auf der Platine verteilt sind:

[SD-Karten Slot]
01 02
03 04
05 06
07 08
09 10
11 12
13 14
15 16
17 18
19 20
21 22
23 24
25 26
[USB-Buchsen]

Fertig angeschlossen sollte es bei euch nun so aussehen:

Raspberry Pi Pinbelegung Funkmodul

Raspberry Pi Pinbelegung Funkmodul

Und im Gesamtpaket sollte es so aussehen:

Raspberry Pi mit Funkmodul

Raspberry Pi mit Funkmodul

4.) Erforderliche Software für das Funkmodul:

Das Funkmodul ist nun angeschlossen und wir können das Raspberry wieder einschalten. Um es aber verwenden zu können benötigen wir noch ein bisschen Software, welche wir nun einmal installieren.

Zur Verwendung der GPIO-Pins benötigen wir eine Programmbibliothek, welche dies möglich macht. Hierzu installieren wir uns WiringPi. Vorerst updaten wir aber unsere Paketquellen und installieren das Paket „git-core“, um das Programm „WiringPi“ beziehen zu können. Dies tun wir wie nachfolgend:

sudo apt-get update
sudo apt-get install git-core

 

Anschließend installieren wir das benötigte Paket „WiringPi„:

git clone git://git.drogon.net/wiringPi
cd wiringPi
./build

Das Shellscript installiert nun die Software. Im nächsten Schritt benötigen wir eine Software, mit der wir die entsprechenden Funksteckdosen anfunken können. Irgendjemand hat mir mal gesagt „Man muss das Rad nicht neu erfinden“ und demnach habe ich auch hier eine Software gefunden, welche genau diese Aufgabe für uns erfüllen wird. Das Programm, welches wir benötigen heißt „Raspberry-Remote“ von xkonni.

Wir müssen uns das Programm selber herunterladen und kompilieren, was ihr wie folgt tut:

cd ..
git clone git://github.com/xkonni/raspberry-remote.git
cd raspberry-remote/
make send

Das Programm ist nun kompiliert und ihr findet die Binary „send“ im selben Ordner. Ich werde sie mir in mein home-Verzeichnis kopieren. Tut dies ebenfalls für den weiteren Verlauf des Tutorials und wechselt in das Home-Verzeichnis.

mv send /home/pi/
cd /home/pi/

Die erforderliche Software für das Funkmodul ist nun installiert und eigentlich könnte man jetzt schon losfunken. Deswegen richten wir im nächsten Schritt die Funksteckdosen ein.

5.) Funksteckdosen einrichten:

Damit das Funkmodul auch mit den Funksteckdosen kommunizieren kann, haben wir extra Funksteckdosen mit Dip-Schalter bestellt. Mit diesen Schaltern geben wir unseren Steckdosen eine Art eindeutige Kennziffer. Alle Steckdosen können den gleichen 5-stelligen Code besitzen, da sie noch einen anderen Schalter für die Steckdosennr. haben.
An den bestellten Steckdosen befindet sich die Schalter unter einer kleinen Klappe, auf der Rückseite der Steckdose. Diese Klappe ist durch eine kleine Schraube gesichert, welche wir lösen um die Klappe zu öffnen. Wir finden eine kleine rote Platine mit ingesamt 10 Schaltern vor. Befindet sich ein Schalter in der unteren Position, so bedeutet das später für unseren Code eine „0“ und wenn der Schalter noch oben gestellt ist bedeutet es später eine „1“. Die ersten 5 Schalter (von links nach rechts) sind beschriftet mit den Zahlen 1 – 5, welche unsere oben angesprochene „eindeutige Kennziffer“ darstellt. Diese können eingestellt werden wie man möchte. Man sollte jedoch beachten, dass zum Beispiel ein Nachbar, welcher ebenfalls Funksteckdosen benutzt und denselben Code eingestellt hat wie ihr, eure Funksteckdosen mit seiner Fernbedienung steuern kann! Es gilt also einen Code zu verwenden, welchen nicht zwangsläufig jeder verwenden würde. Ich wähle für den Verlauf dieses Tutorials nachfolgenden Code:

11010 -> 1 (oben),2 (oben), 3 (unten), 4 (oben), 5 (unten)

Dieser Code muss nun an allen Steckdosen so eingestellt werden. Ist dies geschehen widmen wir uns den Buchstaben, welche direkt nach der Zahlenreihe kommen. Diese Stellen die exakte Steckdosennr. dar. Hier sollte jeweils nur ein Schalter nach oben gestellt werden. Wird der Schalter „A“ also nach oben gestellt, dann ist diese Steckdose die erste Steckdose. Bei Steckdose mit der Nr. 2 legen wir den Schalter „B“ nach oben, usw.
So können wir später unterscheiden welche Steckdose nun eingeschaltet werden soll. Für eine Steckdose sollte es fertig nun so aussehen:

Einstellung Funksteckdosen Bild 1

Einstellung Funksteckdosen Bild 1

 

Einstellung Funksteckdosen Bild 2

Einstellung Funksteckdosen Bild 2

(Ich möchte mich für die schlechten Bilder entschuldigen, aber meine Lichtverhältnisse sind nicht gerade die besten gewesen. Ich werde die Fotos durch Bessere ersetzen, sobald ich Zeit finde.)

Wenn alle Funksteckdosen eingestellt sind, dann können sie nun an die Steckdose angeschlossen werden. Anhand einer kleinen roten Lampe erkennt ihr, ob die Steckdose Strom liefert oder nicht.

6.) Funksteckdosen schalten mit „send“:

Nun können wir das erste mal die Anwendung aus Punkt 4 verwenden. Das Programm „send“ erwartet 3 Parameter:

  1. Eindeutige Kennziffer
  2. Steckdosennr.
  3. Status (an oder aus)

Die Reihenfolge ist wie oben aufgezählt und wichtig. Wir navigieren also zurück an die Stelle wo das Programm „send“ liegt (Ich habe es hier abgelegt: /home/pi/) und führen nachfolgenden Befehl aus:

./send 11010 1 1

Dies schaltet die erste Steckdose ein.

./send 11010 1 0

Dies schaltet die erste Steckdose wieder aus.

Die Kennzahl „11010“ (1. Parameter) sollte natürlich eurer eingestellten Kennzahl entsprechen.

Möchtet ihr die zweite Steckdose einschalten, so entspricht der Aufruf von „send“ nachfolgendem:

./send 11010 2 1

Ich hoffe das Prinzip ist so klar geworden.

7.) Serveranwendung zum Funken:

Da das schalten von Funksteckdosen mittels des Terminal auf Dauer ein wenig nervig wird, können wir uns eine optimale Netzwerkschnittstelle schaffen, die wir mit anderen Programmen ansprechen können. Der Code der Anwendung ist unten abgebildet und kann so kopiert werden:

package de.barny.funkserver;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *
 * @author Barny
 * @version 1.0.0
 */
public class Main {
   
    public static int PORT;
    public static String FREQUENCY;
    
    public static final String CONN_OK = "okay";
    public static final String VERSION = "1.0.0";
    public static final String PROGRAM_TITLE = "[!] FunkServer Vers. "+VERSION+" successfully started";
    public static final String START_MSG = "[#] Started Server on Port %d for Powersocket %s \n";
    public static final String CLIENT_CONNECTED = "[#] Client connected!";
    public static final String CLIENT_DISCONNECTED = "[#] Client disconnected";
    public static final String SEPERATOR = "#";
    public static final String ERROR_CODE = "error";
    public static final String SUCCESS_CODE = "success";
    public static final String SEND_COMMAND = "sudo ./send "+FREQUENCY;
    public static final int REPEAT_TIME = 1;

    public static void main(String[] args) {
        
        if(args.length < 2) {
            printHelp();
            System.exit(0);
        } else {
            parseArgs(args);
            System.out.println(PROGRAM_TITLE);
            System.out.printf(START_MSG,PORT,FREQUENCY);
        }
        
        while(true) {
            try {
                ServerSocket so = new ServerSocket(PORT);
                Socket s;
                boolean isConnected = false;

                s = so.accept();
                isConnected = true;
                System.out.println(CLIENT_CONNECTED);

                BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

                out.write(CONN_OK);
                out.newLine();
                out.flush();

                while(isConnected) {

                    String line;
                    line = in.readLine();
                    String[] splitted;
                    int steckdose;
                    int status;
                    
                    if(line.length() >= 3 && line.contains(SEPERATOR)) {
                        splitted = line.split(SEPERATOR);
                        steckdose = Integer.valueOf(splitted[0]);
                        status = Integer.valueOf(splitted[1]);
                        if(steckdose == 0 && status == 0) {
                            isConnected = false;
                        }else {
                            if(changeStatus(steckdose,status)) {
                                out.write(SUCCESS_CODE);
                                out.newLine();
                                out.flush();
                            }else {
                                out.write(ERROR_CODE);
                                out.newLine();
                                out.flush();
                            }
                        }
                    }else {
                        out.write(ERROR_CODE);
                        out.newLine();
                        out.flush();
                    }
                    

                }
                
                s.close();
                so.close();

                so = null;
                s = null;
                
                System.out.println(CLIENT_DISCONNECTED);
            }catch(IOException e) {
              // eat all exceptions
            }
        }
        
    }
    
    private static boolean changeStatus(int steckdose, int status) {
        try {
            for(int i=1;i<=REPEAT_TIME;i++) {
                System.out.println(executeCommand(createCommand(steckdose,status)));
            }
        }catch(Exception e) {
            return false;
        }
        return true;
    }
    
    private static String createCommand(int steckdose, int status) {
        return(SEND_COMMAND+" "+steckdose+" "+status);
    }
    
    private static String executeCommand(String command) {
        StringBuffer output = new StringBuffer();
        Process p;
        
        try {
            p = Runtime.getRuntime().exec(command);
            p.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

            String line = "";
            while ((line = reader.readLine())!= null) {
                output.append(line + "\n");
            }
            
        }catch(IOException e) {
            // eat all
        }
        catch(InterruptedException e) {
            // eat all
        }

        return output.toString();
    }
    
    private static void parseArgs(String[] arguments) {
        PORT = 1415;
        FREQUENCY = "11111";
        for(int i=0;i<arguments.length;i++) {
            if(arguments[i].toUpperCase().contains("-PORT=")) {
                String[] temp = arguments[i].split("=");
                try {
                    PORT = Integer.valueOf(temp[1]);
                }catch(NumberFormatException e) {
                    PORT = 1415;
                }
                catch(IndexOutOfBoundsException e) {
                    PORT = 1415;
                }
            }
            
            if(arguments[i].toUpperCase().contains("-POWERSOCKETID=")) {
                String[] temp = arguments[i].split("=");
                try {
                    FREQUENCY = temp[1];
                    if(FREQUENCY.length() < 5) {
                        FREQUENCY = "11111";
                    }
                }catch(IndexOutOfBoundsException e) {
                    FREQUENCY = "11111";
                }
            }
        }
    }
    
    private static void printHelp() {
        System.out.println("########################################################################################");
        System.out.println("#                     .:: Funkserver Vers. 1.0 coded by Barny ::.                      #");
        System.out.println("# Usage: java -jar Funkserver.jar {-PowerSocketId=X} {-port=X}                         #");
        System.out.println("# -PowerSocketID=X =  Your personal PowerSocketID (Default is 11111)                   #");
        System.out.println("# -port = The port on which this software will running (Default is 1415)               #");
        System.out.println("#                                                                                      #");
        System.out.println("# Example: java -jar Funkserver.jar -PowerSocketId=11010 -port 1800                    #");
        System.out.println("# This will start the Application on Port 1800 and switch powersockets with id 11010   #");
        System.out.println("########################################################################################");
    }
    
}

Alternativ zum Code biete ich auch hier einen Download der Funkserver.jar an. Diese braucht ihr dann auf euren Raspberry nur auszuführen. Geht dabei wie folgt in euren Terminal vor:

wget https://www.barny-blog.de/downloads/Funkserver.tar.xz
tar -xf Funkserver.tar.xz

Das Programm befindet sich nun entpackt, im selben Ordner. Es erwartet insgesamt 2 Parameter, welche aus Port und eindeutiger Kennzahl der Steckdosen besteht. Wenn es ohne Parameter gestartet wird, dann wird nur die Hilfe geöffnet. Mit korrekten Parametern gestartet sieht das ganze so aus:

java -jar Funkserver.jar -PowerSocketId=11010 -port=1234

Das würde den Server auf Port „1234“ starten und die Steckdosen mit der Kennziffer „11010“ schalten. Die Werte der Parametern müssen natürlich angepasst werden.

Das Programm befindet sich nun im Vordergrund. Um es im Hintergrund zu starten könnt ihr das Programm „screen“ verwenden. Dieses muss unter Umständen nachinstalliert werden. Dies erfolgt mit nachfolgendem Befehl:

apt-get install screen

Nach der Installation kann die Serveranwendung wie nachfolgend gestartet werden:

screen -S Steckdosenserver java -jar Funkserver.jar -PowerSocketId=11010 -port=1234

Mittels der Tastenkombination [STRG-A-D] kann der aktuelle Screen verlassen werden.

screen -ls

Obiger Befehl sollte nun den entsprechenden Screen zeigen. Mit Hilfe nachfolgenden Befehls kann der Screen wieder geöffnet werden:

screen -r Steckdosenserver

Die Serveranwendung lauscht auf dem eingestellten Port nach Verbindungen. Verbindet sich ein Programm auf diesem Port, so gibt die Anwendung die Meldung „okay“ zurück. Nun ist sie einsatzbereit zum Empfangen der Informationen. Die Information muss die Steckdosennr. und den Zustand enthalten. Getrennt werden diese Informationen durch einen Hashtag. Um die Steckdose 1 auzuschalten würde die Anwendung nachfolgenden Befehl erwarten:

1#0

Um Steckdose 2 einzuschalten muss nachfolgendes gesendet werden:

2#1

Die Serveranwendung hält die Verbindung so lange aufrecht und wartet auf Verbindungen, wie der Client verbunden ist. Der Server lauscht für neue Geräte erst wieder, wenn der Client sich getrennt hat. Demnach kann immer nur ein Client gleichzeitig eine Steckdose schalten. Ich hoffe, dass das Prinzip klar geworden ist.

Schlusswort

Das Ende dieses Beitrages ist nun fast erreicht und ich hoffe, dass er euch ein wenig geholfen und gefallen hat. Bei Fragen stehe ich natürlich jederzeit persönlich zur Verfügung. Am besten einfach einen Kommentar verfassen oder mir direkt per E-Mail schreiben (barny@barny-blog.de).

Ursprünglich sollte in diesem Beitrag noch eine Android-App seinen Platz finden, um die Steckdosen mit der Serveranwendung zu steuern. Die Android-App wird ihren Platz aber nun in einem separaten Beitrag finden, weil dies den Rahmen sonst gesprengt hätte. Freut euch also auf eine Fortsetzung! 😉

Zum Teilen, Kopieren und Verlinken:

AchtungDiese Anleitung darf selbstverständlich geteilt werden, solange mein Name darin nicht verschwindet! Ich habe hier sehr viel Arbeit und Zeit reingesteckt und fände es nicht so schön, wenn ich meine Anleitung in einem fremden Blog, ohne meinen Namen, wiederfinde. Ihr dürft sie euch natürlich jederzeit für privat kopieren, ausdrucken und meinen Blog verlinken. Ich danke euch für die Rücksichtnahme! Ich habe genauso viel Respekt vor euren Arbeiten.

Viele Grüße,

Barny

 

Schreibe einen Kommentar

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

19 − 16 =