Bitte um Kommentare zur meiner automatischen Heizungsabschaltung

Begonnen von The Grue, 14 November 2021, 13:46:01

Vorheriges Thema - Nächstes Thema

The Grue

Servus zusammen!

Mit Hilfe des Forums habe ich inzwischen eine relativ ordentliche Heizungsabschaltung, wenn Fenster oder Tür geöffnet wird. Allerdings ist das Ding, bedingt durch meine geringe Erfahrung, noch nicht "schön" und da hoffe ich auf Eure Hilfe.

Gegeben sind Sensoren an Tür und Fenster sowie ein Thermostat.

Wenn Tür oder Fenster geöffnet werden, wird sich der aktuelle Zustand des Thermostates gemerkt und die Heizung abgeschaltet.
Wenn das Fenster geöffnet wird, passiert die Abschaltung (fast) sofort.
Wenn die Tür geöffnet wird, passiert die Abschaltung mit Verzögerung.
Wenn irgendwann sowohl Tür als auch Fenster geschlossen sind, dann wird der ursprüngliche Zustand wiederhergestellt.

(Wenn erst Tür, dann Fenster geöffnet wird gibt's auch die Verzögerung. Nicht hübsch, aber damit kann ich leben).

Hier kommt dann mal mein Code:


defmod Bedroom.ThermostatControl DOIF subs {\
  sub store_and_off {\
    Log3 "Bedroom.ThermostatControl", 3, "Bedroom.ThermostatControl: Store and off";;\
    fhem_set("Bedroom.Thermostat tmOff");; \
  }\
  sub thing_closed {\
    my ($thing, $delay)=@_;;\
Log3 "Bedroom.ThermostatControl", 5, "thing: " . $thing . " delay: " .$delay ;;\
    if (not $_DoorOpen and get_Exec("store_and_off_timer") == 0 ) {\
      $_OldMode = "tm" . ucfirst(ReadingsVal("Bedroom.Thermostat", "thermostatMode", ""));; \
      Log3 "Bedroom.ThermostatControl", 3, "Bedroom.ThermostatControl: " . $thing . " Opened. Old Mode: " . $_OldMode;;\
      set_Exec("store_and_off_timer", $delay, 'store_and_off()');;\
    }\
$_DoorOpen = 1;;\
  }\
}\
{ \
  if ([Bedroom.Window.Sensor:alarm] eq "AccessControl: Window/Door is open") \
  { \
  thing_closed("Window", 1) ;;\
  } \
  if ([Bedroom.Door.Sensor:alarm]   eq "AccessControl: Window/Door is open") \
  { \
  thing_closed("Door", 300) ;;\
  } \
  if ([Bedroom.Window.Sensor:alarm] eq "AccessControl: Window/Door is closed" and \
      [Bedroom.Door.Sensor:alarm]   eq "AccessControl: Window/Door is closed") \
  { \
    $_DoorOpen = 0;;\
    if (get_Exec("store_and_off_timer") > 0 ){\
      Log3 "Bedroom.ThermostatControl", 3, "Bedroom.ThermostatControl: Delete timer";;\
      del_Exec("store_and_off_timer");;\
    } else {\
      Log3 "Bedroom.ThermostatControl", 3, "Bedroom.ThermostatControl: Restore Old Mode: " . $_OldMode;;\
      fhem_set("Bedroom.Thermostat ". $_OldMode) if defined $_OldMode;; \
    }\
  } \
}


Am meisten stören mich eigentlich die Log3 Aufrufe:
    Log3 "Bedroom.ThermostatControl", 3, "Bedroom.ThermostatControl: Store and off";;\

Ich dachte, das müsste doch auch irgendwie so gehen, hab's aber nicht hinbekommen:
    Log3 $DEVICE, 3, $DEVICE . ": Store and off";;\
Das führt zum Fehler

ZitatBedroom.ThermostatControl DOIF: error in defs block: Global symbol "$DEVICE" requires explicit package name (did you forget to declare "my $DEVICE"?) at (eval 782178) line 3.

Gibt's $DEVICE im perl mode nicht? Kann ich das anders erreichen?
(ok, store_and_off bräuchte ich eigentlich gar nicht mehr... aber das Problem habe ich ja bei allen Log3s)


Was mir noch nicht gefällt: Wenn ich das im Wohnzimmer auch haben möchte, dann gibt's eine copy/paste/search/replace - Orgie. Aber vielleicht helfen mir da (doif-) templates.

Zuguterletzt noch ein etwas akademisches Problem: In dem Abschnitt
    if (get_Exec("store_and_off_timer") > 0 ){\
      Log3 "Bedroom.ThermostatControl", 3, "Bedroom.ThermostatControl: Delete timer";;\
      del_Exec("store_and_off_timer");;\


Hier habe ich ja eine race condition: Wenn der Timer zwischen der Abfrage ob er läuft und dem Löschen des Timers abläuft, wird er a) ausgeführt obwohl ich nicht will und b) wird ein nicht existenter Timer gelöscht. Das wird nicht oft vorkommen, aber wie könnte ich das verhindern?

