Twilight Anwendungsbeispiel

Aus FHEMWiki
Zur Navigation springen Zur Suche springen

Das Modul Twilight errechnet verschiedene Dämmerungsphasen und kalkuliert daraus einen wetter- und dämmerungsabhängigen Lichtwert, der den Grad der Außenhelligkeit angibt. Hier soll an einem Beispiel der Einsatz dieses Moduls zur Steuerung eines Ambient-Lichtes und einer Vitrinenbeleuchtung gezeigt werden.

Ziel: eine indirekte Beleuchtung, z. B. im Wohnzimmer, soll, sobald es zu dämmern anfängt bzw. wetterabhängig schon früh "gefühlt" dunkler wird, eingeschaltet werden. In diesem Beispiel wird eine dimmbare indirekte Beleuchtung (ein LED-Lichtschlauch) verwendet. Die Helligkeit des Lichtschlauchs soll bei nur leichter Dämmerung maximal sein und soll sich dann bei Dunkelheit bis auf 20% reduzieren. Die Vitrinenbeleuchtung (ebenfalls LED) soll ebenfalls nur dann eingeschaltet sein, wenn es nicht taghell ist, da man die da sowieso nicht sieht. Nachts soll die Beleuchtung natürlich nicht an sein, dazu wird hier auf eine Variable "Anwesend" zurückgegriffen, die beim Autor als Indikator für Nacht und Abwesenheitsbetrieb verwendet wird. Dies kann individuell angepasst werden. Anwesend=2 bedeutet "Die Bewohner sind im Bett" und Anwesend=4 bedeutet "Die Bewohner sind abwesend".

Neben der automatischen Beleuchtung soll auch ein manuelles Eingreifen möglich sein. So kann über einen Wandtaster sowohl das AmbientLight als auch die Vitrinenbeleuchtung ein- oder ausgeschaltet werden, wobei die Automatik nach einer bestimmten Zeit automatisch wieder greifen soll. Hier werden ein Homematic-Schaltaktor und ein Homematic-Dimmer verwendet, das Beispiel lässt sich leicht auf andere Komponenten übertragen.

Zur Realisierung wurden einige Perl-Schnipsel in ein externes Modul ausgelagert, weil dies wesentlich übersichtlicher ist als die Inline-Definition in der fhem.cfg. Als Basis kann das Modul 99_Utils.pm genommen werden. Der Autor hat diese Datei kopiert, das Modul umbenannt, und den zusätzlichen Code eingetragen.

Definition des Twilight-Devices

Um überhaupt die Lichtwerte zur Verfügung zu haben, muss zunächst ein Twilight-Device erzeugt werden. Hierzu wird folgender Aufruf verwendet:

Syntax: define <name> Twilight <Längengrad> <Breitengrad> <Indoor_Horizont> <Yahoo-Wetter-ID>

Beispiel für Helgoland:

define T twilight 54.18258 7.885938 1 709403

Hier beispielhaft eine Eingabe direkt per telnet in FHEM auf Port 7072

Code

define T twilight 54.18258 7.885938 1 709403

list T
Internals:
   CFGFN
   DEF        54.18258 7.885938 1 709403
   INDOOR_HORIZON 1
   LATITUDE   54.18258
   LONGITUDE  7.885938
   NAME       THelgo
   NR         751
   STATE      6
   TYPE       Twilight
   WEATHER    709403
   WEATHER_HORIZON 6
   Readings:
     2012-03-30 08:40:34   light           6
     2012-03-30 08:40:34   nextEvent       ss_weather
     2012-03-30 08:40:34   nextEventTime   19:13:23
     2012-03-30 08:40:34   nextUpdate      08:55:34
     2012-03-30 08:40:34   sr              07:10:41
     2012-03-30 08:40:34   sr_astro        04:57:56
     2012-03-30 08:40:34   sr_civil        06:28:52
     2012-03-30 08:40:34   sr_indoor       07:17:33
     2012-03-30 08:40:34   sr_naut         05:45:13
     2012-03-30 08:40:34   sr_weather      07:51:46
     2012-03-30 08:40:34   ss              19:54:28
     2012-03-30 08:40:34   ss_astro        22:07:13
     2012-03-30 08:40:34   ss_civil        20:36:17
     2012-03-30 08:40:34   ss_indoor       19:47:36
     2012-03-30 08:40:34   ss_naut         21:19:56
     2012-03-30 08:40:34   ss_weather      19:13:23

Zu sehen ist hier die Übersicht der entsprechenden Dämmerungszeiten des aktuellen Tages (Details siehe FHEM commandref/Twilight).

Berechnung des Automatik-Wertes

In folgender Routine wird zunächst abhängig vom Lichtwert und der aktuellen Anwesenheit der Automatikwert für den Lichtschlauch und die Schrankbeleuchtung errechnet. Der Lichtschlauch ist ein Dimmer, erhält also Werte zwischen 0% und 100% und die Vitrine ist ein Schaltaktor, ist also entweder an oder aus.

 sub calc_a_schlauch{
  my $licht=ReadingsVal("T","light","6");
  my $anwesend=ReadingsVal("anwesend","state","4");
  if($licht eq 6 || $anwesend eq 2 || $anwesend eq 4){
    fhem "set a_schlauch 0" ;
    fhem "set a_schrank off";
  }elsif($licht<6 && $licht>3){
    fhem "set a_schlauch 100";
    fhem "set a_schrank on";
  }elsif($licht>2 && $licht<5){
    fhem "set a_schlauch 40";
    fhem "set a_schrank on";
  }elsif($licht<3){
    fhem "set a_schlauch 20";
    fhem "set a_schrank on";
  }
}

Die Ausgangsbedingungen "light" und "anwesend" werden zu Beginn abgefragt. In der darauffolgenden IF-Anweisung wird dann je nach Lichtstärke ein Wert für die beiden Automatikwerte gesetzt. Zu beachten ist, dass die Devices a_schlauch und a_schrank Dummy-Devices sind (siehe fhem.cfg unten). Hier wird noch nicht direkt geschaltet sondern nur ein Wert berechnet und zwischengespeichert.

Manuelle Schaltung Vitrine

Zur manuellen Schaltung wird durch das Drücken eines Tasters folgender Schnipsel ausgeführt, der dann den neuen Manuell-Wert berechnet:

sub calc_m_schrank{
  my $aktuell = ReadingsVal("m_schrank","state","auto");
  my $auto = ReadingsVal("a_schrank","state","off");
  if($aktuell eq "off" || ($aktuell eq "auto") && $auto eq "off"){
    fhem "set m_schrank on";
  }else{
    fhem "set m_schrank off";
  }
}

Die aktuellen Werte für Manuell und Automatik werden zunächst aus den Dummy-Devices abgefragt. Jetzt gibt es zwei Möglichkeiten. Wenn die Vitrine gerade in dem Zustand ist, dass sie schon manuell ausgeschaltet wurde (also $aktuell eq "off"), dann muss sie jetzt eingeschaltet werden. Dies muss auch dann passieren, wenn man gerade im Automatikmodus ist, und eben dieser gerade auf "off" steht. Dies ist wichtig, damit für den Anwender, dem nicht klar ist, in welcher Betriebsart die Beleuchtung gerade ist, bei jedem Tasterdruck auch ein sichtbarer Schaltvorgang ausgelöst wird.

Manuelle Schaltung LED-Schlauch

Die manuelle Schaltung des LED-Schlauchs ist noch etwas aufwendiger, da mehrere Dimmerstufen angefahren werden sollen:

sub calc_m_schlauch{
  my $aktuell = ReadingsVal("m_schlauch","state",0);
  my $auto = ReadingsVal("a_schlauch","state",0);
  if($aktuell==0 || ($aktuell==-1 && $auto==0)){
     fhem "set m_schlauch 100";
  }elsif($aktuell==100){
     fhem "set m_schlauch 30";
  }elsif($aktuell==30 || ($aktuell==-1 && $auto>0)){
     fhem "set m_schlauch 0";
  }else{
     fhem "set m_schlauch 0";
  }
}

Das Prinzip ist wie bei der Vitrine. Da hier mit numerischen Werten gearbeitet wird, ist die Bedeutung "Automatik" nicht als "auto" definiert sondern als Zahlenwert "-1". D.h. der Wert für "m_schlauch" kann zwischen -1 und 100 schwanken, wobei im Bereich 0-100 ein manueller Wert gesetzt wird und bei "-1" die Automatik greifen soll.

In der IF-Abfrage wird zunächst der Fall behandelt, dass das Licht komplett aus ist. Dies ist entweder der Fall, wenn es manuell aus ist oder die Automatik greift und diese aber auch auf "0" ist. Der zweite Zweig schaltet den manuellen Wert auf 30 runter, wenn dieser gerade auf 100 ist. In allen anderen Fällen wird das Licht im nächsten Schritt manuell ausgeschaltet.

Schalten der Aktoren

Letztlich müssen natürlich die Aktoren tatsächlich geschaltet werden. Dazu wird folgende "Treiber"-Routine genutzt, die die manuellen und automatischen Werte logisch kombiniert:

