AdSense

Samstag, 31. August 2013

Beschleunigungssensor MPU-6050 mit ATMega 16A auslesen

(English version) Der Beschleunigungssensor MPU-6050 ist ziemlich vielseitig, klein und billig. Er kann mit bis zu 6 V betrieben werden und liefert Beschleunigungswerte und sogar Gyroskopwerte (also Drehung in Grad pro Sekunde). So ein Sensor ist also das ideale Kernstück für einen Quadrocopter.

In diesem Post möchte ich nun auch das Auslesen mit einem ATMega zeigen, da sich der Post mit dem Raspberry PI ziemlich großer Beliebtheit erfreut (http://physudo.blogspot.de/2013/07/beschleunigungssensor-mpu-6050-mit.html). Für I2C benutze ich am ATMega diese Implementierung: http://physudo.blogspot.de/2013/07/atmega-ic-master.html.

Zuerst einmal habe ich mir zwei Funktionen gebastelt, die entweder ein Register auslesen oder in ein Register reinschreiben:

void TWIM_WriteRegister(char reg, char value)
{
    TWIM_Start(addr, TWIM_WRITE); // set device address and write mode
    TWIM_Write(reg);
    TWIM_Write(value);
    TWIM_Stop();
}

char TWIM_ReadRegister(char reg)
{
    TWIM_Start(addr, TWIM_WRITE);
    TWIM_Write(reg);
    TWIM_Stop();

    TWIM_Start(addr, TWIM_READ); // set device address and read mode
    char ret = TWIM_ReadNack();
    TWIM_Stop();
    return ret;
}


Als nächstes möchte ich die Beschleunigung bzw. die Werte des Gyrometers auslesen. Zu beachten ist, dass zuerst der Sleep Mode deaktiviert werden muss, das geschieht mit TWIM_WriteRegister(107, 0). Zum auslesen der Werte habe ich mir wieder 2 Funktionen gebaut:

double MPU6050_ReadAccel(int axis)//x = 0; y = 1; z = 2
{
  char reg = axis * 2 + 59;
  char AFS_SEL = TWIM_ReadRegister(28);
  double factor = 1<<AFS_SEL;
  factor = 16384/factor;
  int val = 0;
  double double_val = 0;
  char ret = 0;

  ret = TWIM_ReadRegister(reg);
  val = ret << 8;

  ret = TWIM_ReadRegister(reg+1);  
  val += ret;

  if (val & 1<<15)
  val -= 1<<16;


   
  double_val = val;
 
  double_val = double_val / factor;

  return double_val;
}

double MPU6050_ReadGyro(int axis)//x = 0; y = 1; z = 2
{
  char reg = axis * 2 + 67;
  char FS_SEL = TWIM_ReadRegister(27);
  double factor = 1<<FS_SEL;
  factor = 131/factor;
  int val = 0;
  double double_val = 0;
  char ret = 0;

  ret = TWIM_ReadRegister(reg);
  val = ret << 8;

  ret = TWIM_ReadRegister(reg+1);  
  val += ret;

  if (val & 1<<15)
  val -= 1<<16;


  double_val = val;

  double_val = double_val / factor;

  return double_val;
}


Die Werte sind in Grad / Sekunde für das Gyrometer und in Einheiten von g für den Beschleunigungsmesser, mehr dazu gibt es auch in der Register Map, besonders bei der Erklärung von FS_SEL und AFS_SEL: http://www.invensense.com/mems/gyro/documents/RM-MPU-6000A.pdf

Donnerstag, 29. August 2013

Tageszeitabhängige Header-Grafik

Bei einer Homepage, die ich betreue, wollte ich in der Kopfzeile eine Header-Grafik haben, die sich je nach Tageszeit ändert (tagsüber ein Bild von einem Gebäude bei Tag, in der Nacht ein entsprechendes Bild des Gebäudes bei Nacht). Das lässt sich leicht mit PHP umsetzen:

Zuerst muss die aktuelle Uhrzeit erfasst und in einer Variable gespeichert werden:

$time = date("G", time())

Die Funktion time() liefert den aktuellen UNIX-Timestamp des Servers. Der UNIX-Timestamp ist die Anzahl der Sekunden seit dem 01.01.1979 um 1 Uhr - damit kann man also recht wenig anfangen. Daher kommt noch die Funktion date() zum Einsatz. Sie wandelt den Timestamp in ein verwertbares Format. Das genaue Format wird über den ersten Parameter der Funktion gewählt. Im Beispiel wird der Paramter "G" verwendet - es werden die vollen Stunden ohne führende Null angegeben. Möglich sind aber auch noch viele andere Formate wie Wochentag, Monat und so weiter. Alle möglichen Parameter sind auf dieser Seite zu finden.

Die aktuelle volle Stunde wurde also in der Varible $time gespeichert und kann nun weiter verwendet werden. Wichtig zu wissen ist, dass die Zeit in UTC (Weltzeit) angegeben wird - für MEZ oder MESZ müssten entsprechend 1 oder 2 Stunden addiert werden.

Nun kann anhand der aktuellen Zeit die passende Header-Grafik ausgewählt werden:

if ($time > 7 && $time < 21 ) {
   $pfad = "http://hierdiedomaindeservers.de/images/header_tag.jpg";
 }

else {
    $pfad = "http://hierdiedomaindeservers.de/images/header_nacht.jpg";
}

Ist die Stundenzahl größer als 7 und kleiner als 21 (ist es also zwischen 8:00 und 20:59), dann wird der Pfad der "Tag-Grafik" in der Variable $pfad gespeichert - sonst der Pfad der "Nacht-Grafik".

Zum Schluss wird die Grafik via HTML in der Homepage eingebunden:

<img src="<?php echo $pfad; ?>" width="123" height="456" alt="" />

Mit dieser Methode können natürlich nicht nur tageszeitabhängige sondern auch beispielsweise jahreszeitabhängige oder wochentagsabhängige Grafiken erzeugt werden.

Mittwoch, 28. August 2013

Arduino-Code auf dem ATtiny

Wer meine letzten Beiträge aufmerksam verfolgt hat weiß, dass ich gerade an einer Funkfernbedienung für meinen Rolladen arbeite. Für diesen Zweck ist der "normale" ATmega8 eher nicht geeignet (zu groß, 5V Betriebsspannung, teuer). Das Projekt soll also auf einem ATtiny basieren. Trotzdem möchte ich den gewohnten Komfort und die Libraries der Arduino-Entwicklungsumgebung nutzen. Wie man die Arduino IDE nutzen kann, um einen "nackten" ATmega8 zu programmieren, habe ich in meinem ersten Gastbeitrag hier beschrieben. Hierfür waren keine weitere Schritte nötig, da Arduino den ATmega8 von Haus aus unterstützt.
Für den ATtiny gilt das nicht, allerdings lässt sich die Arduino IDE mit wenigen Schritten mit dem ATtiny "vertraut" machen. Mit der folgenden Anleitung könnt ihr ATtiny45 und ATtiny85 sowie ATtiny24, ATtiny44 und ATtiny84 zur Arduino IDE hinzufügen.

Als erstes ladet ihr diese Datei herunter und entpackt sie. Den enthaltenen Ordner "attiny" kopiert ihr dann in den Ordner "hardware" eurer Arduino-Installation. Ihr solltet dann also z.B. folgende Ordnerstruktur haben: "C:\Programme\Arduino\hardware\attiny".

Der Ordner enthält eine Datei "boards.txt". Die Datei enthält alle Infos zu den verwendeten "Boards" - in diesem Fall natürlich nur ein "nackter" ATtiny. Dazu zählen Fuse-Einstellung, Taktfrequenz usw. Nur die in dieser Datei gelisteten "Boards" erscheinen nachher auch in der IDE. Die Datei enthält allerdings nur die Einstellungen für den Betrieb mit interner Taktquelle.

Natürlich könnte man den Tiny auch mit einer externen Taktquelle und entsprechendem Takt betreiben. Dann müsste eben ein weiterer passender Eintrag eingefügt werden.

Wichtig ist aber in jedem Fall, dass die Fuses für die Taktfrequenz am ATtiny auch entsprechend richtig eingestellt sind, sonst passt das Timing nicht!

Nun muss man der IDE natürlich noch die Pin-Belegung des ATiny beibringen. Dazu ist der Ordner "variants" mit den Unterordnern "tiny8" und "tiny14" enthalten. Sie enthalten jeweils die Datei "pins_arduino.h" in der die Pin-Belegung festgelegt ist. Der Datei kann auch entnommen werden, welcher Pin des ATtiny mit welchen Arduino-Funktionen belegt ist. Beim ATtiny24/44/84 wäre das z.B.
                                          +-\/-+
                                VCC  1|    |14  GND
                      (D 10)  PB0  2|    |13  AREF (D  0)
                       (D  9)  PB1  3|    |12  PA1  (D  1)
                                 PB3  4|    |11  PA2  (D  2)
    PWM  INT0  (D  8)  PB2  5|    |10  PA3  (D  3)
       PWM        (D  7)  PA7  6|    |9   PA4  (D  4)
       PWM        (D  6)  PA6  7|    |8   PA5  (D  5)        PWM
                                          +----+
Mit (D x) sind die entsprechenden Arduino-Pins bezeichnet.

Wenn die Arduino IDE nun gestartet wird, sollten unter Tools-Board die neu eingefügten ATtinys auftauchen:


Nun kann wie gewohnt programmiert werden. Je nach Funkstionsumfang des verwendeten ATtinys kann es natürlich Einschränkungen geben, z.B. bei den Interrups. Außerdem muss zum Programmieren ein Programmer wie z.B. der USBasp verwendet werden.

Die Anleitung gilt so im Prinzip auch für alle anderen ATtinys (und auch ATmegas) - man muss lediglich die passende "pins_arduino.h" auftreiben bzw. selber erstellen.

C# WPF - DataBinding

(English version) DataBindings in WPF sind ziemlich mächtig und nützlich. Heute will ich hier die Grundlagen beschreiben. Die Grundidee dahinter ist: Ich habe ein Anzeigeelement und eine Variable (eigentlich ein Feld). Wenn ich die Variable verändere, will ich, dass sich das Anzeigeelement ändert, umgekehrt will ich aber auch, dass sich bei Veränderung des Anzeigeelements (z.B. Texteingabe) die Variable ändert. Hier nun mal ein kleines Beispiel. Zuerst die XAML-Seite:

<TextBox Name="InputText" Grid.Row="0" Text="{Binding BindingText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TextBox>
<TextBlock Name="OutputText" Grid.Row="1" Text="{Binding BindingText, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"></TextBlock>


Als nächstes braucht man irgendein Objekt, an welches gebindet wird. Das ist bei mir die Klasse "AnyClass", welche das Feld "BindingText" enthält, man könnte jedoch auch genausogut einfach MainWindow.xaml.cs benutzen. Um jetzt das Objekt an welches gebindet wird festzulegen geht man folgendermaßen vor:

AnyClass anyClass = new AnyClass();
InputText.DataContext = anyClass;
OutputText.DataContext = anyClass;


Man könnte auch einfach this.DataContext = anyClass; machen, was prinzipiell auch richtig ist, ich will hier aber möglichst viele Möglichkeiten zeigen. Ebenfalls könnte ich einfach in MainWindow.xaml.cs das entsprechende Feld "BindingText" erstellen und dann this.DataContext = this; aufrufen.

Nun komme ich zur Klasse AnyClass. Zuerst eine kurze Einführung zum Thema Felder. Ein Feld kann wie eine Variable verwendet werden, jedoch kann ein Feld keine Werte direkt speichern. Ein minimales Feld sieht folgendermaßen aus:

public string BindingText
{
    get { return _BindingText; }
    set { _BindingText = value; }
}
private string _BindingText = "";


Das ist also ein Feld. Im get und set Block kann man nun viele lustige Dinge tun, wie z.B. Überprüfen von Eingaben, Events werfen (also ein event, wenn das Feld abgefragt wird z.B.) und eigentlich auch alles andere denkbare.

Nun zeige ich die Klasse AnyClass, welche der letzte fehlende Baustein für das DataBinding ist:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataBindingExample
{
    public class AnyClass : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string BindingText
        {
            get { return _BindingText; }
            set
            {
                _BindingText = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs("BindingText"));
                }
            }
        }
        private string _BindingText = "<empty>";
    }
}


