Direkte Steuerung der FHT8v

WICHTIG: funktioniert nur mit einem CUL V3 oder neuer und culfw Version 1.30 oder neuer!

TFHT Protokoll (statisch T)T
HHHHHauscode in Hexadezimal12342. Raum 1334; 3. Raum 1434 usw. Erstes Byte um eins inkrementieren.
DDGerätenummer in Hexadezimal (bis zu 8 pro Raum)00Es werden alle Antriebe im Raum angesprochen
01Antrieb 1
02Antrieb 2
CCBefehl2fStellantrieb mit FHEM koppeln
A6öffnet den Stellantrieb in VV % (8bits in Hexadezimal)
VVWert000% bzw. Koppel BefehlStellwert in Prozent * 255 / 100 = dezimaler Wert
Den dezimalen Wert in den hexadezimalen Wert umrechnen.
1910%
3320%
4c30%
8552%
FF100%

BEISPIEL: T123400A64C öffnet alle Stellantriebe im Raum 1234 auf 30%.

Ein erster Prototyp

Diese Woche wurde meine ersten selbst entworfenen Platinen von eurocircuits.com geliefert.

Zunächst die Frontseite, die alle Komponenten aufnimmt, welche dies im Details sind, dazu später.
PCB front

Die Rückseite, die lediglich den 2X13 PIN Connector aufnimmt.
PCB backside

Zum Sortieren der Komponenten verwende ich Einweg Suppenschüsseln.
Assorted components

Alle Widerstände und die beiden ICs (MCP 3008 und MCP 23S17) sind aufgelötet.
ICs added

So gut wie fertig, Connector für den PIR Sensor und den IR Abstandssensor hinzugefügt, genauso wie der DHT22 (Temperatur und Luftfeuchte Sensor) und die 7-Segment Anzeigen.
DHT22 and connector for IR proximity added

Fertig montiert.
Fully loaded shield prototype

Um genug Abstand zu den Aufbauten des RaspberryPi zu erhalten, verwende ich extra hohe Header.
Stacking header für Raspberry Pi (extra tall)

Abschließend die fertige Platine auf dem Raspberry Pi.Prototype Shield on Raspberry Pi

7 Segment Anzeige am MCP23S17

Die Anzeige der Temperatur soll über zwei 7 Segment Anzeigen erfolgen. Um ein paar der kostbaren GPIO Ports des Pi zu sparen war die Verwendung eines Port Expander sinnvoll. Ich habe mich für den MCP23S17 entschieden, den man hier käuflich erwerben kann. Der MCP23S17 wird über den SPI Bus kontrolliert, das ist vorteilhaft, da die Anzeige über weitere 7 Segment Anzeigen erweitert werden kann die mit weiteren MCP23S17 am gleichen Bus gesteuert werden können. Der Port Expander verfügt über zwei Bänke mit jeweils 8 IO Ports, gerade genug um jeweils eine 7 Segment Anzeige zu steuern.

Das folgende Bild zeigt das Layout in der Fritzing Software.
7Segment mit MCP23S17

So sieht es dann letztendlich auf dem Experiementierbrett aus.
7Segment mit MCP23S17

Das Script wird mit zwei Parametern aufgerufen, z.B. perl ./7segments.pm 1 2. In diesem Fall erzeugt der Aufruf die Anzeige der Nummer 12. Jeglicher Parameter der nicht den Ziffern 0-9 entspricht schaltet das entsprechende 7 Segment Display aus.

#!/usr/bin/perl

use Device::BCM2835;
use strict;

# call set_debug(1) to do a non-destructive test on non-RPi hardware
# Device::BCM2835::set_debug(1);
Device::BCM2835::init()
|| die "Could not init library";

# Variables
my $test;
my $param1;
my $param2;

# read CLI params
($param1, $param2) = @ARGV;

if ($param1 !~ /[\d]/ || $param1 > 10) {
 $param1 = 10;
}