sub drive_schrank_schlauch{
  my $dimmer=dimvalue(ReadingsVal("dim_schlauch","state",0));
  my $man=ReadingsVal("m_schlauch","state",0);
  my $auto=ReadingsVal("a_schlauch","state",0);
  my $newvalue;
  my $zeit=60;

  if($man==-1){
    $newvalue=$auto;
  }else{
    $newvalue=$man;
    $zeit=5;
  }
  if($dimmer ne $newvalue){
    fhem "set dim_schlauch ".$newvalue." 84000 ".$zeit;
  }
  my $schrank=ReadingsVal("akt_schrank","state","off");
  $man=ReadingsVal("m_schrank","state","auto");
  $auto=ReadingsVal("a_schrank","state","off");
  if($man eq "auto"){
    $newvalue=$auto;
  }else{
    $newvalue=$man;
  }
  if($schrank ne $newvalue){
    fhem "set akt_schrank ".$newvalue;
  }

 }

Hier wird nun zuerst der LED-Schlauch und dann der Schrank behandelt. Zunächst wird sowohl der aktuelle Wert des tatsächlichen Aktors (hier: dim_schlauch) als auch die Manuell- und Automatik-Werte abgefragt. Die Variable $newvalue soll den neuen Schaltwert erhalten. Dies wird deswegen eingesetzt, um einen Schaltbefehl nur dann über Funk zu senden, wenn sich der Zustand geändert hat. Die Variable $zeit wird hier genutzt, um beim automatischen Schalten den Dimmer sehr langsam fahren zu lassen, so dass es zu keiner abrupten merklichen Helligkeitsänderung kommt. Dies geht nur mit Homematic-Dimmern.

In der folgenden IF-Abfrage wird geklärt, ob der Dimmer im manuellen oder automatischen Modus betrieben wird. Dementsprechend wird $newvalue gesetzt. Bei manuellem Betrieb wird die Zeit auf 5 Sekunden runtergesetzt, denn hier soll eine merkliche Helligkeitsänderung in kurzer Zeit nach dem Betätigen des Tasters erfolgen. Stellt sich dann in der kommenden Abfrage heraus, dass der aktuelle Wert des Aktors noch nicht dem von $newvalue entspricht, wird ein tatsächlicher Schaltvorgang ausgelöst. Die Zahl 84000 ist die Einschaltzeit des Dimmers (unwichtig hier, muss nur hoch genug sein, ist aus Sicherheitsgründen nicht auf 0=unendlich - so geht der Dimmer auch bei einem FHEM-Ausfall nach knapp 24 Stunden aus). Im weiteren Verlauf wird die Vitrine nach dem gleichen Prinzip geschaltet, wobei hier keine Zeit sinnvoll ist.

fhem.cfg

In der fhem.cfg müssen, damit die Schnipsel funktionieren, neben dem Twilight-Device auch die Dummy-Devices, die beiden Aktoren, und entsprechende At-/Notify-Defines eingetragen werden, die dafür sorgen, dass die Code-Schnipsel ausgeführt werden. Die Definition der beiden Aktoren ist hier nicht aufgeführt und muss individuell eingetragen werden.

define a_schlauch dummy
define m_schlauch dummy
define a_schrank dummy
define m_schrank dummy
define T twilight 54.18258 7.885938 1 709403
set m_schlauch -1
set m_schrank auto

define m_a_schlauch notify m_a_schlauch {calc_a_schlauch();;}
define n_abwesend_ambient notify anwesend {fhem "trigger m_a_schlauch";;}
define n_lightchange_ambient notify T:light.* {fhem "trigger m_a_schlauch";;}
define n_d_schlauch notify a_schlauch {drive_schrank_schlauch();;}
define n_d_schlauch2 notify m_schlauch {drive_schrank_schlauch();;}
define n_d_schrank notify a_schrank {drive_schrank_schlauch();;}
define n_d_schrank2 notify m_schrank {drive_schrank_schlauch();;}
define n_m_schlauch_reset notify m_schlauch {fhem "delete temp_at_m_schlauch_reset";;fhem "define temp_at_m_schlauch_reset at +01:00:00 set m_schlauch -1";;}
define n_m_schrank_reset notify m_schrank {fhem "delete temp_at_m_schrank_reset";;fhem "define temp_at_m_schrank_reset at +01:00:00 set m_schrank auto";;}
define n_m_schlauch notify taster_wohn:Btn1.off[^L]* {calc_m_schlauch();;}
define n_m_schrank notify taster_wohn:Btn2.on[^L]* {calc_m_schrank();;}

m_a_schlauch ist ein Makro, was hier überflüssig erscheint, aber sinnvoll ist, wenn man einen Perl-Aufruf von verschiedenen Stellen aus antriggern will, so ist man unabängig vom tatsächlichen Inhalt.

Die Berechnung wird also immer dann angetriggert, wenn entweder der Anwesenheitsstatus oder der Lichtwert sich verändert haben. Die folgenden Notifys reagieren auf Werteänderungen der Automatik- und Manuell-Dummys. Die nächsten beiden Notifys (n_m_schlauch_reset und n_m_schrank_reset) sorgen dafür, dass bei einer Änderung der Manuell-Werte durch das Drücken von Tastern, etc. der Wert nach einer Stunde wieder auf Automatik zurückfällt. Die letzten beiden Notifys reagieren auf genau diese Taster, wobei hier ein Homematic-Wandtaster eingesetzt wird, bei dem nur auf einen kurzen Tastendruck reagiert werden soll.

Der bisherige Code sieht nicht vor, mit den Tastern auch frühzeitig wieder auf Automatik zurückzuschalten. Das kann z. B. mit einem zusätzlichen Taster gemacht werden:

define n_tEingang_lichtReset notify taster_eingang:Btn1.offLong.* {lichtReset();;}

Hier wird auf den langen Tastendruck eines anderen Tasters reagiert, wobei dieser Notify zündet, sobald man den Taster länger als 0,4 Sekunden festhält, also noch bevor dieser losgelassen wird. Der Code von lichtReset kann dann mehr tun, als nur die beiden hier beschriebenen Beleuchtungen auf Automatik zu setzen. Beispiel:

sub lichtReset{
  fhem "set m_schlauch -1";
  fhem "set m_schrank auto";
  fhem "set akt_treppe off";
  fhem "set akt_eingang off";
  fhem "set akt_esszimmer off";
}

yahoo - Condition Codes

Condition code	Beschreibung		Internes Mapping in: sub Twilight_getWeatherHorizon
	0	tornado			25
	1	tropical storm		25
	2	hurricane		25
	3	severe thunderstorms	25
	4	thunderstorms		20
	5	mixed rain and snow	10
	6	mixed rain and sleet	10
	7	mixed snow and sleet	10
	8	freezing drizzle	10
	9	drizzle			10
	10	freezing rain		10
	11	showers			7
	12	showers			7
	13	snow flurries		7
	14	light snow showers	5
	15	blowing snow		10
	16	snow			10
	17	hail			6
	18	sleet			6
	19	dust			6
	20	foggy			10
	21	haze			6
	22	smoky			6
	23	blustery		6
	24	windy			6
	25	cold			6
	26	cloudy			6
	27	mostly cloudy (night)	5
	28	mostly cloudy (day)	5
	29	partly cloudy (night)	3
	30	partly cloudy (day)	3
	31	clear (night)		0
	32	sunny			0
	33	fair (night)		0
	34	fair (day)		0
	35	mixed rain and hail	7
	36	hot			0
	37	isolated thunderstorms	15
	38	scattered thunderstorms	15
	39	scattered thunderstorms	15
	40	scattered showers	9
	41	heavy snow		15
	42	scattered snow showers	8
	43	heavy snow		5
	44	partly cloudy		12
	45	thundershowers		6
	46	snow showers		8
	47	isolated thundershowers	8
		not available		1

Zusammenhang STATE und light

STATE wird beim Twilight-Modul von 0 - 11 durchgezählt.

0 -> vor astronomischen Aufgang, 1 -> vor nautischem Aufgang, 2 -> vor zivilem Aufgang, 3 -> vor Sonnenaufgang, 4 -> vor Indoor-Aufgang, 5 -> vor "Wetter-Aufgang", 6 -> vor "Wetter-Untergang" (also den meisten Tag lang)

Bis hierher ist light = STATE. Von nun an wird light wieder weniger (es wird ja dunkler) aber STATE schreitet vor, um Sonnenuntergänge von -aufgängen unterscheidbar zu machen.

7 -> vor Indoor-Untergang, 8 -> vor Sonnenuntergang, 9 -> vor zivilem Untergang, 10 -> vor nautischem Untergang, 11 -> vor astronomischem Untergang

Bitte auch bedenken, dass in der Nordhälfte Deutschlands die Sonne astronomisch im Sommer ca. 6 Wochen lang nicht untergeht, State wird also nicht alle Werte durchlaufen und light wird nie 0 sein.