From 68978a386b4b7267c1a0cdaa57d68333202deda0 Mon Sep 17 00:00:00 2001 From: jamesgo Date: Thu, 11 Mar 2021 16:19:07 +0000 Subject: [PATCH] 94_PWM.pm : add maxOffTimeMode and some small fixes git-svn-id: https://svn.fhem.de/fhem/trunk@23926 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/94_PWM.pm | 165 +++++++++++++++++++++++++++----------------- 1 file changed, 102 insertions(+), 63 deletions(-) diff --git a/fhem/FHEM/94_PWM.pm b/fhem/FHEM/94_PWM.pm index 459abf901..589e78f6b 100644 --- a/fhem/FHEM/94_PWM.pm +++ b/fhem/FHEM/94_PWM.pm @@ -38,6 +38,9 @@ # 26.05.20 GA fix division by zero if minRoomsOn is >0 and roomsCounted is zero # 22.12.20 GA fix maxOffTime for P calculation never activated # 28.12.20 GA fix maxOffTime; maxOffTimeApply is now only set if no heating is required +# 31.01.21 GA add attribute maxOffTimeMode (max, 1, 2, 3) +# 01.02.21 GA fix move reading maxOffTimeCalculation into an attribute and internal values +# 11.03.21 GA fix prevent parallel InternalTimer calls ############################################## # $Id$ @@ -92,7 +95,7 @@ PWM_Initialize($) $hash->{AttrFn} = "PWM_Attr"; $hash->{AttrList} = "disable:1,0 valveProtectIdlePeriod overallHeatingSwitchRef:pulseMax,pulseSum,pulseAvg,pulseAvg2,pulseAvg3,avgPulseRoomsOn". - " overallHeatingSwitchThresholdTemp ".$readingFnAttributes; + " overallHeatingSwitchThresholdTemp maxOffTimeCalculation:on,off maxOffTimeMode:max,1,2,3 ".$readingFnAttributes; #$hash->{GetList} = "status timers"; @@ -105,24 +108,27 @@ PWM_Calculate($) my ($hash) = @_; my $name = $hash->{NAME}; - my %RoomsToSwitchOn = (); - my %RoomsToSwitchOff = (); - my %RoomsToStayOn = (); - my %RoomsToStayOff = (); - my %RoomsValveProtect = (); - my %RoomsMaxOffTimeProtect = (); - my %RoomsPulses = (); - my $roomsActive = 0; - my $newpulseMax = 0; - my $newpulseSum = 0; - my $newpulseAvg = 0; - my $newpulseAvg2 = 0; - my $newpulseAvg3 = 0; - my $RoomsMaxOffTimeProtect_on = 0; + my %RoomsToSwitchOn = (); + my %RoomsToSwitchOff = (); + my %RoomsToStayOn = (); + my %RoomsToStayOff = (); + my %RoomsValveProtect = (); + my %RoomsMaxOffTimeProtect = (); + my %RoomsPulses = (); + my $roomsActive = 0; + my $newpulseMax = 0; + my $newpulseSum = 0; + my $newpulseAvg = 0; + my $newpulseAvg2 = 0; + my $newpulseAvg3 = 0; + my $RoomsMaxOffTimeProtect_on = 0; + my $RoomsMaxOffTimeProtect_off = 0; + my $RoomsMaxOffTimeProtect_stay_on = 0; my $wkey = ""; if($hash->{INTERVAL} > 0) { + RemoveInternalTimer($hash, "PWM_Calculate"); InternalTimer(gettimeofday() + $hash->{INTERVAL}, "PWM_Calculate", $hash, 0); } @@ -143,6 +149,16 @@ PWM_Calculate($) readingsBulkUpdate ($hash, "lastrun", "calculating"); readingsBulkUpdate ($hash, "state", "lastrun: ".$hash->{READINGS}{lastrun}{TIME}); + # migrate reading maxOffTimeCalculate to attribute, added 01.02.2021, will be deleted later + if (defined($hash->{READINGS}{maxOffTimeCalculation})) { + $hash->{c_maxOffTimeCalculation} = $hash->{READINGS}{maxOffTimeCalculation}{VAL}; + $attr{$name}{maxOffTimeCalculation} = $hash->{READINGS}{maxOffTimeCalculation}{VAL}; + + $hash->{c_maxOffTimeMode} = 999 unless defined ($hash->{c_maxOffTimeMode}); + + delete($hash->{READINGS}{maxOffTimeCalculation}); + } + # loop over all devices # fetch all PWMR devices # which are not disabled @@ -177,7 +193,7 @@ PWM_Calculate($) $RoomsValveProtect{$d} = "on"; } elsif ($newstate eq "off_vp") { $RoomsValveProtect{$d} = "off"; - } else { + } elsif ($newstate =~ /mop/) { ############################## ##### maxOffTimeProtect @@ -187,17 +203,19 @@ PWM_Calculate($) $RoomsMaxOffTimeProtect{$d} = $newstate; $newstate = "on"; } elsif ($newstate eq "on_mop_stay") { - $RoomsMaxOffTimeProtect_on++; + $RoomsMaxOffTimeProtect_stay_on++; $RoomsMaxOffTimeProtect{$d} = $newstate; $newstate = ""; } elsif ($newstate eq "on_mop_maybe") { $RoomsMaxOffTimeProtect{$d} = $newstate; $newstate = ""; } elsif ($newstate eq "off_mop") { + $RoomsMaxOffTimeProtect_off++; $RoomsMaxOffTimeProtect{$d} = $newstate; $newstate = "off"; } + } else { ############################## ##### regular calculation @@ -266,15 +284,30 @@ PWM_Calculate($) # maxOffTimeProtect handling - foreach my $d (keys %RoomsMaxOffTimeProtect) { + my $maxOffTimeCnt = $RoomsMaxOffTimeProtect_stay_on; + my $maxOffTimeMode = $hash->{c_maxOffTimeMode}; + + if (defined($hash->{c_maxOffTimeCalculation}) and ($hash->{c_maxOffTimeCalculation} eq "on")) { + Log3 ($hash, 3, "PWM_Calculate $name: checkpoint maxOffTime (param $maxOffTimeMode) (cur $maxOffTimeCnt)"); + } + + foreach my $d (sort keys %RoomsMaxOffTimeProtect) { # sort: off_mop; on_mop; on_mop_maybe; on_mop_stay if ($RoomsMaxOffTimeProtect{$d} eq "off_mop") { $RoomsToSwitchOff{$d} = 1; $RoomsPulses{$d} = 0; } elsif ($RoomsMaxOffTimeProtect{$d} eq "on_mop") { - $RoomsToSwitchOn{$d} = 1; - $RoomsPulses{$d} = $hash->{MaxPulse}; + + if ($maxOffTimeCnt < int($maxOffTimeMode)) { + $RoomsToSwitchOn{$d} = 1; + $RoomsPulses{$d} = $hash->{MaxPulse}; + $maxOffTimeCnt++; + } else { + Log3 ($hash, 3, "PWM_Calculate $defs{$d}->{NAME}: F19 maxOffTime protection stay off (Max $maxOffTimeMode)"); + $RoomsToStayOff{$d} = 1; + $RoomsPulses{$d} = 0; + } } elsif ($RoomsMaxOffTimeProtect{$d} eq "on_mop_stay") { $RoomsToStayOn{$d} = 1; @@ -282,9 +315,13 @@ PWM_Calculate($) } elsif ($RoomsMaxOffTimeProtect{$d} eq "on_mop_maybe") { - if ($RoomsMaxOffTimeProtect_on > 0) { + # on_mop_maybe may only be set if c_maxOffTimeMode > 1 + if (($RoomsMaxOffTimeProtect_on + $RoomsMaxOffTimeProtect_stay_on > 0) + and ($maxOffTimeCnt < int($maxOffTimeMode))) { + Log3 ($hash, 3, "PWM_Calculate $defs{$d}->{NAME}: F20 maxOffTime protection pulled on with another room"); $RoomsToSwitchOn{$d} = 1; $RoomsPulses{$d} = $hash->{MaxPulse}; + $maxOffTimeCnt++; } else { $RoomsToStayOff{$d} = 1; @@ -382,14 +419,6 @@ PWM_Calculate($) my $roomsOn = (scalar keys %RoomsToStayOn) - (scalar keys %RoomsToSwitchOff); - # treat less than 8 active rooms as 8 (more can get active) - # 16.01.2015 - #my $maxRoomsOn = $roomsActive * 0.7; - - # 23.09.2015 - #my $maxRoomsOn = $roomsActive * 0.6; # 11 rooms -> max 6 active - #$maxRoomsOn = (8 * 0.7) if ($roomsActive < 8); - my $maxRoomsOn = $roomsActive - $hash->{NoRoomsToStayOff}; # @@ -551,27 +580,6 @@ PWM_Calculate($) } -if (0) { - foreach my $roomMOP (sort keys %RoomsMaxOffTimeProtect) { - - my $wkey = $name."-".$roomMOP; - $roomsWaitOffset{$wkey} = 0; - - if ( $RoomsMaxOffTimeProtect{$roomMOP} eq "on") { - - PWMR_SetRoom ($defs{$roomMOP}, "on"); - $cntRoomsOn++; - $pulseRoomsOn += $RoomsPulses{$roomMOP}; - - } else { - - PWMR_SetRoom ($defs{$roomMOP}, "off"); - $cntRoomsOff++; - $pulseRoomsOff += $RoomsPulses{$roomMOP}; - } - - } -} foreach my $roomVP (sort keys %RoomsValveProtect) { @@ -776,11 +784,6 @@ if (0) { readingsEndUpdate($hash, 1); Log3 ($hash, 3, "PWM_Calculate $name done"); - -# if(!$hash->{LOCAL}) { -# DoTrigger($name, undef) if($init_done); -# } - } ################################### @@ -907,7 +910,7 @@ PWM_CalcRoom(@) # check if maxOffTime protection is activated (attribute maxOffTimeIdlePeriod is set) # $maxOffTImeApply will only be set if no heating is required - if ($maxOffTimeApply > 0 and ReadingsVal($name, "maxOffTimeCalculation", "off") eq "on") { + if ($maxOffTimeApply > 0 and defined($hash->{c_maxOffTimeCalculation}) and ($hash->{c_maxOffTimeCalculation} eq "on")) { ## wz > 2:00 if ($maxOffTimeAct >= $maxOffTime) { @@ -917,10 +920,12 @@ PWM_CalcRoom(@) } ## wz > 2:00 / 2 - if ($maxOffTimeAct >= $maxOffTime / 2) { + if ($hash->{c_maxOffTimeMode} > 1) { + if ($maxOffTimeAct >= $maxOffTime / 2) { - Log3 ($hash, 3, "PWM_CalcRoom $room->{NAME}: F18 maxOffTime protection (possible)"); - return ("on_mop_maybe", $newpulse, $cycletime, $actorV); + Log3 ($hash, 3, "PWM_CalcRoom $room->{NAME}: F18 maxOffTime protection (possible)"); + return ("on_mop_maybe", $newpulse, $cycletime, $actorV); + } } } @@ -1050,6 +1055,7 @@ PWM_Set($@) { my ($hash, @a) = @_; + my $name = $hash->{NAME}; my $u = "Unknown argument $a[1], choose one of recalc interval cycletime maxOffTimeCalculation:on,off"; @@ -1068,7 +1074,10 @@ PWM_Set($@) } elsif ( $a[1] =~ /^maxOffTimeCalculation$/ ) { - readingsSingleUpdate ($hash, "maxOffTimeCalculation", $a[2], 1); + $hash->{c_maxOffTimeCalculation} = $a[2]; + $attr{$name}{maxOffTimeCalculation} = $a[2]; + + $hash->{c_maxOffTimeMode} = 999 unless defined ($hash->{c_maxOffTimeMode}); } else { @@ -1203,6 +1212,7 @@ PWM_Define($$) #AssignIoPort($hash); if($hash->{INTERVAL} > 0) { + RemoveInternalTimer($hash, "PWM_Calculate"); InternalTimer(gettimeofday() + 10, "PWM_Calculate", $hash, 0); } @@ -1247,6 +1257,13 @@ PWM_Attr(@) delete ($hash->{OverallHeatingSwitchTT_t_regexp} ) if defined ($hash->{OverallHeatingSwitchTT_t_regexp}); delete ($hash->{OverallHeatingSwitchTT_maxTemp} ) if defined ($hash->{OverallHeatingSwitchTT_maxTemp}); delete ($hash->{READINGS}{OverallHeatingSwitchTT_Off} ) if defined ($hash->{READINGS}{OverallHeatingSwitchTT_Off}); + + } elsif ($attrname eq "maxOffTimeCalculation") { + delete ($hash->{c_maxOffTimeCalculation}) if defined ($hash->{c_maxOffTimeCalculation}); + delete ($hash->{c_maxOffTimeMode}) if defined ($hash->{c_maxOffTimeMode}); + + } elsif ($attrname eq "maxOffTimeMode") { + $hash->{c_maxOffTimeMode} = 999; } if (defined $attr{$name}{$attrname}) { @@ -1293,6 +1310,18 @@ PWM_Attr(@) return "$name: invalid value for attribute $attrname ($attrval)"; } + } elsif ($attrname eq "maxOffTimeCalculation") { + $hash->{c_maxOffTimeCalculation} = $attrval; + $hash->{c_maxOffTimeMode} = 999 unless defined ($hash->{c_maxOffTimeMode}); + + } elsif ($attrname eq "maxOffTimeMode") { + if ($attrval eq "max") { + $hash->{c_maxOffTimeMode} = 999; + } else { + $hash->{c_maxOffTimeMode} = $attrval; + } + $hash->{c_maxOffTimeCalculation} = "off" unless defined ($hash->{c_maxOffTimeCalculation}); + } } @@ -1414,8 +1443,8 @@ PWM_Attr(@)
  • maxOffTimeCalculation
    - Defines if parameter maxOffTime for rooms (PWMR objects) is evaluated or not. Possible Values are "on" or "off". Sets reading maxOffTimeCalculation.
    -
  • + Defines whether parameter maxOffTime for rooms (PWMR objects) is evaluated or not. Possible Values are "on" or "off". Sets attribute maxOffTimeCalculation and internal values c_maxOffTimeCalculation and c_maxOffTimeMode.
    +
    @@ -1465,7 +1494,17 @@ PWM_Attr(@) The reading OverallHeatingSwitchTT_Off will be set to 1 if temperature from tsensor prevents overallHeatingSwitch from switching to "on".
    Please be aware that temperatures raising to high will seriously harm your heating system and this parameter should not be used as the only protection feature.
    Using this parameter is on your own risk. Please test your settings very carefully.
    - +
    + +
  • maxOffTimeCalculation
    + Defines whether parameter maxOffTime for rooms (PWMR objects) is evaluated or not. Possible Values are "on" or "off". Sets internal values c_maxOffTimeCalculation and c_maxOffTimeMode.
    +

  • + +
  • maxOffTimeMode
    + Defines the strategy for maxOffTime handling if maxOffTimeCalculation is set. Sets internal value c_maxOffTimeMode.
    + max: try to activate as many rooms as possible. If one room switches to on and a second waited half of his maxOffTime, the second will be switched on as well.
    + 1, 2, 3: defines how many rooms can be switched on at the same time.
    +