Auch ansonsten: bitte haut mir alles um die Ohren, was nicht ordentlich ist, ich will ja was lernen :)

Vielen Dank,
Markus


Beta-User

Das ganze kommt mir übermäßig kompliziert und wenig generisch vor...

Ich habe für Homematic folgende Konstruktion: Ein notify für alle echten Fensterkontakte, für jede Heizkörper-Gruppe ein virtueller Fensterkontakt. In dem steht jeweils drin, welche echten FK's "zu ihm" gehören (auch userAttr).

- Geht ein Fenster auf (und es ist Heizperiode), wird ein InternalTimer generiert, der dann nach Zeitablauf checkt, ob alle zugehörigen Kontakte zu sind => sonst "Fenster-auf" Reaktion.

- Beim Schließen werden alle direkt gecheckt => alle zu? => "Fenster-zu"-Reaktion...

Simpel. Alle Angaben da, wo man es braucht (bei mir: virtueller Kontakt, bei dir: vermutlich der Thermostat). Kurze Auswertung, generisch, für alle passend/anpassbar...

Würde heute vermutlich noch die Zeiten an den Thermostaten hinterlegen, aber der default (90 Sek) ist eigentlich auch ok...

Der Code für myUtils:
sub myWinContactNotify {  #three parameters, last (timeout) is optional
  my ($window, $event, $timeout) = @_;
  $timeout = 90 unless $timeout;
  my @virtuals = devspec2array("TYPE=CUL_HM:FILTER=model=VIRTUAL:FILTER=myRealFK=.*$window.*");
  for my $virtual (@virtuals) {
    my $myreals = AttrVal($virtual,"myRealFK","");
    if ($event =~ /open|tilted/) {
      my $checktime = gettimeofday()+$timeout;
      InternalTimer($checktime,"myTimeoutWinContact",$virtual);   
    } else {
      my @wcs = split(',',$myreals);
      my $openwc = 0;
      for my $wc (@wcs) {
        $openwc++ if (ReadingsVal($wc,"state","closed") ne "closed");
        last if $openwc;
      }
      CommandSet (undef,"$virtual geschlossen") if !$openwc;
    }
  }
  return;
}

sub myTimeoutWinContact {
  my $name = shift // return;
  #my $name = $hash{NAME};
  return if !ReadingsVal("Heizperiode","state","off") eq "on";
  my $myreals = AttrVal($name,"myRealFK","");
  my @wcs = split(',',$myreals);
  my $openwc = 0;
  for my $wc (@wcs) {
    $openwc++ if ReadingsVal($wc,"state","closed") ne "closed";
    last if $openwc;
  }
  CommandSet (undef,"$name offen") if $openwc;
  return;
}


Das notify:
defmod n_FK_TK_notify notify Fenster_.*:open|Fenster_.*:closed|Dachfenster_.*:open|Dachfenster_.*:closed|Terrassentuer_.Z:open|Terrassentuer_.Z:closed|Balkontuer:open|Balkontuer:closed|Haustuer:closed|Haustuer:open { myWinContactNotify ($NAME, $EVENT) }
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Damian

Zitat von: The Grue am 14 November 2021, 13:46:01
Ich dachte, das müsste doch auch irgendwie so gehen, hab's aber nicht hinbekommen:
    Log3 $DEVICE, 3, $DEVICE . ": Store and off";;\
Das führt zum Fehler

Gibt's $DEVICE im perl mode nicht? Kann ich das anders erreichen?
(ok, store_and_off bräuchte ich eigentlich gar nicht mehr... aber das Problem habe ich ja bei allen Log3s)


Im Perlmode $device verwenden, das ist eine echte Perlvariable

Zitat
Zuguterletzt noch ein etwas akademisches Problem: In dem Abschnitt
    if (get_Exec("store_and_off_timer") > 0 ){\
      Log3 "Bedroom.ThermostatControl", 3, "Bedroom.ThermostatControl: Delete timer";;\
      del_Exec("store_and_off_timer");;\


Hier habe ich ja eine race condition: Wenn der Timer zwischen der Abfrage ob er läuft und dem Löschen des Timers abläuft, wird er a) ausgeführt obwohl ich nicht will und b) wird ein nicht existenter Timer gelöscht. Das wird nicht oft vorkommen, aber wie könnte ich das verhindern?

Das wird nicht passieren. Der Timer kann nicht dazwischen kommen, dazu müsste die Kontrolle von DOIF an FHEM abgegeben werden, dass passiert hier nicht - es ist hier alles Single-Thread.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF