From 399b6ce3911fb34ea5c7ff73f0c3582c3f453948 Mon Sep 17 00:00:00 2001
From: Beta-User <>
Date: Sat, 11 May 2019 14:16:45 +0000
Subject: [PATCH] 98_Heating_Control: prepare for beeing deprecated;
 98_Weekdaytimer: add group functions to replace Heating_Control.

git-svn-id: https://svn.fhem.de/fhem/trunk@19369 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
 fhem/CHANGED                    |   3 +
 fhem/FHEM/98_Heating_Control.pm |  42 ++++++++++---
 fhem/FHEM/98_WeekdayTimer.pm    | 105 +++++++++++++++++++++-----------
 3 files changed, 108 insertions(+), 42 deletions(-)

diff --git a/fhem/CHANGED b/fhem/CHANGED
index dc799b7f8..47514140a 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,8 @@
 # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
 # Do not insert empty lines here, update check depends on it.
+  - change:  98_Heating_Control.pm will be removed soon. Users will need to
+             change their device definitions to 98_WeekdayTimer; supporting
+             code is provided, but perl calls have to be changed manually.
  - bugfix:  73_AutoShuttersControl: fix bug roommate and windwo comfort
  - bugfix:  73_DoorBird: Error 404 handling for history images corrected
  - bugfix:  73_AutoShuttersControl: fix sunset sunrise object values
diff --git a/fhem/FHEM/98_Heating_Control.pm b/fhem/FHEM/98_Heating_Control.pm
index 27a566d1f..c921410f3 100644
--- a/fhem/FHEM/98_Heating_Control.pm
+++ b/fhem/FHEM/98_Heating_Control.pm
@@ -50,7 +50,7 @@ sub Heating_Control_Set($@) {
   my ($hash, @a) = @_;
 
   return "no set value specified" if(int(@a) < 2);
-  return "Unknown argument $a[1], choose one of enable disable " if($a[1] eq "?");
+  return "Unknown argument $a[1], choose one of enable disable ConvertToWDT:noArg" if($a[1] eq "?");
 
   my $name = shift @a;
   my $v = join(" ", @a);
@@ -61,6 +61,8 @@ sub Heating_Control_Set($@) {
      fhem("attr $name disable 0");
   } elsif ($v eq "disable") {
      fhem("attr $name disable 1");
+  } elsif ($v eq "ConvertToWDT") {
+     Heating_Control_ConvertToWDT();
   }
   return undef;
 }
