Hallo,
ich habe folgendes anliegen:
Alle HM-CC-RT-DN (nur Kanal 4) auf "controlManu on" setzen um eine Wartung (Entlüften) der Heizungsanlage durchzuführen
Alle HM-CC-RT-DN (nur Kanal 4) auf "controlParty" setzen um "unverheizt" in den Urlaub zu fahren
Dazu müsste mir FHEM eine Liste der "bekannten" HM-CC-RT-DN ausgeben. Realisiert habe ich das nun wie folgt:
Eine Datei 99_ThermoMainentanceUtils.pm angelegt.
Darin habe ich eine globale Variable als Array definiert.
my @thermostates;
Mittels der nachfoglenden Funktion bekomme ich eine Liste aller Kanale aller "bekannten" HM-CC-RT-DN. Diese filtere ich nach Kanal 4.
sub ThermoGetAll() {
# clear current array of devices
@thermostates = ();
# get all HM-CC-RT-DN devices and channels
my @devices = devspec2array("model=HM-CC-RT-DN");
for my $device (@devices) {
# only channel 4 (Clima) is important
if ($device =~ m/_Clima$/) {
push(@thermostates, ThermoCreateRecord($device));
}
}
}
sub ThermoCreateRecord($) {
my ($device) = @_;
my $thermostate = {
device => $device,
temperature => "0.0",
mode => "auto"
}
}
Durch das "push" werden die "gesuchten" Kanäle als "record" in das Array abgelegt. Dadurch kann ich auch die Temperatur und den Betriebsmodus pro Gerät vor der Wartung speichern.
Starten tue ich dann die Wartung durch
sub ThermoMaintenanceOn() {
foreach my $record (@thermostates) {
# get current temperature setting of device
$record->{temperature} = fhem("get $record->{device} param desired-temp");
# get current mode of device
$record->{mode} = fhem("get $record->{device} param controlMode");
# open valve full
fhem("set $record->{device} controlManu on");
# update device immediate
fhem("set $record->{device} burstXmit");
}
}
Beenden kann ich die Wartung mittels
sub ThermoMaintenanceOff() {
foreach my $record (@thermostates) {
# restore mode of device
fhem("set $record->{device} controlMode $record->{mode}");
# restore temperature setting of device
fhem("set $record->{device} desired-temp $record->{temperature}");
# update device immediate
fhem("set $record->{device} burstXmit");
}
}
Für den Urlaub gibt es
sub ThermoVacation($$$$$) {
my ($temperature, $dateStart, $dateEnd, $timeStart, $timeEnd) = @_;
# map time to 00 or 30, others are not accepted by device
$timeStart =~ s/\:[0-2].$/:00/;
$timeStart =~ s/\:[3-5].$/:30/;
$timeEnd =~ s/\:[0-2].$/:00/;
$timeEnd =~ s/\:[3-5].$/:30/;
foreach my $record (@thermostates) {
# set "party/vacation" mode
fhem ("set $record->{device} controlParty $temperature $dateStart $timeStart $dateEnd $timeEnd");
}
}
Alles funktioniert wie es soll, nur werde ich das Gefühl nicht los, dass es etwas ähnliches eigentlich schon geben müsste oder?
Daher meine Frage: Gibt es in FHEM hierfür schon eine Funktionalität die ich "übersehen" habe?
-> Wenn ja bitte einen Schubs zur entsprechenden Doku.
Naja, in der Regel hat man wahrscheinlich irgendein Schema für die Bezeichnung.
Damit lässt sich z.B. bei mir mit einem einzelnen
fhem ("set .*_Heizung_Clima controlManu on")
Dein Entlüften vorbereiten und sinngemäß auch wieder beenden.
Dein Clima Kanal kannst aber auch einfacher finden
:FILTER=chanNo=04
@Hollo:
naja das
..._Clima
ist ja vom System vorgegeben, damit könnte ich arbeiten. Mir ist nur nicht klar wie ich dein
fhem("set .*_Heizung_Clima controlManu on")
wieder rückgängig mache?
Ein einfaches
fhem("set .*_Heizung_Clima controlManu off")
langt da nicht. Ich muss mir ja irgendwie merken wie die Thermostate vorher eingestellt waren.
@CoolTux:
Wo genau würde dieser Filter angewendet werden? Etwa so?
my @devices = devspec2array("model=HM-CC-RT-DN:FILTER=chanNo=4");
Danke und Gruß
Zitat von: __benny__ am 08 November 2017, 08:12:42
@Hollo:
naja das
..._Clima
ist ja vom System vorgegeben, damit könnte ich arbeiten. Mir ist nur nicht klar wie ich dein
fhem("set .*_Heizung_Clima controlManu on")
wieder rückgängig mache?
Ein einfaches
fhem("set .*_Heizung_Clima controlManu off")
langt da nicht. Ich muss mir ja irgendwie merken wie die Thermostate vorher eingestellt waren.
@CoolTux:
Wo genau würde dieser Filter angewendet werden? Etwa so?
my @devices = devspec2array("model=HM-CC-RT-DN:FILTER=chanNo=4");
Danke und Gruß
Bei mir geht das so
{ devspec2array("model=HM-CC-RT-DN:FILTER=chanNo=04") }
Getestet direkt in der Eingabezeile von FHEMWEB
Zitat von: __benny__ am 08 November 2017, 08:12:42
...Ich muss mir ja irgendwie merken wie die Thermostate vorher eingestellt waren.
Mehr oder weniger. ;D
Wenn sie sonst auf "auto" stehen, setzt Du sie halt einfach wieder auf auto und die arbeiten direkt mit dem gültigen Wert der Temp-Liste.
Bei "manual" setzt Du sie einfach auf einen "passenden" Temperaturwert; Du wirst das Entlüften ja nicht mitten in der Nacht machen wollen.
fhem("set .*_Heizung_Clima controlManu 20.0")
@Hollo
eigentlich will ich nach dem Entlüften nicht nochmal 10 Heizkörper händisch anfassen, das widerspricht irgendwie dem Wort "Automatisierung" ::) ;D
@CoolTux
klappt leider nicht, das Ergebnis ist dann kein Array sondern eine Zahl?
Naja dann scheint es keinen "natürlichen" Weg zu geben - Danke an alle Antwortenden -> gelöst
Zitat von: __benny__ am 08 November 2017, 19:30:05
@Hollo
eigentlich will ich nach dem Entlüften nicht nochmal 10 Heizkörper händisch anfassen, das widerspricht irgendwie dem Wort "Automatisierung" ::) ;D
Was
Was ist an 1 Befehl händisch und umständlich? :o
Dein Weg ist doch okay, wenn er funktioniert.
Es gibt meist mehrere Varianten und selten die Ideallösung.
Zitat von: __benny__ am 08 November 2017, 19:30:05
@Hollo
eigentlich will ich nach dem Entlüften nicht nochmal 10 Heizkörper händisch anfassen, das widerspricht irgendwie dem Wort "Automatisierung" ::) ;D
@CoolTux
klappt leider nicht, das Ergebnis ist dann kein Array sondern eine Zahl?
Naja dann scheint es keinen "natürlichen" Weg zu geben - Danke an alle Antwortenden -> gelöst
Ja natürlich ist es eine Zahl. Weil die Liste in ein Array gelesen wird. Und das return Dir nur die Anzahl der Elemente zurück gibt. Du musst das ganze dann halt wie ein Perl Array behandeln.
@Hollo
Naja ich muss diesen zusätzlich in die Console eingeben, nachdem ich mir den Namen vom Device gesucht habe. Schließlich ist ja nicht klar, dass immer das gleiche Gerät gerade im Modus "Manu" ist. Mit der momentanen Lösung heißt es "Feuern-und-vergessen".
@CoolTux
Mit folgendem Code sehe ich die Log-Meldung
sub ThermoGetAll() {
# clear current array of devices
@thermostates = ();
# get all HM-CC-RT-DN devices and channels
my @devices = devspec2array("model=HM-CC-RT-DN");
for my $device (@devices) {
# only channel 4 (Clima) is important
if ($device =~ m/_Clima$/) {
{ Log 1, "ThermoGetAll: $device" };
push(@thermostates, ThermoCreateRecord($device));
}
}
}
damit leider nicht
sub ThermoGetAll() {
# clear current array of devices
@thermostates = ();
# get all HM-CC-RT-DN devices and channels
my @devices = devspec2array("model=HM-CC-RT-DN:FILTER=chanNo=4");
for my $device (@devices) {
{ Log 1, "ThermoGetAll: $device" };
push(@thermostates, ThermoCreateRecord($device));
}
}
Mal noch eine andere Frage zum Thema:
Wenn ich die Kanäle der Geräte einem speziellen "room" zuteile, dann müsste ich mir doch alle Geräte dieses Raums geben lassen können. Das müsst ich zwar konfigurieren, dafür könnte ich allerdings bestimmte Geräte von der Aktion ausschließen oder?
Benny! Konzentration und bisschen nachschauen bitte!
04
Man(n) beachte die 0 vor der vier
;D ;D ;D
Grüße
Leon
Bissel viel Durcheinander! ;)
sub ThermoGetAll() {
# clear current array of devices
# @thermostates = ();
# hier fehlte ein my
my @thermostates;
# get all HM-CC-RT-DN devices and channels
my @devices = devspec2array("model=HM-CC-RT-DN:FILTER=chanNo=04");
# for my $device (@devices) {
# hier sollte foreach stehen
foreach my $device (@devices) {
{ Log 1, "ThermoGetAll: $device" };
push(@thermostates, ThermoCreateRecord($device));
}
}
Gruß
Dan
Danke Dir Dan.
@Dan
nöp fehlte nicht, nur ist @thermostates außerhalb der "sub" global definiert, sonst wäre das ja weg am Ende der sub und wäre sinnfrei... -> siehe initialen Post
@CoolTux
verdammt, die "0" bringts :-) Danke
Zitat von: __benny__ am 09 November 2017, 18:17:16
@Dan
nöp fehlte nicht, nur ist @thermostates außerhalb der "sub" global definiert, sonst wäre das ja weg am Ende der sub und wäre sinnfrei... -> siehe initialen Post
@CoolTux
verdammt, die "0" bringts :-) Danke
Global würde ich sowas aber lieber nicht definieren.
Was spricht dagegen die Variable an die jeweiligen Funktionen weiterzugeben?
Gruß
Dan
@Dan
naja irgendwo muss ich es vorhalten. In der Sprache "C" würde ich diese Variable in der main-Funktion definieren und genau wie du sagst an jede Funktion als Pointer übergeben. Wäre ein "dummy" in fhem.cfg dazu äquivalent?
Oder wäre die "globale" Definition schon ok nur die Übergabe an einzelne Funktionen fehlt noch? Wie macht man sowas korrekt in Perl?
Wieso musst Du es denn "vorhalten"?
Mit:
my @devs = devspec2array("model=HM-CC-RT-DN:FILTER=chanNo=04");
hast Du sofort immer "lokal" ein Array mit den Namen aller Devices die zu der devspec gehören.
Gruß
Dan
Ich bin kein "Perl-Profi".
Angewöhnt habe ich mir global nur Konstanten zu setzen.
z.B.:
my $thermostats = "model=HM-CC-RT-DN:FILTER=chanNo=04";
Und dann z.B.:
sub my_func {
my @devs = devspec2array($thermostats);
}
Gruß
Dan
Hi,
soweit ich das verstehe, ist das "Problem" sich den alten Zustand zu merken und dann später wieder zurückzuholen. Ich würde da ganz "brutal" das ganze am Device selbst machen. Also in etwa so:
$main::defs{$device}{bennysOldDesiredTemp} = ReadingsVal($device, "desired-temp",22);
...und später
fhem("set ".$device." desired-temp ".$main::defs{$device}{bennysOldDesiredTemp});
delete $main::defs{$device}{bennysOldDesiredTemp};
Man sieht dann sogar in den Internals, was man getrieben hat.
Wenn das ganze einen FHEM-Neustart überleben soll, dann kann man das auch mit Readings machen:
readingsSingleUpdate($main::defs{$device}, "bennysOldDesiredTemp", ReadingsVal($device, "desired-temp",22), 1);
...und später
fhem("set ".$device." desired-temp ".ReadingsVal($device, "bennysOldDesiredTemp",22));
fhem("deletereading ".$device." bennysOldDesiredTemp");
Das mit den Deletes ist natürlich optional.
Ich habe das nicht ausprobiert...
Gruß,
Thorsten
Vorhalten, weil ich mir ja die Zustände der Geräte merken will bevor ich temporär die Konfiguration überschreibe um diese dann nach der Wartung wieder so einzustellen wie diese vor der Wartung eingestellt waren.
mit
push(@thermostates, ThermoCreateRecord($device));
wird ja die
sub ThermoCreateRecord($) {
my ($device) = @_;
# { Log 1, "ThermoCreateRecord: \$device: $device" };
my $thermostate = {
device => $device,
temperature => "0.0",
mode => "auto"
}
}
In dieser Struktur ist dann Platz für die Elemente der Konfiguration die überschreiben werden - konrekt so:
sub ThermoMaintenanceOn() {
foreach my $record (@thermostates) {
# get current temperature setting of device
$record->{temperature} = fhem("get $record->{device} param desired-temp"); # <--- hier wird die aktuell eingestellte Temperatur ausgelesen
# get current mode of device
$record->{mode} = fhem("get $record->{device} param controlMode"); # <--- hier wird der aktuell eingestellte Bedienmodus ausgelesen
# { Log 1, "ThermoMaintenanceOn: \$device=$record->{device} : $record->{temperature} : $record->{mode}" };
# open valve full
fhem("set $record->{device} controlManu on"); # <--- hier wird die Einstellung überschrieben
# update device immediate
fhem("set $record->{device} burstXmit");
}
}
Jetzt kann ich die Wartung durchführen und wenn ich damit fertig bin, dann brauche ich nur noch den Button anklicken der
sub ThermoMaintenanceOff() {
foreach my $record (@thermostates) {
# { Log 1, "ThermoMaintenanceOff: \$device=$record->{device} : $record->{temperature} : $record->{mode}" };
# restore mode of device
fhem("set $record->{device} controlMode $record->{mode}"); # <--- hier wird der gemerkte Bedienmodus restauriert
# restore temperature setting of device
fhem("set $record->{device} desired-temp $record->{temperature}"); # <--- hier wird die gemerkte Temperatur restauriert
# update device immediate
fhem("set $record->{device} burstXmit");
}
}
aufruft und alles ist so, als hätte ich nie etwas geändert.
Zitat von: __benny__ am 09 November 2017, 07:08:34
@Hollo
Naja ich muss diesen zusätzlich in die Console eingeben, nachdem ich mir den Namen vom Device gesucht habe. Schließlich ist ja nicht klar, dass immer das gleiche Gerät gerade im Modus "Manu" ist. Mit der momentanen Lösung heißt es "Feuern-und-vergessen".
Das kannst Du damit genauso. :)
@Hollo
Ich kann deinen Ansatz nicht nachvollziehen. Wärst du so nett mal Schritt für Schritt darzulegen wie das gehen soll? Also was muss ich alles tun um ein beliebiges Gerät mit deiner Methode so einzustellen wie es vor der Wartung war.
@Thorsten:
Interessant, leider stecke ich noch nicht so tief in FHEM drin, um deine Ausführungen direkt verstehen zu können.
Das legt eine neue Variable (Reading) "bennysOldDesiredTemp" am Gerät an oder? (Wo steht denn das in der Referenz?)
$main::defs{$device}{bennysOldDesiredTemp}
Das müsste dann also so in die sub
sub ThermoMaintenanceOn($) {
my ($device) = @_;
$main::defs{$device}{bennysOldDesiredTemp} = ReadingsVal($device, "desired-temp",22); # <-- aktuelle Temperatur lesen, falls Fehlschlag dann "22°C" annehmen
$main::defs{$device}{bennysOldcontrolMode} = ReadingsVal($device, "controlMode",auto); # <-- aktuellen Modus lesen, falls Fehlschlag dann "auto" annehmen
# { Log 1, "ThermoMaintenanceOn: \$device=$record->{device} : $record->{temperature} : $record->{mode}" };
# open valve full
fhem("set $record->{device} controlManu on"); # <--- hier wird die Einstellung überschrieben
# update device immediate
fhem("set $record->{device} burstXmit");
}
Wie würde ich dass denn in fhem.cfg aufrufen um alle benötigten Geräte zu erwischen, also nur die _Clima?