Indem man PropertyChanged auslöst bekommt das Anzeigeelement gesagt, dass ein neuer Variablenwert existiert und aktualisiert sich. Das sollte die Grundlagen zum Thema DataBinding abdecken, falls es Fragen gibt, beantworte ich diese gerne in den Kommentaren.

Einen Post zu diesem Thema, der auch etwas weiter greift und z.B. Converter erklärt gibt es auf C# Tipps und Tricks.

Freitag, 23. August 2013

Ein Musikplayer mit C#

(English version) Tja, es gibt viele Musikplayer auf der Welt. Jeder hat Vorteile und Nachteile, bisher habe ich keinen "perfekten" Musikplayer gefunden. Daher habe ich mich mal drangesetzt und einen eigenen Programmiert. Den Player kann man hier herunterladen. Zur Bedienung: Man muss einmal einen Ordner als Musikbibliothek auswählen und mit Refresh Library wird diese dann geladen. Play Pause, etc sollte selbsterklärend sein. Was mir ganz wichtig ist sind die Hotkeys: "AltGr" + "NachRechts" spielt das nächste (zufällige) Lied, mit "AltGr" + "NachLinks" das vorherige. Außerdem kann die Wiedergabe mit "AltGr" + "Leertaste" angehalten und fortgesetzt / gestartet werden. Unter dem Fortschrittsbalken des aktuellen Liedes gibt es ein Such-Fenster, hier kann man Suchbegriffe eintippen. Ein Doppelklick auf ein Lied startet dieses dann. Zwei kleine Programmierkonzepte werde ich hier nun vorstellen: Einerseits das Abspielen von Medien-Dateien mit C# und WPF, andererseits das Verwenden von Hotkeys. Übrigens kann man hier eine grundlegende Einführung in WPF finden: C# Tipps und Tricks.