@@ -71,7 +73,7 @@ sub Heating_Control_Get($@) {
 ########################################################################
 sub Heating_Control_Define($$){
   my ($hash, $def) = @_;
-
+  Log3 $hash, 3, "Heating_Control is deprecated, use WeekdayTimer instead!";
   my $ret = WeekdayTimer_Define($hash, $def);
   return $ret;
 }
@@ -122,21 +124,46 @@ sub Heating_Control_SetAllTemps() {  # {Heating_Control_SetAllTemps()}
   Log3 undef,  3, "Heating_Control_SetAllTemps() done on: ".join(" ",@hcNamen );
 }
 
+########################################################################
+sub Heating_Control_ConvertToWDT() {  
+  my @hcNamen = sort keys %{$modules{Heating_Control}{defptr}};
+  foreach my $hcName ( @hcNamen ) {
+    my $hash = $defs{$hcName};
+    my $definition = $defs{$hcName}{DEF};
+    my $windows = AttrVal($hcName,"windowSensor",undef);
+    my @a = GetDefAndAttr($hcName);
+    shift @a; shift @a; #delete define and uuid
+    my @b = GetAllReadings($hcName);
+    CommandDelete(undef,$hcName);
+    CommandDefine(undef,"$hcName WeekdayTimer $definition");
+    CommandAttr(undef, "$hcName WDT_delayedExecutionDevices $windows");
+    CommandAttr(undef, "$hcName WDT_Group former_HC");
+    foreach my $linesa  ( @a ){
+       AnalyzeCommand(undef, "$linesa") unless ($linesa =~ m/^attr $hcName windowSensor/);
+    }
+    foreach my $linesb  ( @b ){
+       AnalyzeCommand(undef, "$linesb");
+    }
+  }
+  Log3 undef,  3, "Heating_Control_ConvertToWDT() done on: ".join(" ",@hcNamen );
+}
+
 1;
 
 =pod
 =item device
-=item summary    sends heating commands to heating at defined times
-=item summary_DE sendet Temperaturwerte zu festgelegen Zeiten an eine Heizung
+=item summary sends heating commands to heating at defined times - deprecated module!
+=item summary_DE - nicht mehr supportetes Modul, bitte stattdessen WeekdayTimer nutzen!
 =begin html
 
 <a name="Heating_Control"></a>
 <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
 <h3>Heating Control</h3>
 <ul>
-  <br>
+<b>Important Note:</b>  
+  <br>Heating Control is deprecated, as WeekdayTimer offers same functionality at identical syntax. To convert your Heating_Control devices to WeekdayTimer, issue a     <code>set &lt;name&gt; ConvertToWDT</code> to one of them. The WeekdayTimer devices will have the same names, all former HC devices will be in a WDT_Group called former_HC, so they can be switched together. Instead of Heating_Control_SetTemp("HC-device") or Heating_Control_SetAllTemps() use <code>set &lt;name&gt; WDT_Params single</code> or <code>set &lt;name&gt; WDT_Params WDT_Group</code>. For Perl commands, WeekdayTimer offers WeekdayTimer_SetParm("WD-device"), WeekdayTimer_SetAllParms() or WeekdayTimer_SetAllParms("former_HC") (former_HC might also be any other group you want to set).  <br><br>
   <a name="Heating_Controldefine"></a>
-  <b>Define</b>
+    <b>Define</b>
   <ul>
     <code>define &lt;name&gt; Heating_Control &lt;device&gt; [&lt;language&gt;] [<u>weekdays</u>] &lt;profile&gt; [&lt;command&gt;|&lt;condition&gt;]</code>
     <br><br>
@@ -363,7 +390,8 @@ sub Heating_Control_SetAllTemps() {  # {Heating_Control_SetAllTemps()}
 <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
 <h3>Heating Control</h3>
 <ul>
-  <br>
+<br><b>Achtung:</b>  
+  <br>Heating Control wird nicht weiter gepflegt ("deprecated"). WeekdayTimer bietet identische Funktionalität, bei (annähernd) gleicher Syntax. Um alle Heating_Control Devices zu WeekdayTimer umzustellen, genügt ein <code>set &lt;name&gt; ConvertToWDT</code>, wobei als &lt;name&gt; ein beliebiges Heating_Control device angegeben werden kann. Die WeekdayTimer werden mit denselben Namen erstellt, alle früheren HC Geräte erhalten ein WDT_Group-Attribut mit Inhalt former_HC, so dass sie auch in Zukunft miteinander geschalten werden können. Statt des Aufrufs Heating_Control_SetTemp("HC-device") bzw. Heating_Control_SetAllTemps() steht Ihnen <code>set &lt;name&gt; WDT_Params single</code> oder <code>set &lt;name&gt; WDT_Params WDT_Group</code> zur Verfügung, sowie WeekdayTimer_SetParm("WD-device"), WeekdayTimer_SetAllParms() bzw. WeekdayTimer_SetAllParms("former_HC"), wenn Sie Perl nutzen möchten (former_HC ist hier nur ein Beispiel, es können beliebige Gruppennamen verwendet werden.  <br><br>
   <a name="Heating_Controldefine"></a>
   <b>Define</b>
   <ul>
diff --git a/fhem/FHEM/98_WeekdayTimer.pm b/fhem/FHEM/98_WeekdayTimer.pm
index 29bf90ff9..dc8c61464 100644
--- a/fhem/FHEM/98_WeekdayTimer.pm
+++ b/fhem/FHEM/98_WeekdayTimer.pm
@@ -44,7 +44,7 @@ sub WeekdayTimer_Initialize($){
   $hash->{GetFn}   = "WeekdayTimer_Get";
   $hash->{AttrFn}  = "WeekdayTimer_Attr";
   $hash->{UpdFn}   = "WeekdayTimer_Update";
-  $hash->{AttrList}= "disable:0,1 delayedExecutionCond switchInThePast:0,1 commandTemplate ".
+  $hash->{AttrList}= "disable:0,1 delayedExecutionCond WDT_delayedExecutionDevices WDT_Group switchInThePast:0,1 commandTemplate ".
      $readingFnAttributes;
 }
 ################################################################################
@@ -102,17 +102,32 @@ sub WeekdayTimer_Set($@) {
   my ($hash, @a) = @_;
 
   return "no set value specified" if(int(@a) < 2);
-  return "Unknown argument $a[1], choose one of enable disable " if($a[1] eq "?");
+  return "Unknown argument $a[1], choose one of enable disable WDT_Params:single,WDT_Group,all" if($a[1] eq "?");
 
   my $name = shift @a;
   my $v = join(" ", @a);
 
-  Log3 $hash, 3, "[$name] set $name $v";
-
-  if      ($v eq "enable") {
-     fhem("attr $name disable 0");
+  if ($v eq "enable") {
+    Log3 ($hash, 3, "[$name] set $name $v");
+    CommandAttr(undef, "$name disable 0");
   } elsif ($v eq "disable") {
-     fhem("attr $name disable 1");
+    Log3 $hash, 3, "[$name] set $name $v";
+     CommandAttr(undef, "$name disable 1");
+  } elsif ($v =~ m/WDT_Params/) {
+    if ($v =~ /single/) {
+      WeekdayTimer_SetParm($name);
+      Log3 ($hash, 4, "[$name] set $name $v called");
+    } elsif ($v =~ /WDT_Group/) {
+      my $group = AttrVal($hash->{NAME},"WDT_Group",undef);
+      unless (defined $group ){
+         Log3 $hash, 3, "[$name] set $name $v cancelled: group attribute not set for $name!";
+      } else {
+         WeekdayTimer_SetAllParms($group);
+      }
+    } elsif ($v =~ /all/){
+      WeekdayTimer_SetAllParms("all");
+      Log3 $hash,3, "[$name] set $name $v called; params in all WeekdayTimer instances will be set!";
+    }
   }
   return undef;
 }
@@ -467,7 +482,7 @@ sub WeekdayTimer_gatherSwitchingTimes {
     #pruefen auf Angabe eines Schaltpunktes
     my $element = "";
     my @restoreElements = ();
-E:  while (@$a > 0) {
+E:    while (@$a > 0) {
 
        my $actualElement = shift @$a;
        push @restoreElements, $actualElement;
@@ -674,6 +689,8 @@ sub WeekdayTimer_SetTimer($) {
 
   }
 }
+########################################################################
+
 ################################################################################
 sub WeekdayTimer_delayedTimerInPast($) {
   my ($myHash) = @_;
@@ -914,7 +931,9 @@ sub WeekdayTimer_FensterOffen ($$$) {
                     "Heating_Control" => { "READING" => "delayedExecution","STATUS" => "^1\$",          "MODEL" => "a" }
                   );
 
-  my $fensterKontakte = AttrVal($hash->{NAME}, "windowSensor", "")." ".$hash->{NAME};
+  my $fensterKontakte = $hash->{NAME} ." ". AttrVal($hash->{NAME}, "WDT_delayedExecutionDevices", "");
+  my $HC_fensterKontakte = AttrVal($hash->{NAME}, "windowSensor", undef);
+  $fensterKontakte .= " ".$HC_fensterKontakte if defined $HC_fensterKontakte;
   $fensterKontakte =~ s/^\s+//;
   $fensterKontakte =~ s/\s+$//;
 
@@ -922,13 +941,14 @@ sub WeekdayTimer_FensterOffen ($$$) {
   if ($fensterKontakte ne "" ) {
      my @kontakte = split("[ \t]+", $fensterKontakte);
      foreach my $fk (@kontakte) {
-        if(!$defs{$fk}) {
-           Log3 $hash, 3, "[$name] sensor <$fk> not found - check name.";
+        #hier flexible eigene Angaben ermöglichen?, Schreibweise: Device[:Reading[:ValueToCompare[:Comparator]]]; defaults: Reading=state, ValueToCompare=0/undef/false, all other true, Comparator=eq (options: eq, ne, lt, gt, ==, <,>,<>)
+        my $fk_hash = $defs{$fk};
+        unless($fk_hash) {
+          Log3 $hash, 3, "[$name] sensor <$fk> not found - check name.";
         } else {
-           my $fk_hash = $defs{$fk};
            my $fk_typ  = $fk_hash->{TYPE};
            if (!defined($contacts{$fk_typ})) {
-              Log3 $hash, 3, "[$name] TYPE '$fk_typ' of $fk not yet supported, $fk ignored - inform maintainer";
+                            Log3 $hash, 3, "[$name] TYPE '$fk_typ' of $fk not yet supported, $fk ignored - inform maintainer";
            } else {
 
               my $reading      = $contacts{$fk_typ}{READING};
@@ -1111,20 +1131,25 @@ sub WeekdayTimer_Attr($$$$) {
 sub WeekdayTimer_SetParm($) {
   my ($name) = @_;
 
-  my $hash = $modules{WeekdayTimer}{defptr}{$name};
+  my $hash = $defs{$name};
   if(defined $hash) {
      WeekdayTimer_DeleteTimer($hash);
      WeekdayTimer_SetTimer($hash);
   }
 }
 ################################################################################
-sub WeekdayTimer_SetAllParms() {            # {WeekdayTimer_SetAllParms()}
-
-  my @wdNamen = sort keys %{$modules{WeekdayTimer}{defptr}};
-  foreach my $wdName ( @wdNamen ) {
+sub WeekdayTimer_SetAllParms(;$) {            # {WeekdayTimer_SetAllParms()}
+  my ($group) = @_; 
+  my @wdtNames;
+  if (!defined $group or $group eq "all") {
+    @wdtNames = devspec2array('TYPE=WeekdayTimer');
+  } else {
+    @wdtNames = devspec2array("TYPE=WeekdayTimer:FILTER=WDT_Group=$group");
+  }
+  foreach my $wdName ( @wdtNames ) {
      WeekdayTimer_SetParm($wdName);
   }
-  Log3 undef,  3, "WeekdayTimer_SetAllParms() done on: ".join(" ",@wdNamen );
+  Log3 undef,  3, "WeekdayTimer_SetAllParms() done on: ".join(" ",@wdtNames );
 }
 
 1;
@@ -1227,10 +1252,11 @@ sub WeekdayTimer_SetAllParms() {            # {WeekdayTimer_SetAllParms()}
         <code>define dimmer WeekdayTimer livingRoom Sa-Su,We|07:00|dim30% Sa-Su,We|21:00|dim90% (ReadingsVal("WeAreThere", "state", "no") eq "yes")</code><br>
         The dimmer is only set to dimXX% if the dummy variable WeAreThere is "yes"(not a real live example).<p>
 
-        If you want to have set all WeekdayTimer their current value (after a temperature lowering phase holidays)
+        If you want to have set all WeekdayTimer their current value (e.g. after a temperature lowering phase holidays)
         you can call the function <b>WeekdayTimer_SetParm("WD-device")</b> or <b>WeekdayTimer_SetAllParms()</b>.<br>
+        To limit the affected WeekdayTimer devices to a subset of all of your WeekdayTimers, use the WDT_Group attribute and <b>WeekdayTimer_SetAllParms("<group name>")</b>.<br> This offers the same functionality than <code>set wd WDT_Params WDT_Group</code>
         This call can be automatically coupled to a dummy by a notify:<br>
-        <code>define dummyNotify notify Dummy:. * {WeekdayTimer_SetAllTemps()}</code>
+        <code>define dummyNotify notify Dummy:. * {WeekdayTimer_SetAllParms()}</code>
         <br><p>
         Some definitions without comment:
         <code>
@@ -1254,30 +1280,31 @@ sub WeekdayTimer_SetAllParms() {            # {WeekdayTimer_SetAllParms()}
         define wd    Weekdaytimer device de  fr,$we   09:00|19  (function("exit"))
         </code></pre>
     </ul>
-  </ul>
-
+  
   <a name="WeekdayTimerset"></a>
   <b>Set</b>
-
+    <br><br>
     <code><b><font size="+1">set &lt;name&gt; &lt;value&gt;</font></b></code>
     <br><br>
     where <code>value</code> is one of:<br>
     <pre>
     <b>disable</b>               # disables the Weekday_Timer
     <b>enable</b>                # enables  the Weekday_Timer
-    </pre>
-
-    <b><font size="+1">Examples</font></b>:
+    <b>WDT_Params [one of: single, WDT_Group or all]</b></pre>
+    <br>
+    <b>Examples</b>:
     <ul>
       <code>set wd disable</code><br>
       <code>set wd enable</code><br>
+      <code>set wd WDT_Params WDT_Group</code><br>
+    </ul>
+    <ul>
+    The WDT_Params function can be used to reapply the current switching value to the device, all WDT devices with identical WDT_Group attribute or all WeekdayTimer devices; delay conditions will be obeyed, for non-heating type devices, switchInThePast has to be set.
     </ul>
-  </ul>
-
   <a name="WeekdayTimerget"></a>
   <b>Get</b> <ul>N/A</ul><br>
 
-  <a name="WeekdayTimerLogattr"></a>
+  <a name="WeekdayTimerattr"></a>
   <b>Attributes</b>
   <ul>
     <li>delayedExecutionCond <br>
@@ -1286,15 +1313,14 @@ sub WeekdayTimer_SetAllParms() {            # {WeekdayTimer_SetAllParms()}
     <br><br>
     <b>Example:</b>
     <pre>
-    attr wd delayedExecutionCond isDelayed("$HEATING_CONTROL","$WEEKDAYTIMER","$TIME","$NAME","$EVENT")
+    attr wd delayedExecutionCond isDelayed("$WEEKDAYTIMER","$TIME","$NAME","$EVENT")
     </pre>
     the parameter $WEEKDAYTIMER(timer name) $TIME $NAME(device name) $EVENT are replaced at runtime by the correct value.
-
     <br><br>
     <b>Example of a function:</b>
     <pre>
-    sub isDelayed($$$$$) {
-       my($hc, $wdt, $tim, $nam, $event ) = @_;
+    sub isDelayed($$$$) {
+       my($wdt, $tim, $nam, $event ) = @_;
 
        my $theSunIsStillshining = ...
 
@@ -1302,6 +1328,12 @@ sub WeekdayTimer_SetAllParms() {            # {WeekdayTimer_SetAllParms()}
     }
     </pre>
     </li>
+    <li>WDT_delayedExecutionDevices<br>
+    Defines a space separated list devices (atm only window sensors are supported). When one of its state readings is <b>open</b> the aktual switch is delayed.</li><br>
+    <br>
+    <li>WDT_Group<br>
+    Used to generate groups of WeekdayTimer devices to be switched together in case one of them is set to WDT_Params with the WDT_Group modifier, e.g. <code>set wd WDT_Params WDT_Group</code>.<br>This is intended to allow former Heating_Control devices to be migrated to WeekdayTimer and replaces the Heating_Control_SetAllTemps() functionality.</li><br>
+
     <li>switchInThePast<br>
     defines that the depending device will be switched in the past in definition and startup phase when the device is not recognized as a heating.
     Heatings are always switched in the past.
@@ -1312,7 +1344,10 @@ sub WeekdayTimer_SetAllParms() {            # {WeekdayTimer_SetAllParms()}
     <li><a href="#event-on-update-reading">event-on-update-reading</a></li>
     <li><a href="#event-on-change-reading">event-on-change-reading</a></li>
     <li><a href="#stateFormat">stateFormat</a></li>
-  </ul><br>
+  <br>
+  </ul>
+  </ul>
+</ul>
 
 =end html