Autor Thema: universeller countdown timer (mit on-for-timer unterstützung)  (Gelesen 1705 mal)

Offline justme1968

  • Developer
  • Hero Member
  • ****
  • Beiträge: 20001
da homekit für die bewässerungs steuerung inzwischen auch die anzeige der restlaufzeit unterstützt habe ich mir einen mehr oder weniger universellen countdown timer gebaut.
 
den timer kann man auch für eine restlaufzeit anzeige bei on-for-timer verwenden. zumindest für homematic und bei allen geräten die die SetExtensions verenden.

vielleicht hat ja noch jemand verwendung dafür.
 

von hand kann das ganze auf perl ebene so verendet werden: startCountdown($name,$dauer);
statt des namens kann auch direkt der device hash übergeben werden. der timer zählt rückwärts bis 0 und aktualisiert alle 30 sekunden das reading timerRemaining im device. nach dem der timer bei 0 angekommen ist wird das remaining reading gelöscht.

um den timer vorzeitig anzuhalten kann man stopCountdown($name); verwenden. auch hier kann statt des namens direkt der device hash übergeben werden.
 
 
um ein device das von sich aus das on-for-timer kommando anbietet um ein remaining reading zu ergänzen kann man den timer auch aus einem passenden notify heraus starten. das kann im einfachsten fall so aussehen: define startTimer notify <device>:.* {startCountdown($NAME)}
idealerweise grenzt man die regex für das event so weit ein das nur die relevanten events matchen. dies muss bei homematic mindestens das set_on-for-timer und optional das off event sein. bei allen anderen devices die die SetExtensions verwenden muss es on und optional off sein.
 