if ($param2 !~ /[\d]/ || $param2 > 10) {
 $param2 = 10;
}

# MCP23S17 Values
my $SPI_SLAVE_ADDR = 0x40;
my $SPI_IOCTRL     = 0x0A;
my $SPI_IODIRA     = 0x00;
my $SPI_IODIRB     = 0x01;
my $SPI_GPIOA      = 0x12;
my $SPI_GPIOB      = 0x13;

# MCP23S17-PINs
my $SCLK = 11;  # PIN11 = Serial-Clock
my $MOSI = 10;  # PIN10 = Master-Out-Slave-In
my $MISO = 9;   # PIN9  = Master-In-Slave-Out
my $CS   = 24;  # PIN24 = Chip-Select

# Digit Values
my @output10 = ( 0b10000001, 0b11100111, 0b10010010, 
                 0b11000010, 0b11100100, 0b11001000, 
                 0b10001000, 0b11100011, 0b10000000, 
                 0b11000000, 0b11111111 );
my @output1  = ( 0b10000001, 0b11111001, 0b01000101,
                 0b01100001, 0b00111001, 0b00100011,
                 0b00000011, 0b11110001, 0b00000001,
                 0b00100001, 0b11111111 );

# Set RPi pin 11 to be an OUTPUT
Device::BCM2835::gpio_fsel($SCLK, BCM2835_GPIO_FSEL_OUTP);
# Set RPi pin 10 to be an OUTPUT
Device::BCM2835::gpio_fsel($MOSI, BCM2835_GPIO_FSEL_OUTP);
# Set RPi pin 9 to be an INPUT
Device::BCM2835::gpio_fsel($MISO, BCM2835_GPIO_FSEL_INPT);
# Set RPi pin 24 to be an OUTPUT
Device::BCM2835::gpio_fsel($CS, BCM2835_GPIO_FSEL_OUTP);

# prepare the edge
Device::BCM2835::gpio_write($CS, 1);
Device::BCM2835::gpio_write($SCLK, 0);

# subroutine sendValue
sub sendValue {
 # send value
 my $i = 0;
 my $value;
 ($value) = @_;
 while ($i < 8) {
   if ($value & 0x80) {
     Device::BCM2835::gpio_write($MOSI, 1);
   } else {
     Device::BCM2835::gpio_write($MOSI, 0);
   }
   # generate falling edge for the clock signals
   Device::BCM2835::gpio_write($SCLK, 1);
   Device::BCM2835::gpio_write($SCLK, 0);
   $value <<= 1; # shift bit 1 position to the left
   $i ++;
 }
}

# subroutine sendSPI
sub sendSPI {
 # CS active (LOW-Aktiv)
 Device::BCM2835::gpio_write($CS, 0);

 my($opcode, $addr, $data);
 ($opcode, $addr, $data) = @_;

 $test = &sendValue($opcode); # send OP-Code
 $test = &sendValue($addr);   # send address
 $test = &sendValue($data);   # send data

 # CS not active
 Device::BCM2835::gpio_write($CS, 1);
}

# Initialise MCP23S17
$test = &sendSPI($SPI_SLAVE_ADDR, $SPI_IODIRB, 0x00); # GPPIOB as INPUT
$test = &sendSPI($SPI_SLAVE_ADDR, $SPI_GPIOB, 0x00);  # Reset GPIOB
$test = &sendSPI($SPI_SLAVE_ADDR, $SPI_IODIRA, 0x00); # GPPIOA as INPUT
$test = &sendSPI($SPI_SLAVE_ADDR, $SPI_GPIOA, 0x00);  # Reset GPIOA

# Send Data
$test = &sendSPI($SPI_SLAVE_ADDR, $SPI_GPIOB, $output10[$param1]);
$test = &sendSPI($SPI_SLAVE_ADDR, $SPI_GPIOA, $output1[$param2]);

Das großartige Tutorial von Erik Bartmann welches sich hier findet, hat mir sehr geholfen meinen Code zu erstellen. Noch mehr Informationen gibt es auf seiner Website unter http://erik-bartmann.de.

IR Abstands Sensor

Um Energie zu sparen möchte ich, dass das Display (welches noch hinzugefügt werden muss) nur aktiviert wird, wenn sich jemand in der Nähe des Gerätes befindet. Für die Umsetzung dieser Funktion entschied ich mich für den Einsatz eines vorgefertigten  IR Abstand Sensors von Sharp.

Der Sensor arbeitet rein analog, die abgegebene Spannung reicht von 3V, wenn ein Objekt sich circa 10 cm vor dem Sensor befindet, bis 0,4V, wenn das Objekt 80 cm entfernt ist. Leider verfügt aber der Raspberry Pi nicht über analoge Eingänge um diesen Sensor direkt auszuwerten.

Meine Rettung war der grossartige Artikel von Matt @ raspberry-spy.co.uk, in dem er erklärt wie man unterschiedliche Lichtstärken mit dem Raspberry Pi misst.

Also begann ich damit seine Schaltung nachzubauen und führte ein paar erfolgreiche Testmessungen durch. Das folgende Bild zeigt den Aufbau auf meinem  Experimentierbrett.
LDR with capacitor

Weitere Details inklusive eines Fritzing Layouts finden sich in Matts Artikel. Nachdem ich die Schaltung erfolgreich kopiert hatte, habe ich den Widerstand und den Lichtsensor durch den IR Abstands Sensor ersetzt.
IR distance sensor on breadboard

Mit dem folgenden Quellcode zähle ich, wie viele Schleifendurchläufe erforderlich sind bis die Spannung über den Kondensator so weit angestiegen ist, so dass sie vom Raspberry Pi am GPIO Pin als HIGH erkannt wird (ungefähr 2 Volt). Die Anzahl der Schleifendurchläufe ist direkt proportional zum Abstand des Objektes vor dem Sensor.

 #!/usr/bin/perl

use Device::BCM2835;
 use strict;

# call set_debug(1) to do a non-destructive test on non-RPi hardware
 # Device::BCM2835::set_debug(1);
 Device::BCM2835::init()
 || die "Could not init library";

# Variables
 my $ir_pin = 24;
 my $measurement =0;

# logfile handling
 sub logging {

my $logfile = "/appco.de/log/appco.de.log";

if ( ! open LOG, ">>", $logfile ) {
 die "Kann Logdatei nicht anlegen: $!";
 }

my ($sekunden, $minuten, $stunde, $tag, $monat, $jahr) = localtime;
 my $echtes_jahr = $jahr + 1900;
 my $echter_monat = $monat + 1;
 printf LOG "%s.%02s.%02s %02s:%02s:%02s %s\n", $echtes_jahr, $echter_monat, $tag, $stunde, $minuten, $sekunden, $_[0];
 close LOG;

}

while (1){
 # Discharge capacitor
 # Set GPIO pin to OUTPUT
 Device::BCM2835::gpio_fsel($ir_pin, BCM2835_GPIO_FSEL_OUTP);
 # Set GPIO pin to LOW
 Device::BCM2835::gpio_write($ir_pin, LOW);
 sleep (0.1);

# Set GPIO pin to INPUT
 Device::BCM2835::gpio_fsel($ir_pin, BCM2835_GPIO_FSEL_INPT);

$measurement = 0;

# Count loops until voltage across
 # capacitor reads high on GPIO
 while (Device::BCM2835::gpio_lev($ir_pin) == 0){
 $measurement ++;
 sleep (0.2);
 # stop measuring after 100.000 loops
 if ($measurement > 100000){
 &logging ("canceled");
 last;
 }
 }

&logging ("$measurement");

}
 

Aktuell ist der Sensor dauerhaft angeschaltet, was vermutlich mehr Energie verbraucht als ich durch seinen Einsatz eigentlich sparen wollte.

In Zukunft soll der Sensor nur noch dann angeschaltet werden, wenn der PIR Sensor eine Bewegung erkannt hat. Außerdem soll der fertig gekaufte Sensor durch eine eigene Lösung bestehend aus IR LEDs und einem IR Empfänger ersetzt werden.

Temperatur und Luftfeuchte Sensor

Da mein Raspberry Pi die Heizungssteuerung übernehmen soll, braucht er Temperatur und Luftfeuchtigkeitswerte. Dazu habe ich mir einen Kombi Sensor, den DHT22, von Adafruit bestellt. Der Sensor kommt bereits mit dem benötigten 4.7K – 10K Widerstand, dieser wird als Pull-Up Widerstand vom GPIO Pin zu VCC verwendet.

Ursprünglich wollte ich den DHT22 Sensor mit perl auslesen. Nach einiger Zeit wurde klar, dass perl auf dem Raspberry Pi nicht schnell genug ist um erfolgreich Werte auslesen zu können.

An diesem Punkt entschied ich den Quellcode von Adafruit (verfügbar auf Github) zu nutzen und diesen einfach aus meinem perl Skript anzusteuern. Eine sehr gute Anleitung zum DHT22 gibt es von Adafruit hier.

Das folgende Bild zeigt die Anordnung auf dem Experimentierbrett.
Temp/Hum Sensor

So sieht das Ganze dann in der Fritzing Experimentierbrett Ansicht aus
Temp/Hum Fritzing

Das Skript ruft den Adafruit C-Quellcode mit den Parametern 22 (für den Sensor Typ) und 4 (entspricht dem zu nutzenden GPIO Pin) auf. Da auch der Adafruit Code nicht immer in der Lage ist erfolgreich einen Messwert auszulesen habe ich eine kleine Schleife erstellt, die sicherstellt, dass nur dann ein Log Eintrag erfolgt, wenn erfolgreich ein Messwert genommen werden konnte. Um zu beobachten wie viele Durchläufe notwendig waren habe ich eine Zählvariable eingebaut. In der Praxis wird die Schleife normalerweise 2 bis 5 Mal durchlaufen. Das Maximum das ich bisher beobachten konnte waren 11 Durchläufe.

 #!/usr/bin/perl

# logfile handling
 sub logging {

my $logfile = "/appco.de/log/appco.de.log";

if ( ! open LOG, ">>", $logfile ) {
 die "Kann Logdatei nicht anlegen: $!";
 }

my ($sekunden, $minuten, $stunde, $tag, $monat, $jahr) = localtime;
 my $echtes_jahr = $jahr + 1900;
 my $echter_monat = $monat + 1;
 printf LOG "%s.%02s.%02s %02s:%02s:%02s %s\n", $echtes_jahr, $echter_monat, $tag, $stunde, $minuten, $sekunden, $_[0];
 close LOG;

}

my $bin = './Adafruit_DHT 22 4';
 my $check = 0;
 my $counter = 0;

#run until a temperature and humidity value has been logged
 while ($check == 0){
 # run the C program
 $result2 = `$bin`;

# extract the strings
 my @array = split("\n", $result2);

$counter = $counter + 1;

# logging only if the string is not empty
 if ($array[2] ne "") {
 &logging ("$array[2]");
 &logging ("$counter");
 $check = 1;
 }
 }
 

PIR Sensor

Da ich möchte, dass meine Hausautomatisierung in der Lage ist meinen Tagesablauf zu erlernen benötigt der Raspberry Pi ein paar Sensoren. Für den Anfang beginne ich mit einem PIR (passiver IR) Sensor.
Der Fritzing Screenshot unten zeigt wie der Sensor mit dem Cobbler verbunden wird. Im Prinzip wird das rote Kabel mit 5V0, das schwarze Kabel mit GND und das gelbe Kabel mit dem GPIO Pin 25 verbunden.
PIR Fritzing

Für einen ersten Test habe ich den folgenden Befehl von der Kommando Zeile aus ausgeführt.

 while true; do gpio read 6; done
 

Der Befehl gibt eine 0 aus, wenn der PIR nicht ausgelöst wurde und eine 1, wenn der PIR ausgelöst wurde.

Im nächsten Schritt habe ich die gleiche Funktionalität in einem einfachen perl Skript unter Verwendung des wiringPi-Perl Framework implementiert.

 #!/usr/local/bin/perl -w

use lib "/appco.de/WiringPi-Perl";

require "wiringpi.pm";

if (wiringpic::wiringPiSetup () == -1)
 { exit 0};

# set pin #6 (marked with #25 on the T-Cobbler) to mode INPUT
 wiringpic::pinMode (6, 0);

while (1){
 # read from PIR

# PIR not triggered
 if (wiringpic::digitalRead (6) == 0){
 print ("off \n");
 wiringpic::delay (500); # milliseconds
 }

# PIR triggered
 if (wiringpic::digitalRead (6) == 1){
 print ("on \n");
 wiringpic::delay (500); # milliseconds
 }
 }
 

Dieser Quellcode schreibt „off“ auf die Standard Ausgabe, wenn der PIR nicht ausgelöst wurde und „on“, wenn er ausgelöst wurde. Das Skript läuft bis er mit ctrl+c abgebrochen wird.

Sensoren für den Raspberry Pi

Angeregt von Nest® dem lernenden Thermostat möchte ich die Haussteuerungsfähigkeiten des Raspberry Pi mit ein paar Sensoren deutlich verbessern.

Temperature and humidity sensor
Wird eingesetzt um Temperatur und Luftfeuchtigkeit eines Raumes zu messen und das Heizungsventil entsprechend zu regeln. Der Grund warum hier der DHT22 und nicht der preiswertere DHT11 zum Einsatz kommt, ist die viel höhere Präzision, zum Beispiel für die Temperatur: ±0,5°C Abweichung (DHT22) gegenüber ±2°C Abweichung (DHT11). Nach meinem Verständnis sind ±2°C für die Temperatursteuerung in einem bewohnten Raum nicht akzeptabel.
Temp/Hum Sensor
Temperatur/Luftfeuchte Sensor (auf der rechten Seite) bereits komplett verkabelt.

PIR
Der Raspberry Pi soll erkennen ob sich Personen in einem Raum aufhalten und die Temperatur entsprechend steuern. Über die Zeit soll er in der Lage sein sich einen Zeitplan aufzubauen und ihn auch zu pflegen. Ich benutze diesen Sensor von adafruit.com
PIR Sensor

IR Abstand / Annäherung
Mit diesem Sensor sollte der Server in der Lage sein eine Person in der Nähe zu erkennen und das Userinterface zur Verfügung zu stellen. Zunächst einmal werde ich mit einem Sharp GP2Y0A21YK0F arbeiten und vielleicht später zu einer Eigenbau Lösung wechseln.
IR Distance Sensor

Raspberry Pi als Server für die Haussteuerung

Endlich ist er da, mein Raspberry Pi. Ich möchte ihn als Server für den perl basierten Hausautomatisierungsserver fhem nutzenhttp://fhem.de/fhem.html.

Dafür habe ich meinen Pi mit einem Mini USB WLAN Stick und einem CUL Device von Busware http://busware.de/tiki-index.php?page=CUL mit der culfw Firmware http://culfw.de/culfw.html erweitert
Raspberry Pi overview

Für die Installation des fhem Servers habe ich einfach die Anleitung unter http://www.fhemwiki.de/wiki/Raspberry_Pi befolgt.

Die Installation der culfw Firmware war etwas schwieriger, aber ließ sich mit den folgenden Schritten doch erfolgreich bewerkstelligen.

Die Firmware herunterladen
sudo wget http://culfw.de/culfw-1.46.tar.gz
entpacken
sudo tar -zxvf culfw-1.46.tar.gz