Musik wiedergeben

Da ich WPF verwende ist das total simpel: In der xaml-Datei habe ich einfach als Element (so wie z.B. ein Button) ein MediaElement:

<MediaElement Height="10" Width ="10"  LoadedBehavior="Manual" Name="mediaElement1" VerticalAlignment="Top" />

Das MediaElement ist unsichtbar. Um jetzt Musik abzuspielen geht man folgendermaßen vor:

mediaElement1.Source = new Uri(pathToMediaFile);
mediaElement1.Play();


Das war auch schon alles was man dazu sagen muss. Man kann sich jetzt noch an Events hängen, z.B. an mediaElement1_MediaEnded, sodass man weiß, wann die Wiedergabe aufgehört hat (um z.B. das nächste Lied zu starten).

Hotkeys

Anmerkung: Inzwischen benutze ich eine "bessere" Implementierung der Hotkeys, welche man hier nachlesen kann.

Hotkeys zu verwenden ist recht einfach. Zuerst muss man ein paar Zeilen in das Programm einfügen:

[DllImport("User32.dll")]
private static extern bool RegisterHotKey(
    [In] IntPtr hWnd,
    [In] int id,
    [In] uint fsModifiers,
    [In] uint vk);

[DllImport("User32.dll")]
private static extern bool UnregisterHotKey(
    [In] IntPtr hWnd,
    [In] int id);

private HwndSource _source;
private const int HOTKEY_ID = 9000;

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    var helper = new WindowInteropHelper(this);
    _source = HwndSource.FromHwnd(helper.Handle);
    _source.AddHook(HwndHook);
    RegisterHotKey();
}

protected override void OnClosed(EventArgs e)
{
    _source.RemoveHook(HwndHook);
    _source = null;
    UnregisterHotKey();
    base.OnClosed(e);
}

private void UnregisterHotKey()
{
    var helper = new WindowInteropHelper(this);
    UnregisterHotKey(helper.Handle, HOTKEY_ID);
}

private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    const int WM_HOTKEY = 0x0312;
    switch (msg)
    {
        case WM_HOTKEY:
            OnHotKeyPressed(wParam.ToInt32());
            break;
    }
    return IntPtr.Zero;
}


Als nächstes habe ich die drei Hotkeys, welche ich benötige definiert:

private void RegisterHotKey()
{
    var helper = new WindowInteropHelper(this);
    const uint VK_RIGHT = 0x27;
    const uint VK_LEFT = 0x25;
    const uint VK_SPACE = 0x20;
    const uint MOD_ALT = 0x0001;
    const uint MOD_CTRL = 0x0002;

    if (!RegisterHotKey(helper.Handle, HOTKEY_ID+2, MOD_CTRL + MOD_ALT, VK_RIGHT))
    {
        // handle error
    }
    if (!RegisterHotKey(helper.Handle, HOTKEY_ID+1, MOD_CTRL + MOD_ALT, VK_LEFT))
    {
        // handle error
    }
    if (!RegisterHotKey(helper.Handle, HOTKEY_ID, MOD_CTRL + MOD_ALT, VK_SPACE))
    {
        // handle error
    }
}


Nun braucht es nur noch die Funktion, welche die gewünschten Aktionen ausführt, wenn man einen Hotkey drückt:

private void OnHotKeyPressed(int key)//9000 = space, 9001 = left, 9002 = right
{
    //System.Console.Write("KeyPressed! {0}\n", key);
    switch (key)
    {
        case 9000: if (playing) { pause(); } else { play(); }
            break;
        case 9001: back();
            break;
        case 9002: next();
            break;
        default:
            break;
    }
    // do stuff
}


Was genau hier passiert ist auch relativ simpel zu erkennen und sollte selbsterklärend sein. Für die Hotkeys muss man nun weiter nichts mehr tun. Zu beachten ist jedoch, dass diese Hotkeys nur bei meinem Programm funktionieren, solange es offen ist. Würde ich also z.B. "AltGr" + "0" als Hotkey nehmen, so könnte ich kein } mehr schreiben, während das Programm läuft.

Mittwoch, 21. August 2013

PHP - Chat auf eigenem Server "sicher" machen

(English version) Einen Chat mit PHP zu realisieren ist nicht weiter schwer. Relativ schnell merkt man dann auch, dass man Bilder und alles über HTML-Code einfügen kann. Das heißt aber auch, dass man PHP-Code ausführen kann. Das ist natürlich eine große Sicherheitslücke, mit den entsprechenden Befehlen kann man so z.B. den Server formatieren oder ähnliches.

Um das Ausführen von Code zu verhindern kann man nun wie folgt vorgehen: Bevor die Chatnachricht angezeigt wird, wird z.B. das < Symbol durch das entsprechende HTML-Äquivalent ersetzt. Dies wäre &lt;. In PHP funktioniert das so: $chatMessage = str_replace("<", "&lt;", $chatMessage);. Nun kann man keinen PHP-Code mehr ausführen, leider jedoch auch keinen HTML-Code. Um HTML-Code wieder zu aktivieren könnte man z.B. detektieren, ob es sich um bestimmte HTML-Tags (Bild, Link) handelt oder nicht und dementsprechend das Zeichen austauschen.

