DOIF/Automatisierung: Unterschied zwischen den Versionen
(133 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
An dieser Stelle werden Lösungen für | An dieser Stelle werden Lösungen für praxisrelevante Automatisierungsaufgaben mit Hilfe des DOIF-Moduls vorgestellt. Insbesondere werden mit Hilfe von Templates generische DOIF-Lösungen an konkreten Beispielen dargestellt, die für mehrere Szenarien nutzbar sind.<br> | ||
<br> | <br> | ||
Die folgenden Beispieldefinitionen arbeiten mit konkreten Geräten und Readings, sie können als RAW-Definition ins eigene System übernommen werden, dazu müssen die Gerätenamen, Readings, ggf. auch Icons den existierenden Namen des eigenen Systems angepasst werden. Zum Ausprobieren der Beispiele können statt echter Geräte auch Dummys benutzt werden.<br> | Die folgenden Beispieldefinitionen arbeiten mit konkreten Geräten und Readings, sie können als RAW-Definition ins eigene System übernommen werden, dazu müssen die Gerätenamen, Readings, ggf. auch Icons den existierenden Namen des eigenen Systems angepasst werden. Zum Ausprobieren der Beispiele können statt echter Geräte auch Dummys benutzt werden.<br> | ||
<br> | <br> | ||
== Licht == | == Licht == | ||
Zeile 85: | Zeile 83: | ||
Anforderung: | Anforderung: | ||
* Es soll nur eine Steuerung für mehrere Lichtszenarien programmiert werden. | * Es soll nur eine Steuerung für mehrere Lichtszenarien programmiert werden. | ||
* | * Ein Lichtszenario soll durch folgende Angaben definierbar sein: Szenario-Name, Daemmerungssensor (on/off), Zeitspanne, Einschaltbefehl, Ausschaltbefehl | ||
* Ein neues Szenario soll durch hinzufügen einer Parameterzeile erstellt werden können. | |||
* | * Erstellte Lichtszenarien sollen tabellarisch dargestellt werden und über Weboberfläche einzeln schaltbar sein: auto/on/off | ||
* Erstellte Lichtszenarien sollen tabellarisch dargestellt werden und einzeln | |||
'''Beispieldefinition''' | '''Beispieldefinition''' | ||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
defmod di_Licht_all DOIF subs {\ | defmod di_Licht_all DOIF subs {\ | ||
## | ## Ein Szenario wird durch Hinzufügen einer Definitionszeile erstellt\ | ||
## Szene Dämmerungssensor Zeitspanne Einschaltbefehl Ausschaltbefehl\ | |||
## | push (@{$_sc},["Erdgeschoss","Daemmerung2", "[06:25-08:00|8] or [15:00-23:30]", "Lampekueche,Lampeflur on", "Lampekueche,Lampeflur off"]);;\ | ||
push (@{$ | push (@{$_sc},["Kinderz_2", "Daemmerung2", "[06:25-08:00|8] or [15:00-23:10]", "schrank2 on", "schrank2 off"]);;\ | ||
push (@{$ | push (@{$_sc},["Terrasse", "Dunkelheit", "[16:00-23:30]", "Terrasse on", "Terrasse off"]);;\ | ||
push (@{$ | push (@{$_sc},["Garten", "Dunkelheit", "[16:00-23:30]", "Garten pct 50", "Garten off"]);;\ | ||
push (@{$ | push (@{$_sc},["Strauch1", "Dunkelheit", "[17:00-23:05]", "Strauch1 on", "Strauch1 off"]);;\ | ||
push (@{$_sc},["Strauch2", "Dunkelheit", "[17:00-23:05]", "Strauch2 on", "Strauch2 off"]);;\ | |||
push (@{$_sc},["Eingang", "Dunkelheit", "[17:00-23:35]", "Aussenbeleuchtung on", "Aussenbeleuchtung off"]);;\ | |||
\ | \ | ||
\ | \ | ||
## Bei Änderung der Definition werden | ## Bei Änderung der Definition werden erfoderliche Readings erstellt und vorbelegt\ | ||
if ($::init_done) {\ | if ($::init_done) {\ | ||
fhem("deletereading $SELF .*");;\ | fhem("deletereading $SELF .*");;\ | ||
set_State("initialized");;\ | set_State("initialized");;\ | ||
for (my $i=0;;$i < @{$ | for (my $i=0;;$i < @{$_sc};;$i++) {\ | ||
set_Reading ($_sc[$i][0].".Status","off");;\ | |||
set_Reading ($ | set_Reading ($_sc[$i][0].".aktiv","off");;\ | ||
}\ | }\ | ||
}\ | }\ | ||
Zeile 118: | Zeile 113: | ||
\ | \ | ||
DEF TPL_light ( ## Definition des Templates namens TPL_light\ | DEF TPL_light ( ## Definition des Templates namens TPL_light\ | ||
light_$1 { | light_$1 { ## Parameter: Szene Daemmerung Zeitspanne on off \ | ||
## $1 $2 $3 $4 $5\ | |||
if ([$SELF:$1.aktiv] eq "auto") {\ | |||
if ([ | |||
if (($3) and [$2] eq "on") {\ | if (($3) and [$2] eq "on") {\ | ||
fhem_set($4);;\ | fhem_set($4);;\ | ||
set_Reading("$1.Status","on",1);;\ | set_Reading("$1.Status","on",1);;\ | ||
} else {\ | } else {\ | ||
Zeile 132: | Zeile 125: | ||
}\ | }\ | ||
} ## Ende des light-Blocks\ | } ## Ende des light-Blocks\ | ||
\ | |||
active_$1 {\ | |||
if ([$SELF:$1.aktiv] eq "on") {\ | |||
fhem_set ($4);;\ | |||
set_Reading("$1.Status","on",1);;\ | |||
}\ | |||
if ([$SELF:$1.aktiv] eq "off") {\ | |||
fhem_set ($5);;\ | |||
set_Reading("$1.Status","off",1);;\ | |||
}\ | |||
} ## Ende des active-Blocks \ | |||
) ## Ende der Templatedefinition\ | ) ## Ende der Templatedefinition\ | ||
\ | \ | ||
## Generierung der Steuerung pro | ## Generierung der Steuerung pro Licht-Szene mit Hilfe des obigen Templates\ | ||
FOR (@{$ | FOR (@{$_sc},TPL_light($_$1,$_$2,$_$3,"$_$4","$_$5")) | ||
attr di_Licht_all room Licht | |||
attr di_Licht_all uiTable {\ | attr di_Licht_all uiTable {\ | ||
package ui_Table;;\ | package ui_Table;;\ | ||
$TC{1.. | $TC{1..5}="style='padding-left: 2px;; padding-right: 2px;;' align='center'";;\ | ||
\ | |||
}\ | }\ | ||
\ | \ | ||
## Überschrift der | ## Überschrift der Parameter\ | ||
"Szene"|"Dämmerung"|"Zeitspanne"|" | "Szene"|"Dämmerung"|"Zeitspanne"|"Status"|"ausgeführt"|"aktiv"\ | ||
\ | \ | ||
## Pro Datensatz einer | ## Pro Datensatz einer Licht-Szene wird eine Zeile mit Werten und Widgets generiert\ | ||
FOR (@{$VAR{sc}},"$_$1"|icon([$_$2])|"$_$3"| | FOR (@{$VAR{sc}},"$_$1"|icon([$_$2])|"$_$3"|icon([$SELF:$_$1.Status])|::ReadingsTimestamp("$SELF","$_$1.Status",0)|WID([$SELF:$_$1.aktiv],"select,auto,on,off")) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | ''Ergebnis der Beispieldefinition in der Webansicht:'' | ||
[[Datei:Licht_Szenarien.png| | [[Datei:Licht_Szenarien.png|600px|ohne]] | ||
== Beschattung == | == Beschattung == | ||
Zeile 172: | Zeile 179: | ||
'''Beispieldefinition des Steuermoduls''' | '''Beispieldefinition des Steuermoduls''' | ||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
defmod | defmod di_beschattung1 DOIF DEF TPL_shutter ( ## Definition des Templates namens TPL_shutter\ | ||
## Parameternummer $1 $2 $3 $4 $5 $6 $7 $8 \ | ## Parameternummer $1 $2 $3 $4 $5 $6 $7 $8 \ | ||
## Bedeutung Name der Szene Temperatursensor des Zimmers Sonnensensor von Uhrzeit bis Uhrzeit Rollladen Befehl zum Herunterfahren Befehl zum Hochfahren\ | ## Bedeutung Name der Szene Temperatursensor des Zimmers Sonnensensor von Uhrzeit bis Uhrzeit Rollladen Befehl zum Herunterfahren Befehl zum Hochfahren\ | ||
shutter_$1 { | shutter_$1 { ## DOIF Block\ | ||
## | if ([$4-$5]) { ## innerhalb des Zeitfensters \ | ||
if ([$2:measured-temp] > 24 and [$3] eq "on" and !$VAR{$1}) { ## Wenn die Zimmertemperatur über 24 und Sonne scheint und die Rollläden noch nicht heruntergefahren wurden\ | |||
fhem_set("$6 $7");; ## Fenster herunterfahren\ | |||
set_State("Szene: $1 Beschattung");; ## Status mit letztem Befehl belegen \ | |||
$VAR{$1}=1;; ## Merker setzen, dass Fenster bereits heruntergefahren wurde\ | |||
} elsif ([$2:measured-temp] < 23.5 and [$3] eq "off" and $VAR{$1}) { ## Wenn die Zimmertemperatur unter 23.5 und Sonne scheint nicht und die Rollläden bereits heruntergefahren wurden\ | |||
fhem_set("$6 $8");; ## Fenster hochfahren\ | |||
set_State("Szene: $1 keine Beschattung");; ## Status mit letztem Befehl belegen \ | |||
$VAR{$1}=0;; ## Merker zurücksetzen\ | |||
}\ | |||
} \ | |||
}\ | }\ | ||
) ## Ende der Templatedefinition\ | ) ## Ende der Templatedefinition\ | ||
\ | \ | ||
reset {[00:01];;delete $VAR;;} ## DOIF-Block namens reset um nachts alle Merker zu löschen | reset {[00:01];;delete $VAR;;} ## DOIF-Block namens reset um nachts alle Merker zu löschen\ | ||
\ | |||
## Definition einzelner DOIF-Blöcke pro Fenstergruppe mit Hilfe des Templates\ | ## Definition einzelner DOIF-Blöcke pro Fenstergruppe mit Hilfe des Templates\ | ||
## $1 $2 $3 $4 $5 $6 $7 $8\ | ## $1 $2 $3 $4 $5 $6 $7 $8\ | ||
Zeile 208: | Zeile 216: | ||
* [https://fhem.de/commandref_DE.html#DOIF_Perl_Modus siehe Commandref: DOIF-Perlmodus] | * [https://fhem.de/commandref_DE.html#DOIF_Perl_Modus siehe Commandref: DOIF-Perlmodus] | ||
*[https://wiki.fhem.de/wiki/DOIF/Automatisierung#Beschattungssteuerung_abh.C3.A4ngig_von_der_Zimmertemperatur_und_Sonneneinstrahlung_f.C3.BCr_mehrere_Szenarien siehe: Beschattungssteuerung ohne Visualisierung] | *[https://wiki.fhem.de/wiki/DOIF/Automatisierung#Beschattungssteuerung_abh.C3.A4ngig_von_der_Zimmertemperatur_und_Sonneneinstrahlung_f.C3.BCr_mehrere_Szenarien siehe: Beschattungssteuerung ohne Visualisierung] | ||
* [https:// | * [https://wiki.fhem.de/wiki/DOIF/Templates siehe: Generalisierung mit Templates] | ||
}} | }} | ||
Anforderung: | Anforderung: | ||
Zeile 218: | Zeile 226: | ||
<syntaxhighlight lang="perl"> | <syntaxhighlight lang="perl"> | ||
defmod di_beschattung2 DOIF subs {\ | defmod di_beschattung2 DOIF subs {\ | ||
@{$_params}= qw( Szene Temperatursensor Sonnensensor Rollladen runter hoch von bis Status aktiv);;\ | |||
@{$ | \ | ||
## Definition einzelner Datensätze pro Szene\ | ## Definition einzelner Datensätze pro Szene, Szenen können zeilenweise gelöscht bzw. hinzugefügt werden\ | ||
push (@{$ | push (@{$_sc},[qw(Bad TH_Bad_HM Sonne_s R_Bad 30 on 13:00 22:00 off on)]);;\ | ||
push (@{$ | push (@{$_sc},[qw(Dachgeschoss TH_DG_HM Sonne_s R_Dachboden 30 on 13:00 22:00 off on)]);;\ | ||
push (@{$ | push (@{$_sc},[qw(Kueche TH_Kueche_HM Sonne_s R_Kueche 50 on 09:00 14:00 off on)]);;\ | ||
push (@{$ | push (@{$_sc},[qw(Kinderzimmer_1_ost TH_Kz_o_HM Sonne_s R_Kinderzimmer1_O 30 on 09:00 14:00 off on)]);;\ | ||
push (@{$ | push (@{$_sc},[qw(Kinderzimmer_1_sued TH_Kz_o_HM Sonne_s R_Kinderzimmer1_S 25 on 13:00 22:00 off on)]);;\ | ||
push (@{$ | push (@{$_sc},[qw(Kinderzimmer_2_sued TH_Kz_w_HM Sonne_s R_Kinderzimmer2_S 25 on 13:00 22:00 off on)]);;\ | ||
push (@{$ | push (@{$_sc},[qw(Kinderzimmer_2_west TH_Kz_w_HM Sonne_w R_Kinderzimmer2_W.* 25 on 15:30 22:00 off on)]);;\ | ||
push (@{$ | push (@{$_sc},[qw(Wohnzimmer_west TH_WZ_HM Sonne_w R_W_W[23] 25 on 15:30 22:00 off on)]);;\ | ||
\ | \ | ||
if ($::init_done) { | if ($::init_done) { ## Bei Änderung der Definition werden alle erfoderlichen Readings erstellt und vorbelegt\ | ||
fhem("deletereading $SELF .*");; | fhem("deletereading $SELF .*");; ## alle Readings des Moduls löschen\ | ||
set_State("initialized");; ## Status setzen\ | |||
for (my $i=0;;$i < @{$_sc};;$i++) {\ | |||
set_State("initialized");; | for (my $j=6;;$j < @{$_sc[$i]};;$j++) { ## für Parameter 7 bis 10 Readings anlegen\ | ||
for (my $i=0;;$i < @ | set_Reading ($_sc[$i][0].".".$_params[$j],$_sc[$i][$j]);;\ | ||
for (my $j=6;;$j < @{$ | |||
set_Reading ($ | |||
}\ | }\ | ||
}\ | }\ | ||
}\ | }\ | ||
\ | \ | ||
sub reset_state { | sub reset_state {\ | ||
for (my $i=0;;$i < @{$_sc};;$i++) {\ | |||
for (my $i=0;;$i < @ | set_Reading($_sc[$i][0].".Status","off",1);;\ | ||
set_Reading($ | |||
}\ | }\ | ||
\ | \ | ||
Zeile 253: | Zeile 256: | ||
}\ | }\ | ||
\ | \ | ||
DEF TPL_shutter ( ## Definition des Templates namens TPL_shutter | DEF TPL_shutter ( ## Definition des Templates namens TPL_shutter, Parameter: $1:Szenenname, $2:Temperatursensor, $3:Sonnensonsor, $4:Rollläden, $5:runter, $6:hoch, $7:von, $8:bis, $9:Status, $10:aktiv \ | ||
shutter_$1 { \ | |||
if ($10 eq "on" and [$7-$8]) { ## wenn Szene aktiv und innerhalb des Zeitfensters\ | |||
if ([$2:measured-temp] > 24 and [$3] eq "on" and get_Reading("$9") eq "off") { ## Wenn die Zimmertemperatur über 24 und Sonne scheint und Rollläden noch nicht heruntergefahren wurden\ | |||
if ($10 eq "on") { ## wenn Szene aktiv | |||
if ([$2:measured-temp] > 24 and [$3] eq "on" | |||
fhem_set("$4 $5");; ## Rollläden herunterfahren\ | fhem_set("$4 $5");; ## Rollläden herunterfahren\ | ||
set_State("Szene: $1 $5");; ## Status setzen\ | set_State("Szene: $1 $5");; ## Status setzen\ | ||
set_Reading("$1.Status","on",1);; ## Status für Szene im Reading ablegen \ | set_Reading("$1.Status","on",1);; ## Status für Szene im Reading ablegen \ | ||
} | } elsif ([$2:measured-temp] < 23.5 and [$3] eq "off" and get_Reading("$9") eq "on") { ## Wenn die Zimmertemperatur unter 23.5 und Sonne scheint nicht und Rollläden bereits heruntergefahren wurden\ | ||
fhem_set("$4 $6");; ## Rollläden hochfahren\ | fhem_set("$4 $6");; ## Rollläden hochfahren\ | ||
set_State("Szene: $1 $6");; ## Status mit letzer Szene belegen\ | set_State("Szene: $1 $6");; ## Status mit letzer Szene belegen\ | ||
Zeile 272: | Zeile 272: | ||
) ## Ende der Templatedefinition\ | ) ## Ende der Templatedefinition\ | ||
\ | \ | ||
reset {[00:01];; ## nachts alle Status zurücksetzen\ | reset {[00:01];; reset_state();;} ## nachts alle Status zurücksetzen\ | ||
\ | |||
## Generierung der Steuerung pro Beschattung-Szene mit Hilfe des obigen Templates\ | ## Generierung der Steuerung pro Beschattung-Szene mit Hilfe des obigen Templates\ | ||
FOR (@{$ | FOR (@{$_sc},TPL_shutter($_$1,$_$2,$_$3,$_$4,$_$5,$_$6,[$SELF:$_$1.von],[$SELF:$_$1.bis],$_$1.Status,[$SELF:$_$1.aktiv]))\ | ||
attr di_beschattung2 uiTable {\ | attr di_beschattung2 uiTable {\ | ||
package ui_Table;;\ | package ui_Table;;\ | ||
Zeile 286: | Zeile 286: | ||
\ | \ | ||
## Pro Datensatz einer Beschattungs-Szene wird eine Zeile mit Werten und Widgets generiert\ | ## Pro Datensatz einer Beschattungs-Szene wird eine Zeile mit Werten und Widgets generiert\ | ||
FOR (@{$VAR{sc}},"$_$1"|temp_ring([$_$2:measured-temp])|icon([$_$3:state],"fa_cloud","weather_sun\@yellow")|[$SELF:$_$1.von]|[$SELF:$_$1.bis]|icon([$SELF:$_$1.Status],"fts_shutter_10","fts_shutter_80")|WID([$SELF:$_$1.aktiv],"select,on,off")) | FOR (@{$VAR{sc}},"$_$1"|temp_ring([$_$2:measured-temp])|icon([$_$3:state],"fa_cloud","weather_sun\@yellow")|[$SELF:$_$1.von]|[$SELF:$_$1.bis]|icon([$SELF:$_$1.Status],"fts_shutter_10","fts_shutter_80").substr(::ReadingsTimestamp("$SELF","$_$1.Status",0),11,5)|WID([$SELF:$_$1.aktiv],"select,on,off")) | ||
</syntaxhighlight> | |||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:beschattung2.png|600px|ohne]] | |||
== Zeitgesteuerte Heizungsregelung mit Hilfe von Raumthermostaten == | |||
Die folgenden Beispiele funktioniert mit HM-Wandthermostaten. Sie können ebenso für andere Thermostate oder Module wie THRESHOLD entsprechend angepasst werden. | |||
=== Steuerung von Raumthermostaten für mehrere Räume ohne GUI === | |||
'''Beispieldefinition mit einem Template im DOIF-Perlmodus''' | |||
Zeiten, Raumthermostate und Temperaturen werden in der Definition selbst festgelegt und werden dort geändert. Im Status des Moduls werden zur Laufzeit die aktuell gesetzten Temperaturen festgehalten. | |||
<syntaxhighlight lang="perl"> | |||
defmod di_Thermostate DOIF DEF TPL_set_temp ( ## Template zum Setzen der Zimmertemperaturen\ | |||
{$1;; ## Zeitangabe\ | |||
set_State("KU $2, BA $3, DG $4, WZ $5, KO $6, KW $7,Ke $8");;\ | |||
fhem_set"TH_Kueche_HM desired-temp $2";;\ | |||
fhem_set"TH_Bad_HM desired-temp $3";;\ | |||
fhem_set"TH_DG_HM desired-temp $4";;\ | |||
fhem_set"TH_WZ_HM desired-temp $5";;\ | |||
fhem_set"TH_Kz_o_HM desired-temp $6";;\ | |||
fhem_set"TH_Kz_w_HM desired-temp $7";;\ | |||
fhem_set"TH_Keller_HM desired-temp $8";;\ | |||
}\ | |||
)\ | |||
## Zeit Ku,Ba,DG,Wz,Ko,Kw,Ke\ | |||
## $1 $2 $3 $4 $5 $6 $7 $8 | |||
morgens_ein TPL_set_temp ([05:00|8] or [05:30|7],21,21,21,21,21,21,22)\ | |||
morgens_aus TPL_set_temp ([08:00|8] or [09:00|7],20,20,20,21,20,20,21)\ | |||
mittags_ein TPL_set_temp ([12:00], 21,20,21,22,19,21.5,21.5)\ | |||
abends_aus TPL_set_temp ([20:00], 21,20,20,20,20,20,21) | |||
</syntaxhighlight> | |||
=== Steuerung von Raumthermostaten für mehrere Räume mit GUI === | |||
Anforderung: | |||
* Es soll nur eine zentrale Steuerungslogik für das Setzen der Temperaturen für alle Räume mit einer Fußbodenheizung erstellt werden. | |||
* Anzahl der Zeitpunkte zum Setzen der Vorgabetemperaturen soll einfach veränderbar sein. | |||
* Das Hinzufügen bzw. Löschen von Räumen soll durch Hinzufügen oder Löschen jeweils einer Zeile möglich sein. | |||
* Das Ändern der Temperaturen sowie das Ändern der Schaltzeitpunkte soll über WEB-Oberfläche möglich sein. | |||
* Das temporäre Ändern der aktuellen Vorgabetemperatur bis zum nächsten Schaltzeitpunkt soll über WEB-Oberfläche möglich sein. | |||
* Die aktuelle Temperatur des Zimmers und der Zustand der Thermostats (on/off) soll visualisiert werden. | |||
* Schaltzeiten sollen für Wochentage und Wochenende (Ferien) separat einstellbar sein. | |||
* Das Setzen der Wunschtemperatur soll pro Raum abschaltbar sein. | |||
Das folgende Beispiel wurde für eine Fußbodenheizung mit Stellantrieben programmiert. Die Thermostate sind jeweils direkt mit einem Schalter gepeert. Die Schalter schalten ihrerseits per ON/OFF-Befehl die Stellantriebe des Raumes. | |||
'''Beispieldefinition im DOIF-Perlmodus''' | |||
<syntaxhighlight lang="perl"> | |||
defmod di_Therm DOIF subs {\ | |||
## Schaltzeitpunkte, Liste kann angepasst werden \ | |||
@{$_Timer}= qw(morgens vormittags nachmittags abends);;\ | |||
@{$_Timer_default_at} = qw(04:30 08:00 13:00 22:00);;\ | |||
@{$_Timer_default_we} = qw(05:30 09:00 13:00 22:00);;\ | |||
$_temp_default_at=20;; ## Wunschtemperaturvorgabe für Arbeitstage\ | |||
$_temp_default_we=20;; ## Wunschtemperaturvorgabe fürs Wochenende\ | |||
$_temp_default_diff=1;; ## Reduzierung der Wunschtemperatur außerhalb der Heizzeiten um X-Grad\ | |||
\ | |||
\ | |||
## Angaben: Raumbezeichnung, Thermostat, Schalter;; Angaben können zweilenweise erweitert werden\ | |||
push (@{$_sc},[qw(Bad TH_Bad_HM H_Bad)]);;\ | |||
push (@{$_sc},[qw(Dachgeschoss TH_DG_HM H_DG)]);;\ | |||
push (@{$_sc},[qw(Kueche TH_Kueche_HM H_Kueche)]);;\ | |||
push (@{$_sc},[qw(Kinder_ost TH_Kz_o_HM H_Kz_o)]);;\ | |||
push (@{$_sc},[qw(Kinder_west TH_Kz_w_HM H_Kz_w)]);;\ | |||
push (@{$_sc},[qw(Wohnzimmer TH_WZ_HM H_WZ)]);;\ | |||
push (@{$_sc},[qw(Schlafzimmer TH_Keller_HM H_Keller)]);;\ | |||
push (@{$_sc},[qw(Keller TH_AKeller_HM H_AKeller)]);;\ | |||
\ | |||
## Bei Initialisierung oder Änderung der Definition werden Timer-Readings und Temperatur-Readings erstellt und vorbelegt\ | |||
if ($::init_done) {\ | |||
fhem("deletereading $SELF .*");; ## Lösche alle Readings\ | |||
for (my $j=0;;$j<@{$_Timer};;$j++) { ## Für alle Timer\ | |||
set_Reading($_Timer[$j],$_Timer_default_at[$j]);; ## Vorbelegung der Zeit für Arbeitstage\ | |||
set_Reading("$_Timer[$j]_WE",$_Timer_default_we[$j]);; ## Vorbelegung der Zeit für Wochenende\ | |||
for (my $i=0;;$i < @{$_sc};;$i++) { ## Vorbelegung der Wunschtemperaturen für alle Räume\ | |||
set_Reading("$_sc[$i][0]_mode","auto");;\ | |||
set_Reading("$_sc[$i][0]_temp_at_$_Timer[$j]",$j % 2 ? $_temp_default_at-$_temp_default_diff: $_temp_default_at);;\ | |||
set_Reading("$_sc[$i][0]_temp_we_$_Timer[$j]",$j % 2 ? $_temp_default_we-$_temp_default_diff: $_temp_default_we);;\ | |||
}\ | |||
}\ | |||
}\ | |||
\ | |||
sub temp_at_set { ## Routine zum Setzen der Wunschtemperaturen aller Räume für einen Zeitpunkt an Arbeitstagen\ | |||
my ($timer)=@_;;\ | |||
for (my $i=0;;$i< @{$_sc};;$i++) {\ | |||
fhem_set("$_sc[$i][1] desired-temp ".get_Reading ("$_sc[$i][0]_temp_at_$timer")) if (get_Reading("$_sc[$i][0]_mode") eq "auto");;\ | |||
}\ | |||
}\ | |||
sub temp_we_set { ## Routine zum Setzen der Wunschtemperaturen aller Räume für einen Zeitpunkt am Wochenende\ | |||
my ($timer)=@_;;\ | |||
for (my $i=0;;$i< @{$_sc};;$i++) {\ | |||
fhem_set("$_sc[$i][1] desired-temp ".get_Reading ("$_sc[$i][0]_temp_we_$timer")) if (get_Reading("$_sc[$i][0]_mode") eq "auto");;\ | |||
}\ | |||
}\ | |||
} ## subs\ | |||
\ | |||
DEF TPL_set_temp ( ## Definition des Templates namens TPL_set_temp zum Setzen der Thermostat-Vorgabetemperatur\ | |||
Timer_at_$1 {[$2|AT];;temp_at_set("$1")} ## Block zum Setzen der Wunschtemperatur an Arbeitstagen, Parameter: $1:Timername, $2:Time_AT\ | |||
Timer_we_$1 {[$3|WE];;temp_we_set("$1")} ## Block zum Setzen der Wunschtemperatur am Wochenende, Parameter: $1:Timername, $3:Time_WE\ | |||
) ## TPL_set_temp\ | |||
\ | |||
## Generierung der Steuerung pro Raum mit Hilfe des obigen Templates\ | |||
FOR(@{$_Timer},TPL_set_temp($1,[$SELF:$_],[$SELF:$1_WE])) | |||
attr di_Therm room Heizung | |||
attr di_Therm uiTable {\ | |||
package ui_Table;;\ | |||
$TABLE='text-align:right;;';;\ | |||
$TD{0}{2..6} = "align='center'";;\ | |||
$TC{0}="align='left'";;\ | |||
\ | |||
sub onoff_hue {\ | |||
my($redblue)=@_;;\ | |||
return ($redblue == 0 ? 240 : 0);; \ | |||
}\ | |||
}\ | |||
\ | |||
""|""|""|FOR (@{$_Timer},"$1"|)""\ | |||
""|""|"Arbeitstage"|FOR (@{$_Timer},WID([$SELF:$1],"time")|)""\ | |||
""|""|"Wochenende"|FOR (@{$_Timer},WID([$SELF:$1_WE],"time")|)""\ | |||
FOR (@{$_sc},\ | |||
("$1$1"|\ | |||
card([$1$2:measured-temp:col1d],undef,\ | |||
[$1$3:state] eq "off" ? "sani_floor_heating_neutral\@silver" : "sani_floor_heating\@red" ,15,25,\ | |||
undef,undef,"°C",\&temp_hue,"1,,fill:silver","130,1,1,1,1,,200",\ | |||
undef,undef,[$1$3:state:col1d:$_ eq "on" ? 1:0],0,5,0,0,"I-O",\&onoff_hue,"0,,fill:silver")|\ | |||
"Modus:".widget([$SELF:$1$1_mode],"select,auto,off"),,"aktuell:".widget([$1$2:desired-temp],"selectnumbers,18,0.5,22,1,lin","set")|\ | |||
FOR(@{$_Timer},\ | |||
("AT: ".widget([$SELF:$1$1_temp_at_$2],"selectnumbers,18,0.5,22,1,lin"),,"WE: ".widget([$SELF:$1$1_temp_we_$2],"selectnumbers,18,0.5,22,1,lin")|))\ | |||
""\ | |||
)\ | |||
) | |||
</syntaxhighlight> | </syntaxhighlight> | ||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:di_Raumthermostate.png|800px|ohne]] | |||
== Tages-, Monats- und Jahresstatistik für Strom-, Gas-, Wasserzähler und andere Zähler== | |||
Anforderung: | |||
* Zähler sollen durch Angabe des Devicenamens und Readings des Zählers hinzugefügt werden können | |||
* Es soll der aktuelle Stunden-, Tages-, Monats- und Jahreswert berechnet werden | |||
* Es soll der Wert der letzten Stunde, des letzten Tages, Monats und Jahres berechnet werden | |||
* Die Werte sollen geloggt werden | |||
* Die Werte sollen im DOIF visualisiert werden können | |||
'''Beispieldefinition im DOIF-Perlmodus''' | |||
<syntaxhighlight lang="perl"> | |||
defmod di_counter_new DOIF subs {\ | |||
## Device Reading hier die push-Zeilen löschen bzw. durch eigene Readings ersetzen\ | |||
push (@{$_counter},["MQTT2_DVES_C58DCB","total_w"]);; ## Wasserzähler\ | |||
push (@{$_counter},["counter_rw","total_l"]);; ## Leitungswasser\ | |||
push (@{$_counter},["counter_rw","total_z"]);; ## Regenwasser\ | |||
push (@{$_counter},["MQTT2_DVES_C58DCB","total_pv"]);; ## Solarenergie\ | |||
push (@{$_counter},["MQTT2_DVES_C58DCB","total_c"]);; ## Bezugszähler\ | |||
push (@{$_counter},["MQTT2_DVES_C58DCB","total_f"]);; ## Einspeisezähler \ | |||
push (@{$_counter},["MQTT2_DVES_C58DCB","total_gas"]);; ## Gaszähler \ | |||
push (@{$_counter},["vaillant","total_h"]);; ## Gasverbrauch Heizung + Warmwasser\ | |||
push (@{$_counter},["vaillant","total_hc"]);; ## Gasverbrauch Heizung\ | |||
push (@{$_counter},["vaillant","total_hwc"]);; ## Gasverbrauch Warmwasser \ | |||
push (@{$_counter},["di_tibber","costsSum"]);; ## Stromkosten \ | |||
\ | |||
## Die restliche Code-Definition muss nicht angepasst werden\ | |||
## Anpassung der Visualisierung wird im uiTable-Attribut weiter unten vorgenommen\ | |||
\ | |||
sub hour { ## Diese Funktion wird zur vollen Stunde ausgeführt\ | |||
my ($device,$reading,$mday,$yday)=@_;;\ | |||
set_Reading ("$device.$reading.hour_counter",ReadingsVal($device, $reading,0));; \ | |||
set_Reading ("$device.$reading.last_hour",get_Reading("$device.$reading.hour",0),1);;\ | |||
set_Reading ("$device.$reading.hour",0,1);;\ | |||
set_Reading ("$device.$reading.day",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.day_counter",0)))*1000)/1000,1);;\ | |||
\ | |||
}\ | |||
\ | |||
sub midnight { ## Diese Funktion wird um Mitternacht ausgeführt\ | |||
my ($device,$reading,$mday,$yday)=@_;;\ | |||
set_Reading("$device.$reading.day_counter",ReadingsVal($device, $reading,0));; \ | |||
set_Reading("$device.$reading.last_day",get_Reading("$device.$reading.day",0),1);;\ | |||
set_Reading("$device.$reading.day",0,1);;\ | |||
set_Reading ("$device.$reading.month",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.month_counter",0)))*1000)/1000,1);;\ | |||
set_Reading ("$device.$reading.year",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.year_counter",0)))*1000)/1000,1);;\ | |||
\ | |||
if ($mday == 1) {\ | |||
set_Reading("$device.$reading.month_counter",ReadingsVal($device, $reading,0));;\ | |||
set_Reading("$device.$reading.last_month",get_Reading("$device.$reading.month",0),1);;\ | |||
set_Reading("$device.$reading.month",0,1);;\ | |||
if ($yday == 0) {\ | |||
set_Reading("$device.$reading.year_counter",ReadingsVal($device, $reading,0));;\ | |||
set_Reading("$device.$reading.last_year",get_Reading("$device.$reading.year",0),1);;\ | |||
set_Reading("$device.$reading.year",0,1);;\ | |||
}\ | |||
}\ | |||
}\ | |||
\ | |||
sub init_readings {\ | |||
my ($device,$reading)=@_;;\ | |||
if (get_Reading("$device.$reading.day_counter","") eq "") { ## Initialisierung der Readings\ | |||
## aktuellen Zählerstand initialisieren\ | |||
set_Reading("$device.$reading.last_counter",ReadingsVal($device, $reading,0));;\ | |||
set_Reading("$device.$reading.hour_counter",ReadingsVal($device, $reading,0));;\ | |||
set_Reading("$device.$reading.day_counter",ReadingsVal($device, $reading,0));; \ | |||
set_Reading("$device.$reading.month_counter",ReadingsVal($device, $reading,0));;\ | |||
set_Reading("$device.$reading.year_counter",ReadingsVal($device, $reading,0));;\ | |||
\ | |||
set_Reading ("$device.$reading.hour",0);; ## aktueller Stundenverbrauch\ | |||
set_Reading ("$device.$reading.day",0);; ## aktueller Tagesverbrauch\ | |||
set_Reading ("$device.$reading.month",0);; ## aktueller Monatsverbrauch\ | |||
set_Reading ("$device.$reading.year",0);; ## aktueller Jahresverbrauch\ | |||
set_Reading ("$device.$reading.last_hour",0);; ## Verbrauch der letzten Stunde\ | |||
set_Reading ("$device.$reading.last_day",0);; ## Verbrauch des letzten Tages\ | |||
set_Reading ("$device.$reading.last_month",0);; ## Verbrauch des letzten Monats\ | |||
set_Reading ("$device.$reading.last_year",0);; ## Verbrauch des letzten Jahres\ | |||
## Log definieren\ | |||
fhem ("defmod log.counter.$device.$reading FileLog ./log/counter.$device.$reading.log $SELF:$device.$reading.last_.*");;\ | |||
fhem ("attr log.counter.$device.$reading room Filelogs");;\ | |||
}\ | |||
}\ | |||
\ | |||
} ## Ende subs-Block\ | |||
\ | |||
get_data { ## Optionale Übernahme bestehender Daten aus dem Log\ | |||
for (my $i=0;;$i<@{$_counter};;$i++) \ | |||
{ ## my $i=3;;\ | |||
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_hour","bar2day",-10,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_hour"));;\ | |||
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_day","bar2month",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_day"));;\ | |||
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_month","bar2year",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_month"));;\ | |||
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_year","bar2decade",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_year"));;\ | |||
}\ | |||
}\ | |||
\ | |||
hour {[:00];; ## Sicherung der Daten der letzten Stunde\ | |||
for (my $i=0;;$i<@{$_counter};;$i++) { ## Für jeden Zähler wird die Funktion hour aufgerufen\ | |||
hour($_counter[$i][0],$_counter[$i][1],$mday,$yday);;\ | |||
}\ | |||
}\ | |||
\ | |||
midnight {[00:01];; ## Sicherung der Daten um Mitternacht\ | |||
for (my $i=0;;$i<@{$_counter};;$i++) { ## Für jeden Zähler wird die Funktion midnight aufgerufen\ | |||
midnight($_counter[$i][0],$_counter[$i][1],$mday,$yday);;\ | |||
}\ | |||
}\ | |||
\ | |||
init { ## initialisierung aller Readings\ | |||
for (my $i=0;;$i<@{$_counter};;$i++) {## Für jeden Zähler werden Readings über die Funktion init_readings initialisiert\ | |||
init_readings($_counter[$i][0],$_counter[$i][1]);;\ | |||
}\ | |||
}\ | |||
\ | |||
DEF TPL_stat (\ | |||
day_count_$1_$2 { ## bei einem Event des Zählers, wird der tägliche, monatliche und jährliche Verbrauch im jeweiligen Reading festgehalten\ | |||
## $1 Zählerdevice, $2 Zählerreading\ | |||
\ | |||
# my $diff = int(([$1:$2,0]-(get_Reading("$1.$2.last_counter",0)))*1000)/1000;;\ | |||
set_Reading ("$1.$2.last_counter",[$1:$2,0]);;\ | |||
set_Reading ("$1.$2.hour",int(([$1:$2,0]-(get_Reading("$1.$2.hour_counter",0)))*1000)/1000,1);;\ | |||
}\ | |||
)\ | |||
\ | |||
## Pro Zähler wird über eine FOR-Schleife ein day_count_<Device>_<Reading>-Block generiert\ | |||
FOR(@{$_counter},TPL_stat($1$1,$1$2)) ## $1$1 entspricht dem Device, $1$2 entspricht dem Reading | |||
attr di_counter_new room Verbrauch | |||
attr di_counter_new uiTable {package ui_Table;;} ## Optionale Visualisierung der Energie-Verbräuche/-Produktion im DOIF-Device\ | |||
\ | |||
## Template für die Darstellung eines Wertes, einzelne card-Aufrufe können auskommentiert werden\ | |||
DEF TPL_single (\ | |||
##card([$SELF:$2.$3.day:col1w],"$1",undef,$4,$5,$10,$11,"$12",undef,"1","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")| Wochendarstellung\ | |||
card([[$SELF:$2.$3.last_hour:bar2day-10],[$SELF:$2.$3.hour]],"$1 in $12/h",undef,$4/12,$5/12,$10,$11,["letzte","aktuell"],undef,"2","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\ | |||
card([[$SELF:$2.$3.last_day:bar2month-300],[$SELF:$2.$3.day]],"$12/Tag",undef,$4,$5,$10,$11,["letzter","aktuell"],undef,"1","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\ | |||
card([[$SELF:$2.$3.last_month:bar2year-300],[$SELF:$2.$3.month]],"$12/Monat",undef,$6,$7,$10,$11,["letzter","aktuell"],undef,"0","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\ | |||
card([[$SELF:$2.$3.last_year:bar2decade-300],[$SELF:$2.$3.year]],"$12/Jahr",undef,$8,$9,$10,$11,["letzter","aktuell"],undef,"0","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")\ | |||
)\ | |||
\ | |||
## Template für die Darstellung von zwei Werten, einzelne card-Aufrufe können auskommentiert werden\ | |||
DEF TPL_double (\ | |||
##card([[$SELF:$3.$4.day:col1w],[$SELF:$6.$7.day:col1w]],"$1",undef,$8,$9,$14,$15,["$2","$5"],undef,"1","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")| Wochendarstellung\ | |||
card([[$SELF:$3.$4.last_hour:bar2day-10],[$SELF:$6.$7.last_hour:bar2day-10],[$SELF:$3.$4.hour],[$SELF:$6.$7.hour]],"$1/h",undef,$8/12,$9/12,$14,$15,["$2","$5","$2","$5"],undef,"2","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\ | |||
card([[$SELF:$3.$4.last_day:bar2month-300],[$SELF:$6.$7.last_day:bar2month-300],[$SELF:$3.$4.day],[$SELF:$6.$7.day]],"pro Tag",undef,$8,$9,$14,$15,["$2","$5","$2","$5"],undef,"1","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\ | |||
card([[$SELF:$3.$4.last_month:bar2year-300],[$SELF:$6.$7.last_month:bar2year-300],[$SELF:$3.$4.month],[$SELF:$6.$7.month]],"pro Monat",undef,$10,$11,$14,$15,["$2","$5","$2","$5"],undef,"0","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\ | |||
card([[$SELF:$3.$4.last_year:bar2decade-300],[$SELF:$6.$7.last_year:bar2year-300],[$SELF:$3.$4.year],[$SELF:$6.$7.year]],"pro Jahr",undef,$12,$13,$14,$15,["$2","$5","$2","$5"],undef,"0","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")\ | |||
)\ | |||
\ | |||
## Die Visualisierung einer Tabellenzeile wird über die obigen beiden Templates vorgenommen, hier zeilenweise anpassen/löschen:\ | |||
\ | |||
## Über das Template TPL_single wird jeweils pro card ein Wert visualisiert\ | |||
## Überschrift,Device,Reading,minTag,maxTag,minMonat,maxMonat,minJahr,maxJahr,minColor,maxColor,Einheit\ | |||
TPL_single (Frischwasser,MQTT2_DVES_C58DCB,total_w,0,500,0,10000,0,80000,90,0,Liter)\ | |||
TPL_single (Gas,MQTT2_DVES_C58DCB,total_gas,0,10,0,250,0,2000,90,0,m³)\ | |||
TPL_single (Einspeisung,MQTT2_DVES_C58DCB,total_f,0,30,0,600,0,5000,0,90,kWh)\ | |||
TPL_single (Bezug,MQTT2_DVES_C58DCB,total_c,-10,0,-300,0,-3000,0,0,90,kWh)\ | |||
TPL_single (Stromkosten,di_tibber,costsSum,0,4,0,90,0,1200,90,0,€)\ | |||
\ | |||
## Über das Template TPL_double werden jeweils pro card zwei Werte visualisiert\ | |||
## Überschrift,Bezeichnung1,Device1,Reading1,Bezeichnung2,Device2,Reading2,minTag,maxTag,minMonat,maxMonat,minJahr,maxJahr,minColor,maxColor,Einheit\ | |||
##TPL_double (Heizenergie,Gesamt,vaillant,total_h,Wasser,vaillant,total_hwc,0,100,0,2000,0,20000,90,0,kWh)\ | |||
\ | |||
##TPL_double (Stromeinspeisung/Strombezug,Bezug,MQTT2_DVES_C58DCB,total_c,Einsp.,MQTT2_DVES_C58DCB,total_f,-10,25,-300,600,-3000,5000,0,90,kWh) | |||
</syntaxhighlight> | |||
Bemerkungen: | |||
* Die Visualisierung der Verläufe über das Attribut uiTable ist optional. | |||
* Die Verlaufswerte der grafischen Darstellung mit Hilfe der card-Funktion werden im DOIF-Device gespeichert. Bereits geloggte Daten können mit '''set di_counter_new get_data''' importiert werden, [https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#Import.2C_.C3.84nderung_und_L.C3.B6schung_von_Diagrammdaten siehe dazu auch Datenimport] | |||
* Die obige Definition funktioniert nur mit Zählern, die mit aufsteigenden Werten (positiv/negativ) arbeiten, wie z. B. Stromverbrauch in kWh, Wasserverbrauch in Litern usw.. Es funktioniert nicht mit momentanen Werten, wie z. B. aktuelle Leistungsaufnahme eines Verbrauchers in Watt, diese müssten zunächst kumuliert werden. | |||
''Ergebnis der Beispieldefinition in der Webansicht:'' | |||
[[Datei:di_counter.png|1000px|ohne]] | |||
== Weiterführende Links == | |||
* Dokumentation [[DOIF/Perl-Modus]] | |||
* DOIF-WEB-Interface [[DOIF/uiTable Schnelleinstieg]] | |||
[[Category:Examples]] | |||
[[Kategorie:HOWTOS]] | |||
[[Kategorie:Code Snippets]] |
Aktuelle Version vom 8. Juni 2023, 08:43 Uhr
An dieser Stelle werden Lösungen für praxisrelevante Automatisierungsaufgaben mit Hilfe des DOIF-Moduls vorgestellt. Insbesondere werden mit Hilfe von Templates generische DOIF-Lösungen an konkreten Beispielen dargestellt, die für mehrere Szenarien nutzbar sind.
Die folgenden Beispieldefinitionen arbeiten mit konkreten Geräten und Readings, sie können als RAW-Definition ins eigene System übernommen werden, dazu müssen die Gerätenamen, Readings, ggf. auch Icons den existierenden Namen des eigenen Systems angepasst werden. Zum Ausprobieren der Beispiele können statt echter Geräte auch Dummys benutzt werden.
Licht
Einfache Zeitsteuerung für ein Szenario
Anforderung: Lichter sollen in einem bestimmten Zeitraum leuchten.
Beispieldefinition
defmod di_licht DOIF ([21:00-23:00])\
(set Lampeflur on, set Lampekueche on)\
DOELSE\
(set Lampeflur off, set Lampekueche off)
Helligkeitsabhängige Zeitsteuerung für ein Szenario
Anforderung: Lichter sollen innerhalb eines Zeitraums leuchten, aber nur wenn es dunkel ist.
Beispieldefinition für Dunkelheit
Zunächst wird ein DOIF-Modul definiert, welches mit Hilfe eines Helligkeitssensors den Zustand "on" bei Dunkelheit annimmt, sonst "off"
defmod Dunkelheit DOIF ([Helligkeitssensor:brightness] < 100) DOELSE
attr Dunkelheit cmdState on|off
Beispieldefinition
defmod di_licht DOIF ([16:00-23:00] and [Dunkelheit] eq "on")\
(set Lampeflur on, set Lampekueche on)\
DOELSE\
(set Lampeflur off, set Lampekueche off)
Helligkeitsabhängige Zeitsteuerung für mehrere Szenarien
Anforderung:
- Es soll nur eine Steuerung für alle Lichtszenarien programmiert werden.
- Verschiedene Lichtszenarien sollen über Angabe bestimmter Parameter generiert werden.
- Eine Lichtszene soll durch folgende Angaben definierbar sein: Szenenname, Daemmerungssensor (on/off), Zeitspanne, Einschaltbefehl, Ausschaltbefehl, Zeitraum des Jahres.
- Eine neue Szene soll durch Hinzufügen eines Template-Aufrufs erstellt werden können.
Beispieldefinition
defmod di_Licht_tpl DOIF DEF TPL_light ( ## Definition des Templates namens TPL_light zur Steuerung einer Lichtszene\
light_$1 { ## DOIF Block\
## Parameter: Szene Daemmerungssensor Zeitspanne on off von bis\
## Nr.: $1 $2 $3 $4 $5 $6 $7\
if ($md ge "$6" or $md le "$7") { ## wenn innerhalb der Jahreszeit (von bis)\
if (($3) and [$2] eq "on") { ## wenn in der Zeitspanne und Dämmerung on\
fhem_set($4);; ## schalte on-Befehle\
set_State("Szene: $1");; ## Setze Status des DOIF-Moduls\
} else {\
fhem_set ($5);; ## sonst, schalte off-Befehle\
}\
}\
} ## Ende des light-Blocks\
) ## Ende der Templatedefinition\
\
## Generierung der Steuerung pro Beschattungsszene mit Hilfe des obigen Templates\
TPL_light (Erdgeschoss,Daemmerung2,([06:25-08:00|8] or [15:00-23:00]),"Lampekueche,LampeFlur on","Lampekueche,LampeFlur off",01-01, 12-31)\
TPL_light (Kind2,Daemmerung2,[06:25-08:00|8] or [15:00-23:10],"schrank2 on","schrank2 off",12-01,03-31)\
TPL_light (Terrasse,Dunkelheit,[17:00-23:05],"Terrasse on","Terrasse off",01-01,12-31)\
TPL_light (Garten,Dunkelheit,[16:00-23:30],"Garten pct 50","Garten off",01-01,12-31)\
## ... hier können weitere Szenarien durch hinzufügen weiterer Zeilen generiert werden
Helligkeitsabhängige Zeitsteuerung für mehrere Szenarien mit tabellarischer Übersicht
Anforderung:
- Es soll nur eine Steuerung für mehrere Lichtszenarien programmiert werden.
- Ein Lichtszenario soll durch folgende Angaben definierbar sein: Szenario-Name, Daemmerungssensor (on/off), Zeitspanne, Einschaltbefehl, Ausschaltbefehl
- Ein neues Szenario soll durch hinzufügen einer Parameterzeile erstellt werden können.
- Erstellte Lichtszenarien sollen tabellarisch dargestellt werden und über Weboberfläche einzeln schaltbar sein: auto/on/off
Beispieldefinition
defmod di_Licht_all DOIF subs {\
## Ein Szenario wird durch Hinzufügen einer Definitionszeile erstellt\
## Szene Dämmerungssensor Zeitspanne Einschaltbefehl Ausschaltbefehl\
push (@{$_sc},["Erdgeschoss","Daemmerung2", "[06:25-08:00|8] or [15:00-23:30]", "Lampekueche,Lampeflur on", "Lampekueche,Lampeflur off"]);;\
push (@{$_sc},["Kinderz_2", "Daemmerung2", "[06:25-08:00|8] or [15:00-23:10]", "schrank2 on", "schrank2 off"]);;\
push (@{$_sc},["Terrasse", "Dunkelheit", "[16:00-23:30]", "Terrasse on", "Terrasse off"]);;\
push (@{$_sc},["Garten", "Dunkelheit", "[16:00-23:30]", "Garten pct 50", "Garten off"]);;\
push (@{$_sc},["Strauch1", "Dunkelheit", "[17:00-23:05]", "Strauch1 on", "Strauch1 off"]);;\
push (@{$_sc},["Strauch2", "Dunkelheit", "[17:00-23:05]", "Strauch2 on", "Strauch2 off"]);;\
push (@{$_sc},["Eingang", "Dunkelheit", "[17:00-23:35]", "Aussenbeleuchtung on", "Aussenbeleuchtung off"]);;\
\
\
## Bei Änderung der Definition werden erfoderliche Readings erstellt und vorbelegt\
if ($::init_done) {\
fhem("deletereading $SELF .*");;\
set_State("initialized");;\
for (my $i=0;;$i < @{$_sc};;$i++) {\
set_Reading ($_sc[$i][0].".Status","off");;\
set_Reading ($_sc[$i][0].".aktiv","off");;\
}\
}\
} ## end of subs\
\
DEF TPL_light ( ## Definition des Templates namens TPL_light\
light_$1 { ## Parameter: Szene Daemmerung Zeitspanne on off \
## $1 $2 $3 $4 $5\
if ([$SELF:$1.aktiv] eq "auto") {\
if (($3) and [$2] eq "on") {\
fhem_set($4);;\
set_Reading("$1.Status","on",1);;\
} else {\
fhem_set ($5);;\
set_Reading("$1.Status","off",1);;\
}\
}\
} ## Ende des light-Blocks\
\
active_$1 {\
if ([$SELF:$1.aktiv] eq "on") {\
fhem_set ($4);;\
set_Reading("$1.Status","on",1);;\
}\
if ([$SELF:$1.aktiv] eq "off") {\
fhem_set ($5);;\
set_Reading("$1.Status","off",1);;\
}\
} ## Ende des active-Blocks \
) ## Ende der Templatedefinition\
\
## Generierung der Steuerung pro Licht-Szene mit Hilfe des obigen Templates\
FOR (@{$_sc},TPL_light($_$1,$_$2,$_$3,"$_$4","$_$5"))
attr di_Licht_all room Licht
attr di_Licht_all uiTable {\
package ui_Table;;\
$TC{1..5}="style='padding-left: 2px;; padding-right: 2px;;' align='center'";;\
\
}\
\
## Überschrift der Parameter\
"Szene"|"Dämmerung"|"Zeitspanne"|"Status"|"ausgeführt"|"aktiv"\
\
## Pro Datensatz einer Licht-Szene wird eine Zeile mit Werten und Widgets generiert\
FOR (@{$VAR{sc}},"$_$1"|icon([$_$2])|"$_$3"|icon([$SELF:$_$1.Status])|::ReadingsTimestamp("$SELF","$_$1.Status",0)|WID([$SELF:$_$1.aktiv],"select,auto,on,off"))
Ergebnis der Beispieldefinition in der Webansicht:
Beschattung
Beschattungssteuerung abhängig von der Zimmertemperatur und Sonneneinstrahlung für mehrere Szenarien
Anforderung:
- Es soll nur eine zentrale Steuerungslogik für alle Beschattungsszenarien erstellt werden.
- Ein Beschattungsszenario soll durch folgende Angaben definierbar sein: Name der Szene, Temperatursensor des Zimmers, Sonnensensor, von Uhrzeit, bis Uhrzeit, Rollläden, Befehl zum Herunterfahren, Befehl zum Hochfahren.
- Ein neues Beschattungsszenario soll nur durch das Hinzufügen eines Template-Aufrufs erstellt werden können.
Zunächst wird ein DOIF-Modul definiert, welches verzögert mit Hilfe einer PV-Anlage den Zustand "on" bei Sonneneinstrahlung annimmt, sonst "off".
Beispieldefinition für Sonneneinstrahlung
defmod Sonne_s DOIF ([zaehler:PV-Leistung] > 2.5)
attr Sonne_s cmdState on|off
attr Sonne_s wait 1800:7200
Beispieldefinition des Steuermoduls
defmod di_beschattung1 DOIF DEF TPL_shutter ( ## Definition des Templates namens TPL_shutter\
## Parameternummer $1 $2 $3 $4 $5 $6 $7 $8 \
## Bedeutung Name der Szene Temperatursensor des Zimmers Sonnensensor von Uhrzeit bis Uhrzeit Rollladen Befehl zum Herunterfahren Befehl zum Hochfahren\
shutter_$1 { ## DOIF Block\
if ([$4-$5]) { ## innerhalb des Zeitfensters \
if ([$2:measured-temp] > 24 and [$3] eq "on" and !$VAR{$1}) { ## Wenn die Zimmertemperatur über 24 und Sonne scheint und die Rollläden noch nicht heruntergefahren wurden\
fhem_set("$6 $7");; ## Fenster herunterfahren\
set_State("Szene: $1 Beschattung");; ## Status mit letztem Befehl belegen \
$VAR{$1}=1;; ## Merker setzen, dass Fenster bereits heruntergefahren wurde\
} elsif ([$2:measured-temp] < 23.5 and [$3] eq "off" and $VAR{$1}) { ## Wenn die Zimmertemperatur unter 23.5 und Sonne scheint nicht und die Rollläden bereits heruntergefahren wurden\
fhem_set("$6 $8");; ## Fenster hochfahren\
set_State("Szene: $1 keine Beschattung");; ## Status mit letztem Befehl belegen \
$VAR{$1}=0;; ## Merker zurücksetzen\
}\
} \
}\
) ## Ende der Templatedefinition\
\
reset {[00:01];;delete $VAR;;} ## DOIF-Block namens reset um nachts alle Merker zu löschen\
\
## Definition einzelner DOIF-Blöcke pro Fenstergruppe mit Hilfe des Templates\
## $1 $2 $3 $4 $5 $6 $7 $8\
TPL_shutter (Dachgeschoss,TH_DG_HM,Sonne_s,12:00,21:00,R_DG,30,on)\
TPL_shutter (Kueche,TH_Kueche_HM,Sonne_s,09:00,14:00,R_Kueche,50,on)\
TPL_shutter (Kinderzimmer1_ost,TH_Kz_o_HM,Sonne_s,09:00,14:00,R_Kinderzimmer1_O,30,on)\
TPL_shutter (Kinderzimmer1_sued,TH_Kz_o_HM,Sonne_s,12:00,21:00,R_Kinderzimmer1_S,25,on)\
TPL_shutter (Kinderzimmer2_sued,TH_Kz_w_HM,Sonne_s,12:00,21:00,R_Kinderzimmer2_S,25,on)\
TPL_shutter (Kinderzimmer2_west,TH_Kz_w_HM,Sonne_w,15:30,22:00,R_Kinderzimmer2_W.*,25,on)\
TPL_shutter (Wohnzimmmer_sued,TH_WZ_HM,Sonne_s,12:30,21:00,R_W_S,25,on)\
TPL_shutter (Wohnzimmer_west,TH_WZ_HM,Sonne_w,15:30,22:00,R_W_W[23],25,on)\
## hier können weitere Szenarien für weitere Fenster hinzugefügt werden
Beschattungssteuerung abhängig von der Zimmertemperatur und Sonneneinstrahlung für mehrere Szenarien mit Visualisierung
Anforderung:
- Es soll nur eine zentrale Steuerungslogik für alle Beschattungsszenarien erstellt werden.
- Ein Beschattungsszenario soll durch folgende Angaben definierbar sein: Name der Szene, Temperatursensor des Zimmers, Sonnensensor(on/off), von Uhrzeit, bis Uhrzeit, Rollläden, Befehl zum Herunterfahren, Befehl zum Hochfahren, Status, Modus(aktiv/deaktiv)
- Ein neues Beschattungsszenario soll nur durch das Hinzufügen einer Parameter-Zeile erstellt werden können.
- Erstellte Beschattungsszenarien sollen automatisch tabellarisch dargestellt werden und einzeln abschaltbar sein.
Beispieldefinition des Steuermoduls
defmod di_beschattung2 DOIF subs {\
@{$_params}= qw( Szene Temperatursensor Sonnensensor Rollladen runter hoch von bis Status aktiv);;\
\
## Definition einzelner Datensätze pro Szene, Szenen können zeilenweise gelöscht bzw. hinzugefügt werden\
push (@{$_sc},[qw(Bad TH_Bad_HM Sonne_s R_Bad 30 on 13:00 22:00 off on)]);;\
push (@{$_sc},[qw(Dachgeschoss TH_DG_HM Sonne_s R_Dachboden 30 on 13:00 22:00 off on)]);;\
push (@{$_sc},[qw(Kueche TH_Kueche_HM Sonne_s R_Kueche 50 on 09:00 14:00 off on)]);;\
push (@{$_sc},[qw(Kinderzimmer_1_ost TH_Kz_o_HM Sonne_s R_Kinderzimmer1_O 30 on 09:00 14:00 off on)]);;\
push (@{$_sc},[qw(Kinderzimmer_1_sued TH_Kz_o_HM Sonne_s R_Kinderzimmer1_S 25 on 13:00 22:00 off on)]);;\
push (@{$_sc},[qw(Kinderzimmer_2_sued TH_Kz_w_HM Sonne_s R_Kinderzimmer2_S 25 on 13:00 22:00 off on)]);;\
push (@{$_sc},[qw(Kinderzimmer_2_west TH_Kz_w_HM Sonne_w R_Kinderzimmer2_W.* 25 on 15:30 22:00 off on)]);;\
push (@{$_sc},[qw(Wohnzimmer_west TH_WZ_HM Sonne_w R_W_W[23] 25 on 15:30 22:00 off on)]);;\
\
if ($::init_done) { ## Bei Änderung der Definition werden alle erfoderlichen Readings erstellt und vorbelegt\
fhem("deletereading $SELF .*");; ## alle Readings des Moduls löschen\
set_State("initialized");; ## Status setzen\
for (my $i=0;;$i < @{$_sc};;$i++) {\
for (my $j=6;;$j < @{$_sc[$i]};;$j++) { ## für Parameter 7 bis 10 Readings anlegen\
set_Reading ($_sc[$i][0].".".$_params[$j],$_sc[$i][$j]);;\
}\
}\
}\
\
sub reset_state {\
for (my $i=0;;$i < @{$_sc};;$i++) {\
set_Reading($_sc[$i][0].".Status","off",1);;\
}\
\
}\
}\
\
DEF TPL_shutter ( ## Definition des Templates namens TPL_shutter, Parameter: $1:Szenenname, $2:Temperatursensor, $3:Sonnensonsor, $4:Rollläden, $5:runter, $6:hoch, $7:von, $8:bis, $9:Status, $10:aktiv \
shutter_$1 { \
if ($10 eq "on" and [$7-$8]) { ## wenn Szene aktiv und innerhalb des Zeitfensters\
if ([$2:measured-temp] > 24 and [$3] eq "on" and get_Reading("$9") eq "off") { ## Wenn die Zimmertemperatur über 24 und Sonne scheint und Rollläden noch nicht heruntergefahren wurden\
fhem_set("$4 $5");; ## Rollläden herunterfahren\
set_State("Szene: $1 $5");; ## Status setzen\
set_Reading("$1.Status","on",1);; ## Status für Szene im Reading ablegen \
} elsif ([$2:measured-temp] < 23.5 and [$3] eq "off" and get_Reading("$9") eq "on") { ## Wenn die Zimmertemperatur unter 23.5 und Sonne scheint nicht und Rollläden bereits heruntergefahren wurden\
fhem_set("$4 $6");; ## Rollläden hochfahren\
set_State("Szene: $1 $6");; ## Status mit letzer Szene belegen\
set_Reading("$1.Status","off",1);; ## Status für Szene im Reading ablegen\
}\
}\
}\
) ## Ende der Templatedefinition\
\
reset {[00:01];; reset_state();;} ## nachts alle Status zurücksetzen\
\
## Generierung der Steuerung pro Beschattung-Szene mit Hilfe des obigen Templates\
FOR (@{$_sc},TPL_shutter($_$1,$_$2,$_$3,$_$4,$_$5,$_$6,[$SELF:$_$1.von],[$SELF:$_$1.bis],$_$1.Status,[$SELF:$_$1.aktiv]))\
attr di_beschattung2 uiTable {\
package ui_Table;;\
$TC{1..10}="style='padding-left: 10px;; padding-right: 10px;; padding-top: 3px;; padding-bottom: 3px;;' align='center'";;\
}\
\
## Überschrift der Parameter\
"Szene"|"Temperatur"|"Einstrahlung"|"von"|"bis"|"Status"|"aktiv"\
\
## Pro Datensatz einer Beschattungs-Szene wird eine Zeile mit Werten und Widgets generiert\
FOR (@{$VAR{sc}},"$_$1"|temp_ring([$_$2:measured-temp])|icon([$_$3:state],"fa_cloud","weather_sun\@yellow")|[$SELF:$_$1.von]|[$SELF:$_$1.bis]|icon([$SELF:$_$1.Status],"fts_shutter_10","fts_shutter_80").substr(::ReadingsTimestamp("$SELF","$_$1.Status",0),11,5)|WID([$SELF:$_$1.aktiv],"select,on,off"))
Ergebnis der Beispieldefinition in der Webansicht:
Zeitgesteuerte Heizungsregelung mit Hilfe von Raumthermostaten
Die folgenden Beispiele funktioniert mit HM-Wandthermostaten. Sie können ebenso für andere Thermostate oder Module wie THRESHOLD entsprechend angepasst werden.
Steuerung von Raumthermostaten für mehrere Räume ohne GUI
Beispieldefinition mit einem Template im DOIF-Perlmodus
Zeiten, Raumthermostate und Temperaturen werden in der Definition selbst festgelegt und werden dort geändert. Im Status des Moduls werden zur Laufzeit die aktuell gesetzten Temperaturen festgehalten.
defmod di_Thermostate DOIF DEF TPL_set_temp ( ## Template zum Setzen der Zimmertemperaturen\
{$1;; ## Zeitangabe\
set_State("KU $2, BA $3, DG $4, WZ $5, KO $6, KW $7,Ke $8");;\
fhem_set"TH_Kueche_HM desired-temp $2";;\
fhem_set"TH_Bad_HM desired-temp $3";;\
fhem_set"TH_DG_HM desired-temp $4";;\
fhem_set"TH_WZ_HM desired-temp $5";;\
fhem_set"TH_Kz_o_HM desired-temp $6";;\
fhem_set"TH_Kz_w_HM desired-temp $7";;\
fhem_set"TH_Keller_HM desired-temp $8";;\
}\
)\
## Zeit Ku,Ba,DG,Wz,Ko,Kw,Ke\
## $1 $2 $3 $4 $5 $6 $7 $8
morgens_ein TPL_set_temp ([05:00|8] or [05:30|7],21,21,21,21,21,21,22)\
morgens_aus TPL_set_temp ([08:00|8] or [09:00|7],20,20,20,21,20,20,21)\
mittags_ein TPL_set_temp ([12:00], 21,20,21,22,19,21.5,21.5)\
abends_aus TPL_set_temp ([20:00], 21,20,20,20,20,20,21)
Steuerung von Raumthermostaten für mehrere Räume mit GUI
Anforderung:
- Es soll nur eine zentrale Steuerungslogik für das Setzen der Temperaturen für alle Räume mit einer Fußbodenheizung erstellt werden.
- Anzahl der Zeitpunkte zum Setzen der Vorgabetemperaturen soll einfach veränderbar sein.
- Das Hinzufügen bzw. Löschen von Räumen soll durch Hinzufügen oder Löschen jeweils einer Zeile möglich sein.
- Das Ändern der Temperaturen sowie das Ändern der Schaltzeitpunkte soll über WEB-Oberfläche möglich sein.
- Das temporäre Ändern der aktuellen Vorgabetemperatur bis zum nächsten Schaltzeitpunkt soll über WEB-Oberfläche möglich sein.
- Die aktuelle Temperatur des Zimmers und der Zustand der Thermostats (on/off) soll visualisiert werden.
- Schaltzeiten sollen für Wochentage und Wochenende (Ferien) separat einstellbar sein.
- Das Setzen der Wunschtemperatur soll pro Raum abschaltbar sein.
Das folgende Beispiel wurde für eine Fußbodenheizung mit Stellantrieben programmiert. Die Thermostate sind jeweils direkt mit einem Schalter gepeert. Die Schalter schalten ihrerseits per ON/OFF-Befehl die Stellantriebe des Raumes.
Beispieldefinition im DOIF-Perlmodus
defmod di_Therm DOIF subs {\
## Schaltzeitpunkte, Liste kann angepasst werden \
@{$_Timer}= qw(morgens vormittags nachmittags abends);;\
@{$_Timer_default_at} = qw(04:30 08:00 13:00 22:00);;\
@{$_Timer_default_we} = qw(05:30 09:00 13:00 22:00);;\
$_temp_default_at=20;; ## Wunschtemperaturvorgabe für Arbeitstage\
$_temp_default_we=20;; ## Wunschtemperaturvorgabe fürs Wochenende\
$_temp_default_diff=1;; ## Reduzierung der Wunschtemperatur außerhalb der Heizzeiten um X-Grad\
\
\
## Angaben: Raumbezeichnung, Thermostat, Schalter;; Angaben können zweilenweise erweitert werden\
push (@{$_sc},[qw(Bad TH_Bad_HM H_Bad)]);;\
push (@{$_sc},[qw(Dachgeschoss TH_DG_HM H_DG)]);;\
push (@{$_sc},[qw(Kueche TH_Kueche_HM H_Kueche)]);;\
push (@{$_sc},[qw(Kinder_ost TH_Kz_o_HM H_Kz_o)]);;\
push (@{$_sc},[qw(Kinder_west TH_Kz_w_HM H_Kz_w)]);;\
push (@{$_sc},[qw(Wohnzimmer TH_WZ_HM H_WZ)]);;\
push (@{$_sc},[qw(Schlafzimmer TH_Keller_HM H_Keller)]);;\
push (@{$_sc},[qw(Keller TH_AKeller_HM H_AKeller)]);;\
\
## Bei Initialisierung oder Änderung der Definition werden Timer-Readings und Temperatur-Readings erstellt und vorbelegt\
if ($::init_done) {\
fhem("deletereading $SELF .*");; ## Lösche alle Readings\
for (my $j=0;;$j<@{$_Timer};;$j++) { ## Für alle Timer\
set_Reading($_Timer[$j],$_Timer_default_at[$j]);; ## Vorbelegung der Zeit für Arbeitstage\
set_Reading("$_Timer[$j]_WE",$_Timer_default_we[$j]);; ## Vorbelegung der Zeit für Wochenende\
for (my $i=0;;$i < @{$_sc};;$i++) { ## Vorbelegung der Wunschtemperaturen für alle Räume\
set_Reading("$_sc[$i][0]_mode","auto");;\
set_Reading("$_sc[$i][0]_temp_at_$_Timer[$j]",$j % 2 ? $_temp_default_at-$_temp_default_diff: $_temp_default_at);;\
set_Reading("$_sc[$i][0]_temp_we_$_Timer[$j]",$j % 2 ? $_temp_default_we-$_temp_default_diff: $_temp_default_we);;\
}\
}\
}\
\
sub temp_at_set { ## Routine zum Setzen der Wunschtemperaturen aller Räume für einen Zeitpunkt an Arbeitstagen\
my ($timer)=@_;;\
for (my $i=0;;$i< @{$_sc};;$i++) {\
fhem_set("$_sc[$i][1] desired-temp ".get_Reading ("$_sc[$i][0]_temp_at_$timer")) if (get_Reading("$_sc[$i][0]_mode") eq "auto");;\
}\
}\
sub temp_we_set { ## Routine zum Setzen der Wunschtemperaturen aller Räume für einen Zeitpunkt am Wochenende\
my ($timer)=@_;;\
for (my $i=0;;$i< @{$_sc};;$i++) {\
fhem_set("$_sc[$i][1] desired-temp ".get_Reading ("$_sc[$i][0]_temp_we_$timer")) if (get_Reading("$_sc[$i][0]_mode") eq "auto");;\
}\
}\
} ## subs\
\
DEF TPL_set_temp ( ## Definition des Templates namens TPL_set_temp zum Setzen der Thermostat-Vorgabetemperatur\
Timer_at_$1 {[$2|AT];;temp_at_set("$1")} ## Block zum Setzen der Wunschtemperatur an Arbeitstagen, Parameter: $1:Timername, $2:Time_AT\
Timer_we_$1 {[$3|WE];;temp_we_set("$1")} ## Block zum Setzen der Wunschtemperatur am Wochenende, Parameter: $1:Timername, $3:Time_WE\
) ## TPL_set_temp\
\
## Generierung der Steuerung pro Raum mit Hilfe des obigen Templates\
FOR(@{$_Timer},TPL_set_temp($1,[$SELF:$_],[$SELF:$1_WE]))
attr di_Therm room Heizung
attr di_Therm uiTable {\
package ui_Table;;\
$TABLE='text-align:right;;';;\
$TD{0}{2..6} = "align='center'";;\
$TC{0}="align='left'";;\
\
sub onoff_hue {\
my($redblue)=@_;;\
return ($redblue == 0 ? 240 : 0);; \
}\
}\
\
""|""|""|FOR (@{$_Timer},"$1"|)""\
""|""|"Arbeitstage"|FOR (@{$_Timer},WID([$SELF:$1],"time")|)""\
""|""|"Wochenende"|FOR (@{$_Timer},WID([$SELF:$1_WE],"time")|)""\
FOR (@{$_sc},\
("$1$1"|\
card([$1$2:measured-temp:col1d],undef,\
[$1$3:state] eq "off" ? "sani_floor_heating_neutral\@silver" : "sani_floor_heating\@red" ,15,25,\
undef,undef,"°C",\&temp_hue,"1,,fill:silver","130,1,1,1,1,,200",\
undef,undef,[$1$3:state:col1d:$_ eq "on" ? 1:0],0,5,0,0,"I-O",\&onoff_hue,"0,,fill:silver")|\
"Modus:".widget([$SELF:$1$1_mode],"select,auto,off"),,"aktuell:".widget([$1$2:desired-temp],"selectnumbers,18,0.5,22,1,lin","set")|\
FOR(@{$_Timer},\
("AT: ".widget([$SELF:$1$1_temp_at_$2],"selectnumbers,18,0.5,22,1,lin"),,"WE: ".widget([$SELF:$1$1_temp_we_$2],"selectnumbers,18,0.5,22,1,lin")|))\
""\
)\
)
Ergebnis der Beispieldefinition in der Webansicht:
Tages-, Monats- und Jahresstatistik für Strom-, Gas-, Wasserzähler und andere Zähler
Anforderung:
- Zähler sollen durch Angabe des Devicenamens und Readings des Zählers hinzugefügt werden können
- Es soll der aktuelle Stunden-, Tages-, Monats- und Jahreswert berechnet werden
- Es soll der Wert der letzten Stunde, des letzten Tages, Monats und Jahres berechnet werden
- Die Werte sollen geloggt werden
- Die Werte sollen im DOIF visualisiert werden können
Beispieldefinition im DOIF-Perlmodus
defmod di_counter_new DOIF subs {\
## Device Reading hier die push-Zeilen löschen bzw. durch eigene Readings ersetzen\
push (@{$_counter},["MQTT2_DVES_C58DCB","total_w"]);; ## Wasserzähler\
push (@{$_counter},["counter_rw","total_l"]);; ## Leitungswasser\
push (@{$_counter},["counter_rw","total_z"]);; ## Regenwasser\
push (@{$_counter},["MQTT2_DVES_C58DCB","total_pv"]);; ## Solarenergie\
push (@{$_counter},["MQTT2_DVES_C58DCB","total_c"]);; ## Bezugszähler\
push (@{$_counter},["MQTT2_DVES_C58DCB","total_f"]);; ## Einspeisezähler \
push (@{$_counter},["MQTT2_DVES_C58DCB","total_gas"]);; ## Gaszähler \
push (@{$_counter},["vaillant","total_h"]);; ## Gasverbrauch Heizung + Warmwasser\
push (@{$_counter},["vaillant","total_hc"]);; ## Gasverbrauch Heizung\
push (@{$_counter},["vaillant","total_hwc"]);; ## Gasverbrauch Warmwasser \
push (@{$_counter},["di_tibber","costsSum"]);; ## Stromkosten \
\
## Die restliche Code-Definition muss nicht angepasst werden\
## Anpassung der Visualisierung wird im uiTable-Attribut weiter unten vorgenommen\
\
sub hour { ## Diese Funktion wird zur vollen Stunde ausgeführt\
my ($device,$reading,$mday,$yday)=@_;;\
set_Reading ("$device.$reading.hour_counter",ReadingsVal($device, $reading,0));; \
set_Reading ("$device.$reading.last_hour",get_Reading("$device.$reading.hour",0),1);;\
set_Reading ("$device.$reading.hour",0,1);;\
set_Reading ("$device.$reading.day",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.day_counter",0)))*1000)/1000,1);;\
\
}\
\
sub midnight { ## Diese Funktion wird um Mitternacht ausgeführt\
my ($device,$reading,$mday,$yday)=@_;;\
set_Reading("$device.$reading.day_counter",ReadingsVal($device, $reading,0));; \
set_Reading("$device.$reading.last_day",get_Reading("$device.$reading.day",0),1);;\
set_Reading("$device.$reading.day",0,1);;\
set_Reading ("$device.$reading.month",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.month_counter",0)))*1000)/1000,1);;\
set_Reading ("$device.$reading.year",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.year_counter",0)))*1000)/1000,1);;\
\
if ($mday == 1) {\
set_Reading("$device.$reading.month_counter",ReadingsVal($device, $reading,0));;\
set_Reading("$device.$reading.last_month",get_Reading("$device.$reading.month",0),1);;\
set_Reading("$device.$reading.month",0,1);;\
if ($yday == 0) {\
set_Reading("$device.$reading.year_counter",ReadingsVal($device, $reading,0));;\
set_Reading("$device.$reading.last_year",get_Reading("$device.$reading.year",0),1);;\
set_Reading("$device.$reading.year",0,1);;\
}\
}\
}\
\
sub init_readings {\
my ($device,$reading)=@_;;\
if (get_Reading("$device.$reading.day_counter","") eq "") { ## Initialisierung der Readings\
## aktuellen Zählerstand initialisieren\
set_Reading("$device.$reading.last_counter",ReadingsVal($device, $reading,0));;\
set_Reading("$device.$reading.hour_counter",ReadingsVal($device, $reading,0));;\
set_Reading("$device.$reading.day_counter",ReadingsVal($device, $reading,0));; \
set_Reading("$device.$reading.month_counter",ReadingsVal($device, $reading,0));;\
set_Reading("$device.$reading.year_counter",ReadingsVal($device, $reading,0));;\
\
set_Reading ("$device.$reading.hour",0);; ## aktueller Stundenverbrauch\
set_Reading ("$device.$reading.day",0);; ## aktueller Tagesverbrauch\
set_Reading ("$device.$reading.month",0);; ## aktueller Monatsverbrauch\
set_Reading ("$device.$reading.year",0);; ## aktueller Jahresverbrauch\
set_Reading ("$device.$reading.last_hour",0);; ## Verbrauch der letzten Stunde\
set_Reading ("$device.$reading.last_day",0);; ## Verbrauch des letzten Tages\
set_Reading ("$device.$reading.last_month",0);; ## Verbrauch des letzten Monats\
set_Reading ("$device.$reading.last_year",0);; ## Verbrauch des letzten Jahres\
## Log definieren\
fhem ("defmod log.counter.$device.$reading FileLog ./log/counter.$device.$reading.log $SELF:$device.$reading.last_.*");;\
fhem ("attr log.counter.$device.$reading room Filelogs");;\
}\
}\
\
} ## Ende subs-Block\
\
get_data { ## Optionale Übernahme bestehender Daten aus dem Log\
for (my $i=0;;$i<@{$_counter};;$i++) \
{ ## my $i=3;;\
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_hour","bar2day",-10,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_hour"));;\
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_day","bar2month",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_day"));;\
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_month","bar2year",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_month"));;\
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_year","bar2decade",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_year"));;\
}\
}\
\
hour {[:00];; ## Sicherung der Daten der letzten Stunde\
for (my $i=0;;$i<@{$_counter};;$i++) { ## Für jeden Zähler wird die Funktion hour aufgerufen\
hour($_counter[$i][0],$_counter[$i][1],$mday,$yday);;\
}\
}\
\
midnight {[00:01];; ## Sicherung der Daten um Mitternacht\
for (my $i=0;;$i<@{$_counter};;$i++) { ## Für jeden Zähler wird die Funktion midnight aufgerufen\
midnight($_counter[$i][0],$_counter[$i][1],$mday,$yday);;\
}\
}\
\
init { ## initialisierung aller Readings\
for (my $i=0;;$i<@{$_counter};;$i++) {## Für jeden Zähler werden Readings über die Funktion init_readings initialisiert\
init_readings($_counter[$i][0],$_counter[$i][1]);;\
}\
}\
\
DEF TPL_stat (\
day_count_$1_$2 { ## bei einem Event des Zählers, wird der tägliche, monatliche und jährliche Verbrauch im jeweiligen Reading festgehalten\
## $1 Zählerdevice, $2 Zählerreading\
\
# my $diff = int(([$1:$2,0]-(get_Reading("$1.$2.last_counter",0)))*1000)/1000;;\
set_Reading ("$1.$2.last_counter",[$1:$2,0]);;\
set_Reading ("$1.$2.hour",int(([$1:$2,0]-(get_Reading("$1.$2.hour_counter",0)))*1000)/1000,1);;\
}\
)\
\
## Pro Zähler wird über eine FOR-Schleife ein day_count_<Device>_<Reading>-Block generiert\
FOR(@{$_counter},TPL_stat($1$1,$1$2)) ## $1$1 entspricht dem Device, $1$2 entspricht dem Reading
attr di_counter_new room Verbrauch
attr di_counter_new uiTable {package ui_Table;;} ## Optionale Visualisierung der Energie-Verbräuche/-Produktion im DOIF-Device\
\
## Template für die Darstellung eines Wertes, einzelne card-Aufrufe können auskommentiert werden\
DEF TPL_single (\
##card([$SELF:$2.$3.day:col1w],"$1",undef,$4,$5,$10,$11,"$12",undef,"1","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")| Wochendarstellung\
card([[$SELF:$2.$3.last_hour:bar2day-10],[$SELF:$2.$3.hour]],"$1 in $12/h",undef,$4/12,$5/12,$10,$11,["letzte","aktuell"],undef,"2","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\
card([[$SELF:$2.$3.last_day:bar2month-300],[$SELF:$2.$3.day]],"$12/Tag",undef,$4,$5,$10,$11,["letzter","aktuell"],undef,"1","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\
card([[$SELF:$2.$3.last_month:bar2year-300],[$SELF:$2.$3.month]],"$12/Monat",undef,$6,$7,$10,$11,["letzter","aktuell"],undef,"0","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\
card([[$SELF:$2.$3.last_year:bar2decade-300],[$SELF:$2.$3.year]],"$12/Jahr",undef,$8,$9,$10,$11,["letzter","aktuell"],undef,"0","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")\
)\
\
## Template für die Darstellung von zwei Werten, einzelne card-Aufrufe können auskommentiert werden\
DEF TPL_double (\
##card([[$SELF:$3.$4.day:col1w],[$SELF:$6.$7.day:col1w]],"$1",undef,$8,$9,$14,$15,["$2","$5"],undef,"1","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")| Wochendarstellung\
card([[$SELF:$3.$4.last_hour:bar2day-10],[$SELF:$6.$7.last_hour:bar2day-10],[$SELF:$3.$4.hour],[$SELF:$6.$7.hour]],"$1/h",undef,$8/12,$9/12,$14,$15,["$2","$5","$2","$5"],undef,"2","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\
card([[$SELF:$3.$4.last_day:bar2month-300],[$SELF:$6.$7.last_day:bar2month-300],[$SELF:$3.$4.day],[$SELF:$6.$7.day]],"pro Tag",undef,$8,$9,$14,$15,["$2","$5","$2","$5"],undef,"1","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\
card([[$SELF:$3.$4.last_month:bar2year-300],[$SELF:$6.$7.last_month:bar2year-300],[$SELF:$3.$4.month],[$SELF:$6.$7.month]],"pro Monat",undef,$10,$11,$14,$15,["$2","$5","$2","$5"],undef,"0","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\
card([[$SELF:$3.$4.last_year:bar2decade-300],[$SELF:$6.$7.last_year:bar2year-300],[$SELF:$3.$4.year],[$SELF:$6.$7.year]],"pro Jahr",undef,$12,$13,$14,$15,["$2","$5","$2","$5"],undef,"0","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")\
)\
\
## Die Visualisierung einer Tabellenzeile wird über die obigen beiden Templates vorgenommen, hier zeilenweise anpassen/löschen:\
\
## Über das Template TPL_single wird jeweils pro card ein Wert visualisiert\
## Überschrift,Device,Reading,minTag,maxTag,minMonat,maxMonat,minJahr,maxJahr,minColor,maxColor,Einheit\
TPL_single (Frischwasser,MQTT2_DVES_C58DCB,total_w,0,500,0,10000,0,80000,90,0,Liter)\
TPL_single (Gas,MQTT2_DVES_C58DCB,total_gas,0,10,0,250,0,2000,90,0,m³)\
TPL_single (Einspeisung,MQTT2_DVES_C58DCB,total_f,0,30,0,600,0,5000,0,90,kWh)\
TPL_single (Bezug,MQTT2_DVES_C58DCB,total_c,-10,0,-300,0,-3000,0,0,90,kWh)\
TPL_single (Stromkosten,di_tibber,costsSum,0,4,0,90,0,1200,90,0,€)\
\
## Über das Template TPL_double werden jeweils pro card zwei Werte visualisiert\
## Überschrift,Bezeichnung1,Device1,Reading1,Bezeichnung2,Device2,Reading2,minTag,maxTag,minMonat,maxMonat,minJahr,maxJahr,minColor,maxColor,Einheit\
##TPL_double (Heizenergie,Gesamt,vaillant,total_h,Wasser,vaillant,total_hwc,0,100,0,2000,0,20000,90,0,kWh)\
\
##TPL_double (Stromeinspeisung/Strombezug,Bezug,MQTT2_DVES_C58DCB,total_c,Einsp.,MQTT2_DVES_C58DCB,total_f,-10,25,-300,600,-3000,5000,0,90,kWh)
Bemerkungen:
- Die Visualisierung der Verläufe über das Attribut uiTable ist optional.
- Die Verlaufswerte der grafischen Darstellung mit Hilfe der card-Funktion werden im DOIF-Device gespeichert. Bereits geloggte Daten können mit set di_counter_new get_data importiert werden, siehe dazu auch Datenimport
- Die obige Definition funktioniert nur mit Zählern, die mit aufsteigenden Werten (positiv/negativ) arbeiten, wie z. B. Stromverbrauch in kWh, Wasserverbrauch in Litern usw.. Es funktioniert nicht mit momentanen Werten, wie z. B. aktuelle Leistungsaufnahme eines Verbrauchers in Watt, diese müssten zunächst kumuliert werden.
Ergebnis der Beispieldefinition in der Webansicht:
Weiterführende Links
- Dokumentation DOIF/Perl-Modus
- DOIF-WEB-Interface DOIF/uiTable Schnelleinstieg