in das Device Verzeichnis wechseln (e.g. Devices/CUL)
cd /home/pi/CUL_VER_146/culfw/Devices/CUL
das Paket dfu-programmer installieren
sudo apt-get install dfu-programmer
Das Device mit gedrücktem Taster in die USB Buchse stecken
Abschließend
sudo make usbprogram_v3 V3 bei der Verwendung eines CUL V3
ausführen.
Danach sollte ein neues USB Gerät auftauchen: „03eb:204b Atmel Corp.“. Falls nicht das Gerät noch einmal einstecken, aber diesmal ohne den Taster gedrückt zu halten.

Mittlerweile läuft der Server seit einigen Tagen, tut aber noch nichts anders als den FS20 Verkehr abzuhören und zu protokollieren.

T4F4C00B600F7
T430D00362601
K51913145FC
T52396702FE
T52396782FD
K7114323738
T52396782FD

Ich benutze den S300TH Temperatur/Luftfeuchte Sensor im Arbeitszimmer für Test Zwecke, außerdem habe ich mir einen FHT80TF-2 Tür/Fenster Sensor und einen FHT8v elektrischen Ventilantrieb als Test Geräte zugelegt.
Breadboard and test devices

Ich will in Zukunft die FHT8v direkt vom Server aus steuern ohne die Notwendigkeit eine FHT80b einsetzen zu müssen. Normalerweise sollte das relativ einfach umzusetzen sein, allerdings war ein erster Test nicht erfolgreich.

Der Wettersensor ist defekt

Mein Wettersensor (OC-3) scheint defekt zu sein, er meldet konstant eine Luftfeuchtigkeit von 99%, wie man hier sehen kann http://wetter.appco.de. Bei der Suche nach Lösungen für diesen Fehler auf Google fand ich jemanden der ein paar Lötstellen erneuert hat und so den Fehler beheben konnte.

Da mein Sensor noch Garantie hat werde ich ihn zur Reparatur einsenden.

Vielleicht eine gute Möglichkeit eine Solarzelle zu ergänzen und so die Batterien dauerhaft loszuwerden.

Medien Wand

Je mehr die Haussteuerung wuchs, desto schneller wuchs auch der Wust an Kabeln. Die sich alle hinter Fernseher und AV Receiver sammelten.

Es war an der Zeit eine bessere Lösung zu finden. Ich wollte es stylish und einfach, aber war nicht bereit Kompromisse in Bezug auf die Anzahl meiner Gadgets einzugehen (oder deren zukünftiges Wachstum zu beschränken).

Meine Lösung ist eine Medien Wand, welche Fernseher, Mac mini, Apple TV und den AV Receiver beherbergt. Alles weitere soll dahinter verborgen werden und außerdem soll sie ein schicke Hintergrundbeleuchtung beherbergen.
Storage shelf

Als Basis für die Gerätschaften setze ich auf ein einfaches Regalsystem aus dem Baumarkt.

Einige der Geräte auf dem Bild haben es nicht in das finale Layout geschafft, nichtsdestotrotz war das Chaos, das die Kabel und Geräte hinter dem Fernseher hervorriefen war nicht zu verachten.
dry wall construction

Im nächsten Schritt wurde eine Gipskartonwand um das Regal herum errichtet.
OSB board layer

Um sicherzustellen, dass die Medien Wand auch größere und schwerere Fernseher tragen kann, wurde die erste Beplankung aus OSB Platten erstellt.
Final layout

Gefolgt von einer Lage Gipskarton und einer Probeaufstellung des finale Equipments. Die Medien Wand hat einen Abstand von ca. 25 cm zur Rückwand. Das Regal ist über die linke Seite erreichbar während die rechte Seite komplett verschlossen ist.
With wall-paper

Fast fertig und schon tapeziert.
Night view

So sieht die Medien Wand bei Nacht aus, wenn die LED Beleuchtung eingeschaltet ist. Die Farbe lässt sich über die Haussteuerung ändern.