Arduino als Logic Analyzer

Wie in einem meiner "Home Automation"-Beiträge versprochen, erkläre ich in diesem Beitrag, wie man ganz einfach in wenigen Schritten das Arduino-Board als einen Logic Analyzer verwenden kann.

Zuerst muss die nötige Software für den Arduino herunter geladen werden. Diese ist HIER erhältlich. Je nachdem, ob ihr Sampling-Raten von 2 oder 4 Mhz benötigt oder ob euch maximal 1 Mhz ausreichen, muss dort der passende Sketch herunter geladen und auf den Arduino gespielt werden. Außerdem muss muss noch die Datei "ols.profile-agla.cfg" herunter geladen werden. Diese wird später benötigt.

Nachdem ihr den Sketch auf euren Arduino gespielt habt, könnte ihr probehalber den Serial Monitor öffnen, eine Baud-Rate von 115200 einstellen und entweder eine 1 oder eine 2 über die serielle Schnittstelle an den Arduino schicken. Wenn er mit einer Statusmeldung antwortet, hat soweit alles geklappt.

Als nächstes brauchen wir eine Software, die die analysierten Daten sauber auf dem PC darstellt. Dazu verwenden wir das Programm "Logic Sniffer". Das Programm basiert auf Java, kann also sowohl unter Windows als auch unter Linux verwendet werden. Ladet unter "Download" die neueste Version herunter und entpackt sie. In den Ordner "plugins" kommt die vorher herunter geladene Datei "ols.profile-agla.cfg. Nun kann das Programm gestartet werden - je nach OS mit run.bat oder run.sh. Es öffnet sich die Benutzeroberfläche:
Mit einem Klick auf "Capture"-"Begin capture" öffnet sich folgendes Fenster:
Hier stellt ihr den COM-Port ein, an dem der Arduino hängt. Im Zweifel muss auch die Baud-Rate noch passend eingestellt werden. Bei "Device type" muss der Arduino ausgewählt werden. Ein Klick auf "Show device metadata" sollte dann diverse Daten zum Vorschein bringen.
Im folgenden Reiter "Acquisition" können Details zur Datenerfassung wie z.B. die Sampling-Rate oder die Aufnahmegröße eingestellt werden.
Im letzten Reiter "Triggers" kann nun noch eingestellt werden, ob die Aufnahme durch einen Trigger gestartet werden soll. Ein Haken in der Mask-Reihe gibt an, welcher Kanal getriggert werden soll. Value gibt an, ob bei einem HIGH-Pegel (Haken gesetzt) oder bei einem LOW-Pegel (kein Haken gesetzt) aufgenommen werden soll. Die "Before/After ratio" gibt an, welcher Zeitraum vor und nach dem Trigger ausgegeben werden soll. Im abgebildeten Beispiel werden also 5% der Zeit VOR dem Trigger und 95% der Zeit NACH dem Trigger ausgegeben.

Falls noch nicht geschehen, schließt nun das zu untersuchende Signal an den Arduino an. Dabei entspricht der Kanal 0 dem Pin 8 am Arduino, Kanal 1 ist Pin 9 usw. 6 Kanäle werden unterstützt.

Wenn alles passend eingestellt und angeschlossen ist, kann der "Capture"-Knopf gedrückt werden. Wenn ihr alles richtig gemacht habt, solltet ihr nun euer Signal auf dem Bildschirm vor euch sehen:

Natürlich kann dieser Logic Analyzer nicht mit "großen" Geräten mithalten. Vorallem der Speicher für eure Aufnahmen ist begrenzt. Man kann also nur recht kurze Signale bei geringen Sampling-Raten untersuchen. Für kleine Projekte sollte es aber auf jeden Fall reichen.

Sonntag, 18. August 2013

"Home Automation" mit dem Arduino und 433 MHz - Der Rolladen, Teil 2

(English version) Die Theorie zur Steuerung des Rolladens ist bekannt - jetzt geht es an die praktische Ansteuerung.

Das Protokoll zur Steuerung des Rolladens ist ja wie bereits erwähnt sehr ähnlich dem Protokoll zur Steuerung der Funksteckdosen. Da lag es nahe, bei der Entwicklung der passenden Software nicht ganz bei Null anzufangen, sondern die bereits existierende und bewährte rc-switch-Library zu verwenden. Natürlich sind einige Anpassungen nötig.

Anpassungen rc-switch

Die Library bietet von Haus aus drei Protokolle für unterschiedliche Steckdosen. Diese unterscheiden sich hauptsächlich in der Pulslänge und der Form des Sync-Bits. Ich habe mich entschieden, für den Rolladen ein viertes Protokoll hinzuzufügen.

Die erste Anpassung muss also in der Funktion setProtocol() vorgenommen werden:

void RCSwitch::setProtocol(int nProtocol) {
  this->nProtocol = nProtocol;
  if (nProtocol == 1){
    this->setPulseLength(350);
  }
  else if (nProtocol == 2) {
    this->setPulseLength(650);
  }
  else if (nProtocol == 3) {
    this->setPulseLength(100);
  }
  //edit: Protokoll 4 für Rolladen mit Pulslänge 250ms und 4 Wiederholungen
  else if (nProtocol == 4) {
    this->setPulseLength(250);
    this->setRepeatTransmit(4);
  }
}

Alle Änderungen sind mit einem //edit-Kommentar markiert. Ich habe hier im Prinzip nur einen vierten else-if-Zweig für das Protokoll 4 eingefügt. Wird das Protokoll 4 gewählt, setzt der Code die Pulslänge (ein Puls entspricht einem Viertel) auf 250µs.Außerdem wird die Funktion setRepeatTransmit mit dem Parameter 4 aufgerufen. Dies bewirkt, dass jeder Befehl automatisch immer viermal gesendet wird (so wie es auch die Fernbedienung macht).

Als nächste Anpassung musste eine Funktion eingefügt werden, mit der das Senden eines Quad-State-Befehls möglich ist. Dafür habe ich einfach die sendTriState()-Funktion erweitert:

//edit: Quad-State-Befehl mit zusätzl. Q senden
void RCSwitch::sendQuadState(char* sCodeWord) {
  for (int nRepeat=0; nRepeat<nRepeatTransmit; nRepeat++) {
    //Syn-Bit wird hier VOR Übertragung gesendet!
 this->sendSync(); 
 int i = 0;
    while (sCodeWord[i] != '\0') {
      switch(sCodeWord[i]) {
        case '0':
          this->sendT0();
        break;
        case 'F':
          this->sendTF();
        break;
        case '1':
          this->sendT1();
        break;
        case 'Q':
          this->sendQQ();
        break;
      }
      i++;
    }   
  }
}

Ein großer Unterschied zwischen Rolladen und Steckdosen ist das Sync-Bit. Während es bei den Steckdosen erst NACH Übertragung des Befehls gesendet wird, muss beim Rolladen zuerst das Sync-Bit und dann der Befehl übertragen werden. Daher wird in der Funktion sendQuadState die Funktion sendSync() zu Beginn der Funktion aufgerufen - bei der ursprünglichen sendTriState()-Funktion erfolgte der Aufruf erst am Ende. Als weitere Änderung habe ich einen vierten Case eingefügt. Stößt das Programm beim "abarbeiten" des zu sendenden Codeworts auf ein Q, wird die (ebenfalls von mir eingefügt) Funktion sendQQ() aufgerufen.

/**
 * edit: Sends a Quad-State "Q" Bit
 *            ___   _
 * Waveform: |   |_| |___
 */
void RCSwitch::sendQQ() {
  this->transmit(3,1);
  this->transmit(1,3);
}

Die Funktion sendet mit transmit(3,1) zuerst ein langes HIGH-Signal, gefolgt von einem kurzen HIGH-Signal. Der erste Parameter der Funktion gibt an, wie viele Pulslängen die HIGH-Phase andauert. Der zweite Parameter gibt entsprechend die Länge der LOW-Phase an.

Die letzte Anpassung wurde in der Funktion zum Senden des Sync-Bits vorgenommen:

void RCSwitch::sendSync() {

    if (this->nProtocol == 1){
        this->transmit(1,31);
    }
    else if (this->nProtocol == 2) {
        this->transmit(1,10);
    }
    else if (this->nProtocol == 3) {
        this->transmit(1,71);
    }
 
    //edit: Syn-Bit für Rolladen
    else if (this->nProtocol == 4) {
        this->transmit(18,6);
    }
}

Das Sync-Bit des Rolladens besteht bekanntermaßen aus einer HIGH-Phase von 4500µs Dauer, gefolgt von einer 1500µs andauernden LOW-Phase. Das Sync-Bit besteht also aus 18 Pulslängen HIGH und 6 Pulslängen LOW (bei einer Pulslänge von 250µs).

Mit diesen kleinen Änderungen lässt sich die rc-switch Library nun auch zur Steuerung des Rolladens verwenden.

Jetzt wird es spannend

Nach so viel Theorie soll nun endlich der Praxistest erfolgen!

Also schnell ein kleines Programm zusammen gebastelt, dass unter Verwendung der modifizierten Library den Rolladen hoch und runter fahren lässt:

#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {
  Serial.begin(9600);
  Serial.println("Bereit...");
  mySwitch.enableTransmit(10);
  mySwitch.setProtocol(4);
}

void loop() {
  //runter
  Serial.println("Runter...");
  mySwitch.sendQuadState("0F0F0100QQ0F100F0101");
  mySwitch.sendQuadState("0F0F0100QQ0F100F0110");
  
  delay(5000);
  
  //Stopp
  Serial.println("Stopp...");
  mySwitch.sendQuadState("0F0F0100QQ0F100FFFFF");
  
  delay(1000);
  
  //rauf
  Serial.println("Rauf...");
  mySwitch.sendQuadState("0F0F0100QQ0F100F0F0F");
  mySwitch.sendQuadState("0F0F0100QQ0F100F0F1Q");
  
  delay(5000);
  
  //Stopp
  Serial.println("Stopp...");
  mySwitch.sendQuadState("0F0F0100QQ0F100FFFFF");
  
  delay(1000);
}

In der setup()-Funktion wird das Protkoll auf 4 gesetzt - sonst kann der Rolladen nichts mit dem Funksignal anfangen. In der loop()-Funktion werden dann mit der neuen sendQuadState()-Funktion zuerst die Befehle zum herunterlassen des Rolladens gesendet (woher die Befehle kommen habe ich in Teil 1 beschrieben). Dann wird 5 Sekunden lange gewartet, der Rolladen wird gestoppt, wieder herauf gefahren, nach 5 Sekunden wieder gestoppt usw.

Im letzten Schritt muss nun nur noch die Steuerung von Steckdose und Rolladen zusammengefasst werden, um die gewünschte Funktionalität (Steckdose an, Rolladen verfahren, Steckdose aus) zu erhalten.

Samstag, 17. August 2013

"Home Automation" mit dem Arduino und 433 MHz - Der Rolladen, Teil 1

(Englisch version) Seit meinem letzten Beitrag können wir bereits erfolgreich mit der Funksteckdose kommunizieren. Das Ein- und wieder Ausschalten des Stroms für den Rolladen ist also schonmal kein Problem. Der spannende Teil ist die Kommunikation mit dem Rolladen selbst. Bekannt ist nur, dass sie (wie bei der Steckdose) auf dem 433MHz-Band abläuft. Zum verwendeten Protokoll waren aber keine Infos aufzutreiben. Als erstes habe ich einfach mal die "ReceiveDemo" der rc-switch-Library compiliert, auf den Arduino übertragen und damit versucht, die Signale der Fernbedienung des Rolladens zu lesen. Wie zu erwarten war, hatte ich hier natürlich kein Glück. Die Demo kann nur die üblichen Prokolle der Funksteckdosen auslesen und konnte daher mit der Fernbedienung des Rolladens nichts anfangen.

Reverse Engineering

Um überhaupt einen groben Überblick über das verwendete Protokoll zu erhalten, müssten die Signale der Fernbedienung ausgelesen werden. Dies wäre am einfachsten zu erledigen mit einem Logic Analyzer. Leider habe ich solches Geräte nicht daheim herumfahren - das gibt das Budget nicht her ;)

Also ein bisschen Google bemüht und eine Möglichkeit gefunden, wie man den Arduino als einfachen Logic Analyzer benutzen kann. Wie genau das geht werde ich in einem seperaten Beitrag beschreiben.

Also habe ich einfach den Daten-Pin des Empfangsmoduls mit dem Logic-Analyzer-Arduino verbunden und konnte damit direkt das Signal der Fernbedienung auslesen.