achtung: der timer wird zwar bei manuellem off automatisch abgebrochen (wenn das off event im notify berücksichtigt wird. die meisten anderen schaltzusände (wir z.b. ein normales on wärend das on-for-timer noch läuft) werden (noch) nicht korrekt berücksichtig. das kann man mit einem passenden stopCountdown aufruf von hand beheben.

der code für 99_myUtils.pm:sub                               
startCountdown($;$$) {           
  my($name, $duration, $interval) = @_;
                                 
  my $hash = $name;               
  $hash = $defs{$name} if( ref($hash) ne 'HASH' );
  $name = $hash->{NAME};         
                                 
  if( !$hash ) {                 
    Log3 $name, 2, "startCountdown error: no such device: $name";
    return;                       
  }                               
                                 
  Log3 $name, 4, "startCountdown for: $name";
                                 
   my $remaining;                 
  if( !defined($duration) ) {     
    my $state = ReadingsVal($name, 'state', undef);
    if( $state eq 'off' ) {       
      stopCountdown($name);       
      return;                     
    } elsif( defined(ReadingsVal($name, 'timerDuration', undef)) ) {
      return;                     
    };                           
                                 
    $duration = "<unknown>";     
    if( my $TIMED_OnOff = $hash->{TIMED_OnOff} ) {
      $duration = $TIMED_OnOff->{DURATION};
      $remaining = $TIMED_OnOff->{START} + $TIMED_OnOff->{DURATION} - time();
    } elsif( $state =~ m/set_on-for-timer (\d*)/ ) {
      $duration = $1;             
      $remaining = $1;           
    } elsif( $state =~ m/set_off-for-timer (\d*)/ ) {
      $duration = $1;             
      $remaining = $1;           
    }                             
                                 
  }                               
                                 
  if( $duration ne "<unknown>" ) {
    if( $duration <= 0 ) {       
      stopCountdown($hash);       
      return;                     
    }                             
                                 
    readingsSingleUpdate($hash, 'timerDuration', $duration, 1);
    updateCountdown($hash, $remaining);
                                 
  } else {                       
    readingsSingleUpdate($hash, 'timerDuration', $duration, 1);
                                 
  }                               
                                 
  return;                         
}                                 
                                 
sub                               
updateCountdown($;$) {           
  my($name, $remaining) = @_;     
                                 
  my $hash = $name;               
  $hash = $defs{$name} if( ref($hash) ne 'HASH' );
  $name = $hash->{NAME};         
                                 
  if( !$hash ) {                 
    Log3 $name, 2, "updateCountdown error: no such device: $name";
    return;                       
  }                               
                                 
  if( !defined($remaining) ) {   
    $remaining = "<unknown>";     
                                 
    if( my $TIMED_OnOff = $hash->{TIMED_OnOff} ) {
      $remaining = $TIMED_OnOff->{START} + $TIMED_OnOff->{DURATION} - time();
    } else {                     
      $remaining = ReadingsVal($name, 'timerDuration', undef);
      if( $remaining ne '<unknown>' ) {
        my $age = ReadingsAge($name, 'timerDuration', undef);
        $remaining = $remaining - $age;
      }                           
    }                             
  }                               
                                 
  Log3 $name, 4, "updateCountdown: remaining $remaining";
  if( $remaining ne "<unknown>" ) {
    if( $remaining <= 0 ) {       
      stopCountdown($name);       
      return;                     
    }                             
                                 
    readingsSingleUpdate($hash, 'timerRemaining', int($remaining), 1);
    InternalTimer( gettimeofday() + 30, 'updateCountdown', $hash);
  }                               
}                                 
                                 
sub                               
stopCountdown($) {               
  my($name) = @_;                 
                                 
  my $hash = $name;               
  $hash = $defs{$name} if( ref($hash) ne 'HASH' );
  $name = $hash->{NAME};         
                                 
  if( !$hash ) {                 
    Log3 $name, 2, "stopCountdown error: no such device: $name";
    return;                       
  }                               
                                 
  Log3 $name, 4, "stopCountdown for: $name";
                                 
  readingsSingleUpdate($hash, 'timerRemaining', 0, 1);
                                 
  RemoveInternalTimer( $hash, 'updateCountdown' );
  CommandDeleteReading( undef, "$name timerDuration" );
  CommandDeleteReading( undef, "$name timerRemaining" );
                                 
  return;                         
}

testen kann man das z.b. mit einem dummy:define timer dummy
attr timer setList on off set_on-for-timer
attr timer useSetExtensions 1
define timerNotify notify timer:.* {startCountdown($NAME)}

inform timer timer
set timer on-for-timer 60

um schneller etwas zu sehen empfiehlt es sich bei den tests das update intervall von 30 auf 1 oder 2 zu verkürzen.

edit 2018-02-09:code etwas überarbeitet. reading in timerRemaining umbenannt, zusätzliches reading timerDuration eingebaut.
« Letzte Änderung: 09 Februar 2018, 13:51:43 von justme1968 »
FHEM5.4,DS1512+,2xCULv3,DS9490R,HMLAN,2xRasPi
CUL_HM:HM-LC-Bl1PBU-FM,HM-LC-Sw1PBU-FM,HM-SEC-MDIR,HM-SEC-RHS
HUEBridge,HUEDevice:LCT001,LLC001,LLC006,LWL001
OWDevice:DS1420,DS18B20,DS2406,DS2423
FS20:fs20as4,fs20bs,fs20di
AKCP:THS01,WS15
CUL_WS:S300TH
Gefällt mir Gefällt mir x 3 Liste anzeigen

Offline justme1968

  • Developer
  • Hero Member
  • ****
  • Beiträge: 20001
Antw:universeller countdown timer (mit on-for-timer unterstützung)
« Antwort #1 am: 09 Februar 2018, 13:44:23 »
edit 2018-02-09:code etwas überarbeitet. reading in timerRemaining umbenannt, zusätzliches reading timerDuration eingebaut.
FHEM5.4,DS1512+,2xCULv3,DS9490R,HMLAN,2xRasPi
CUL_HM:HM-LC-Bl1PBU-FM,HM-LC-Sw1PBU-FM,HM-SEC-MDIR,HM-SEC-RHS
HUEBridge,HUEDevice:LCT001,LLC001,LLC006,LWL001
OWDevice:DS1420,DS18B20,DS2406,DS2423
FS20:fs20as4,fs20bs,fs20di
AKCP:THS01,WS15
CUL_WS:S300TH
Gefällt mir Gefällt mir x 1 Liste anzeigen

Offline FunkOdyssey

  • Hero Member
  • *****
  • Beiträge: 1897
Antw:universeller countdown timer (mit on-for-timer unterstützung)
« Antwort #2 am: 03 Januar 2020, 21:51:10 »
Gerade mal wieder über diesen Thread gestolpert und ich bin erneut begeistert.
Danke für die Funktion und die Anleitung.
Eigentlich schade, dass so etwas nicht bereits in den SetExtensions enthalten ist.

 

decade-submarginal