Ein Druck auf den "Hoch"-Knopf lieferte folgendes Signal:

Runter ergab folgendes Signal:

Und Stopp:

Die Übertragung wird immer mit einer Art Sync-Bit gestartet. Dazu sendet die Fernbedienung erst 4500µs ein HIGH-Signal und dann für 1500µs ein LOW-Signal. Danach folgt die Datenübertragung. Das Muster ist ähnlich wie das Tri-State-System bei den Steckdosen - aber eben nur ähnlich. Neben den dort bekannten Zuständen 0, 1 und F ist hier noch ein vierter Zustand zu erkennen:
 _ _ _       _
|         | _ |   | _
Es handelt sich also im Prinzip um ein "Quad-State-System". Dementsprechend habe ich den vierten Zustand "Q" genannt. Ein "kurzes" Signal hat die Dauer von 250µs, ein "langes" dauert dementsprechend 750µs.

Theoretisch könnte man das Signal auch rein binär auswerten und ein kurzes HIGH-Signal als "0" und ein langes HIGH-Signal als "1" deuten. Dies wäre jedoch (meiner Meinung nach) unübersichtlich, da man mit ewig langen Ketten aus 0 und 1 hantieren müsste.

Die Signale können nun also nach dem Quad-State-System ausgewertet werden. Es ergeben sich dabei folgende übertragene Code-Wörter:
Hoch =   0F0F0100QQ0F100F 0F0F
Runter = 0F0F0100QQ0F100F 0101
Stopp =  0F0F0100QQ0F100F FFFF

Es fällt sofort auf, dass die ersten 16 Bits aller Codewörter identisch sind, lediglich die letzten 4 Bits unterscheiden sich. Es liegt also die Vermutung nahe, dass es sich bei den ersten 16 Bits um die Adresse des Rolladens handelt und bei den restlichen Bits um den Befehl.

Fernbedienung auslesen

Um das Signal der Fernbedienung einfach auslesen zu können, habe ich zunächst ein Programm geschrieben, das auf Signale wartet und diese dann im Quad-State-Format ausgibt.

int logfile[40];
int i = 0;
float lastTime = 0;
boolean capturing = false;
boolean checking = false;
boolean dataIncoming = false;

void setup() {
  Serial.begin(9600);
  Serial.println("Bereit...");
  pinMode(2, INPUT);
  attachInterrupt(0, handleInterrupt, CHANGE);
}

void loop() {
}

Zuerst werden diverse Variablen deklariert - unter anderem ein "logfile", in dem später der ausgelesene Code gespeichert wird. Die setup()-Funktion ist sehr übersichtlich, hier wird nur die serielle Verbindung gestartet sowie der Interrupt auf Pin 2 aktiviert (dort hängt der Daten-Pin des Empfangsmoduls). Der Interrupt wird jedes Mal aktiviert, wenn sich das Signal am Pin ändert.
Noch übersichtlicher ist die loop()-Funktion - sie ist komplett leer ;)

Die eigentliche "Arbeit" erfolgt in der Interrupt-Funktion:

void handleInterrupt() {

  if (!capturing) {  //wenn keine Aufnahme läuft
    if (!checking) {  //wenn nicht gerade auf "Start-Signal" geprüft wird
      if (digitalRead(2) == HIGH) {  //wenn Wechsel von LOW nach (jetzt) HIGH
        lastTime = micros();
        checking = true;
      }
    }

    else {    //wenn gerade auf Start-Signal geprüft wird
      if ((micros() - lastTime > 4000) && (digitalRead(2) == LOW)) {    //wenn HIGH-Phase länger als 4ms war und wir jetzt LOW sind
        //das war das Start-Signal
        checking = false;
        capturing = true;
        lastTime = micros();
      }

      else {
        //das war nicht das Start-Signal
        checking = false;
      }
    }
  }

  else {  //es läuft eine Aufnahme
    if (!dataIncoming) {  //bisher noch keine Nutzdaten empfangen
      if ((micros() - lastTime > 1000) && digitalRead(2) == HIGH) {  //das war die lange LOW-Phase vor Beginn der Übertragung
        dataIncoming = true; //ab jetzt kommen Daten  
        lastTime = micros();
      }
    }

    else {  //jetzt wird es interessant, jetzt kommen die Daten
      //wenn steigene Flanke (also jetzt HIGH)
      if (digitalRead(2) == HIGH) {
        //Beginn der HIGH-Phase merken
        lastTime = micros();
      }  

      //wenn fallende Flanke (also jetzt LOW) 
      else if (digitalRead(2) == LOW) {
        //=> prüfe wie lange HIGH war
        if (micros() - lastTime > 500) {
          //long
          logfile[i] = 1;
        }

        else {
          //short
          logfile[i] = 0;
        }

        if (i < 39) {
          //solange noch nicht alle Bits empfangen wurden
          i++;
        }

        else {
          //wir sind fertig
          noInterrupts();  //Interrupts aus damit Ausgabe nicht gestört wird
          Serial.println("Empfangene Daten:");
          //Ausgabe als "quad-bit"
          for (i = 0; i <= 38; i = i + 2) {
            if ((logfile[i] == 0) && (logfile[i+1] == 0))
              Serial.print("0");

            else if ((logfile[i] == 0) && (logfile[i+1] == 1))
              Serial.print("F");

            else if ((logfile[i] == 1) && (logfile[i+1] == 0))
              Serial.print("Q");

            else if ((logfile[i] == 1) && (logfile[i+1] == 1))
              Serial.print("1");
          }
          Serial.println();
          i = 0;
          dataIncoming = false;
          capturing = false;
          interrupts();  //Interrupts wieder an
          return;  //und alles auf Anfang
        }
      }

    }
  }
}

Sie besteht aus mehreren if-else-Abfragen, die den Zustand der diversen Bool-Variablen überprüfen. Als erstes wird überprüft, ob gerade eine "Aufnahme" läuft (capturing). Falls dies nicht der Fall ist, wird untersucht, ob gerade auf das Start-Signal (Sync-Bit) geprüft wird (checking). Falls dies auch nicht der Fall ist (und gerade ein Wechsel von LOW nach HIGH statt gefunden hat) merkt sich der Arduino die aktuelle Zeit und setzt "checking" auf true. Beim nächsten Flankenwechsel läuft das Programm also in den else-Zweig (es wird auf Start-Signal geprüft). Ist der Wechsel auf HIGH länger als 4000µs her kann man davon ausgehen, dass man soeben die lange HIGH-Phase des Sync-Bits empfangen hat. Also merkt sich der Arduino die Zeit, setzt checking auf false und capturing auf true. Dauerte die HIGH-Phase nicht lange genug, wird checking wieder auf false gesetzt, sonst geschieht nichts.

Wurde checking auf true gesetzt, läuft das Programm beim nächsten Flankenwechsel in den entsprechenden else-Zweig. In diesem Zweig wird als erstes geprüft, ob bereits Nutzdaten empfangen werden oder ob das Ende des Sync-Bits erwartet wird (dataIncoming). Das Auslesen der Nutzdaten verläuft relativ simpel. Bei steigender Flanke wird die aktuelle Zeit gespeichert. Bei fallender Flanke wie geprüft, ob die HIGH-Phase länger als 500µs (und somit lang) oder kürzer (und somit kurz) war. Dementsprechend wird im logfile eine 1 oder eine 0 gespeichert - intern arbeitet das Programm als mit dem "doofen" unübersichtlichen Binär-System ;)
Das Ganze wird insgesamt 40mal durchgeführt, dann wurde das komplette Signal empfangen.  Nun wird das empfangene Signal über die serielle Schnittstelle im Quad-State-Format ausgegeben und alle Bedingungen werden wieder auf ihren Ursprungszustand gesetzt. Dann wird das Programm mit dem return-Befehl neu gestartet.

Wurde alles passend verkabelt und das Programm auf den Arduino gespielt, sollte der Serielle Monitor nun bei jedem Druck auf eine Taste der Fernbedienung den passenden Code ausspucken.
Das klappt sogar auf Anhieb.

Dabei sind mir zwei Dinge aufgefallen, die bei der reinen Analyse mit dem Logic Analyzer nicht offensichtlich waren.
1. Die Fernbedieung sendet alle Signale jeweils 4mal - vermutlich um Übertragungsfehler auszuschließen
2. Der Signal zum hoch und runter fahren besteht jeweils aus zwei Befehlen: "hoch" sendet 4mal den schon bekannten Befehl "0F0F0100QQ0F100F 0F0F" gefolgt von 4mal "0F0F0100QQ0F100F 0F1Q" - "runter" ist entsprechend "0F0F0100QQ0F100F 0101" und "0F0F0100QQ0F100F 0110". Warum genau das so ist habe ich leider nicht heraus gefunden.

Im nächsten Beitrag werde ich beschreiben, wie man mit den so gewonnenen Erkenntnissen endlich den Rolladen steuern kann.

Montag, 12. August 2013

"Home Automation" mit dem Arduino und 433 MHz - Die Funksteckdose

(English version) Wie in meinem letzten Beitrag beschrieben, möchte ich mit den 433MHz-Funkmodulen Funksteckdosen ansteuern. Bei Pollin gibt es ein Set mit drei Steckdosen und einer Fernbedienung (die wir natürlich nicht brauchen werden ;) ) für unter 10 Euro: Klick mich! Zusätzliche Steckdosen können für 4,50€ zugekauft werden.

Für die Ansteuerung dieser Steckdosen gibt es (wie so oft) eine fertige Library für Arduino mit Namen rc-switch. Die Library kann sowohl Sender als auch Empfänger ansprechen. Mitgeliefert werden einige Beispiele, die das demonstrieren.

Übertragungsprotokoll

Bevor ich aber auf die Verwendung näher eingehe, möchte ich noch die Grundlagen des verwendeten Übertragungsprotokolls erläutern. Der Sender sendet im Prinzip nur eine Bitfolge in Form von HIGH- und LOW-Pegeln. Diese Bitfolge wird jedoch nicht als binäre Bitfolge (also nur 0 und 1), sondern als sogenannte Tri-State-Bitfolge ausgewertet. Wie der Name schon erahnen lässt, gibt es DREI ZUSTÄNDE (statt zwei bei rein binärer Übertragung). Die Zustände heißen 0, 1 und F, wobei F für "floating" steht. Dargestellt werden diese Zustände mit einer Folge HIGH-LOW-HIGH-LOW des Pegels. Die Abfolge von HIGH und LOW ist immer gleich, die Information wird über das Längenverhältnis von HIGH- und LOW-Phase übertragen.
Klingt vielleicht ein bisschen abstrakt, ist aber im Prinzip ganz einfach, wenn man es sich bildlich veranschaulicht:
ein Tri-State-Bit kann man sich wie zwei 4/4-Takte vorstellen. Jeweils eine HIGH-LOW-Folge entspricht einem Takt. Jeder Takt hat eine bestimmte Länge t. Der Takt wird in vier Teile mit der Länge t/4 geteilt. Nun gibt es zwei Möglichkeiten: entweder ist die HIGH-Phase länger als die LOW-Phase (3/4 der Zeit t HIGH und 1/4 LOW) oder umgekehrt.
Bildlich dargestellt:
 _ _ _                       _
|         | _  oder aber |   | _ _ _

Die drei Zustände werden dann folgendermaßen dargestellt:
 _            _
|   | _ _ _ |  | _ _ _ entspricht einer 0
 _ _ _       _ _ _                 
|         | _ |        | _ entspricht einer 1
 _            _ _ _
|   | _ _ _ |        | _ entspricht F

Drückt der Benutzer nun einen Knopf auf der Fernbedienung der Steckdosen, sendet diese zuerst die Adresse der gewünschten Steckdose sowie dem Befehl ("Ein" oder "Aus") im Tri-State-Format. Zum Schluss folgt ein Sync-Bit.

rc-switch und die Funksteckdosen

Mit dem Ganzen müssen wir uns aber eigentlich gar nicht auseinander setzen, denn wir haben ja rc-switch, unsere Library. Sie unterstützt alle möglichen Arten von Funksteckdosen von Haus aus.
Die Adressierung der Steckdosen erfolgt über DIP-Schalter:

Würde man die mitgelieferte Fernbedienung benutzen, müsste man hier mit den ersten fünf Schaltern den "System-Code" einstellen und mit den restlichen fünf, ob sich um Steckdose A, B, C, D oder E. handelt. In unserem Fall ist das aber egal, wir stellen einfach irgendeinen Code ein (in diesem Fall 11011'10000).

Nun bestromt man das Funkmodul, verbindet den DATA-Pin mit einem Pin des Arduinos und spielt folgendes Programm auf den Arduino:

#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {

  //Sender ist mit Pin 10 verbunden  
  mySwitch.enableTransmit(10);
  
}

void loop() {

  //Einschalten
  //der erste Parameter ist die Stellung der ersten fünf DIP-Schalter, 
  //der zweite Parameter die Stellung der restlichen fünf
  mySwitch.switchOn("11011", "10000");

  //Warte...
  delay(1000);
  
  //Ausschalten
  mySwitch.switchOff("11011", "10000");
  
  //Warte...
  delay(1000);
  
}

Im setup() teilen wir dem Programm mit, an welchem Pin unser Sender hängt. Im loop() schalten wir die Steckdose dann zuerst an, warten eine Sekunde, schalten sie wieder aus, warten wieder eine Sekunde usw.
Der Befehl switchOn bzw. switchOff mit den Parametern wird von der Library intern in eine Tri-State-Bitfolge bestehend aus der Adresse und dem Ein- bzw. Aus-Befehl umgewandelt. Bei der Umwandlung wird es ein bisschen verwirrend, eine 1 im Parameter der obigen Befehle wird nämlich zu einer 0 im Tri-State-Befehl. Eine 0 wird zum F. Umgewandelt in Tri-State wäre die Adresse der verwendeten Steckdose nun also 00F00'0FFFF. Der Befehl zum Einschalten der Steckdose lautet 0F, der zum Ausschalten F0.

Man könnte also statt dem "fertigen" switchOn()-Befehl auch den sendTriState()-Befehl der Library verwenden, um den Code zum Schalten der Steckdose "von Hand" zu senden:

void loop() {

  //Einschalten
  mySwitch.sendTriState("00F000FFFF0F");

  //Warte...
  delay(1000);
  
  //Ausschalten
  mySwitch.sendTriState("00F000FFFFF0");
  
  //Warte...
  delay(1000);
  
}  

Wer diese ganze Tri-State-Geschichte nicht mag und lieber mit "echten" Bits arbeitet, kann das Tri-State-Format dann auch noch ins "normale" Bit-Format umrechnen:
00F00'0FFFF'0F entspräche dann 0000010000'0001010101'0001 und 00F00'0FFFF'0F wäre entsprechend 0000010000'0001010101'0100. Diese Bitfolgen könnten dann mit dem Befehl
mySwitch.send("000001000000010101010001");
übertragen werden. Da hier jedoch die Übersicht flöten geht, lasse ich das bleiben ;)

Die Funksteckdosen können wir nun also ansprechen, als nächstes ist nun der Rolladen dran. Das wird ein bisschen spannender ;) Mehr dazu im nächsten Beitrag.

Sonntag, 11. August 2013

"Home Automation" mit dem Arduino und 433 MHz - Vorgeplänkel

Neben den 2,4GHz-Funkmodulen, zu denen ich bereits einige Gast-Beiträge in diesem Blog veröffentlicht habe, beschäftige ich mich auch noch mit dem 433MHz-Band. Meine Erfahrungen hier möchte ich in den kommenden Posts teilen. 

Vorgeschichte

In meiner Wohnung wurden vor einem Jahr elektrisch betriebene Rolläden nachgerüstet. Die Rolläden werden über eine kleine Fernbedienung über Funk gesteuert. Das schreit ja geradezu nach "Home Automation". So könnte man die Rolläden z.B. automatisch herunterfahren lassen, wenn die Sonne ins Zimmer scheint und während der Ferienzeit könnten die Läden abends und morgens "zufällig" runter- bzw. hochgelassen werden, um Einbrecher abzuschrecken.

Ein Blick auf die Rückseite der Fernbedienung bringt folgendes zutage:

Besser hätte es eigentlich gar nicht laufen können, bei dem 433MHz-Band handelt es sich um ein sogenanntes ISM-Band (Industrial, Scientific and Medical Band). Hier sind allerlei Funkalarmanlagen, Funkfernbedienungen und Funksteckdosen unterwegs. Daher gibt es für den geneigten Bastler äußert billige Sender und Empfänger, mit denen er sich auf diesem Band vergnügen kann (Suche bei Ebay nach "433 mhz transmitter receiver" und du wirst finden).

Standard ist die folgende Empfänger-Sender-Kombi, die man schon für 1 Euro frisch aus China ordern kann:
Links zu sehen ist das Empfangsmodul, rechts das Sendemodul. Die Module haben jeweils drei Anschlüsse (beim Empfänger sind die beiden mittleren Pins verbunden): VCC, GND und Data. Die Funktion ist somit denkbar einfach. Wird am Data-Pin des Senders ein HIGH-Signal angelegt, sendet er ebenfalls ein HIGH-Signal. Entsprechend umgekehrt ist es beim Empfänger: empfängt er ein HIGH-Signal, liegt am Data-Pin HIGH an - sonst LOW. Damit lassen sich dann sehr einfach Bitfolgen übertragen.

Der Plan

Der Motor des Rolladen hat einen "normalen" Schuko-Stecker und wird in der Wohnung in eine freie Steckdose gesteckt. Mir ist schon vor einiger Zeit unangenehm aufgefallen, dass der Motor auch im Standy-Modus einige Watt Leistung zieht. In Zeiten steigender Strompreise natürlich ein Unding ;) Da sich die Steckdose aber irgendwo hinter meinem Schreibtisch befindet, war ich bisher immer zu faul, den Motor bei Nichtgebrauch auszustecken. Viel komfortabler wäre hier eine Funksteckdose.
Wie schon erwähnt, funken auch die meisten Funksteckdosen im 433MHz-Band. Es lassen sich hier also zwei Fliegen mit einer Klappe schlagen. Ziel ist es, ein System zu entwicklen, das sowohl Rolladen als auch Steckdose ansprechen kann.
In der Anwendung soll das dann in etwa so aussehen: möchte man den Rolladen schließen, drückt man den entsprechenden Knopf. Das System schaltet dann zuerst die Funksteckdose an. Dann bekommt der Motor sein Signal, um den Rolladen abzusenken. Ist der Vorgang abgeschlossen, wird die Funksteckdose wieder ausgeschaltet und der Bewohner kann mit gutem Gewissen ins Bett gehen.

Klingt theoretisch ganz einfach, zumindest der Teil mit der Steckdose ist es in der Praxis auch. Mit dem Rolladen wird es ein bisschen spannender, doch dazu in meinem nächsten Beitrag mehr.