From 5814683d6f7efa8cb7e65d40aa774cc97e8bdd11 Mon Sep 17 00:00:00 2001 From: jamesgo <> Date: Sun, 8 Nov 2015 09:12:39 +0000 Subject: [PATCH] 93_PWMR.pm : restructured readings git-svn-id: https://svn.fhem.de/fhem/trunk@9817 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/contrib/93_PWMR.pm | 151 ++++++++++++++++++++++++++-------------- fhem/contrib/94_PWM.pm | 74 +++++++++++++------- 2 files changed, 147 insertions(+), 78 deletions(-) diff --git a/fhem/contrib/93_PWMR.pm b/fhem/contrib/93_PWMR.pm index 4b71622f1..749cc71fe 100644 --- a/fhem/contrib/93_PWMR.pm +++ b/fhem/contrib/93_PWMR.pm @@ -13,6 +13,9 @@ # 13.10.15 GA add event-on-change-reading # 14.10.15 GA fix round energyusedp # 15.10.15 GA add a_regexp_on, a regular expression for the on state of the actor +# 05.11.15 GA fix new reading desired-temp-until which substitutes modification date of desired-temp in the future +# events for desired-temp adjusted (no update of timestamp if temperature stays the same) + # module for PWM (Pulse Width Modulation) calculation # this module defines a room for calculation @@ -107,10 +110,8 @@ PWMR_CalcDesiredTemp($) { my ($hash) = @_; - $hash->{STATE} = "Calculating"; - if($hash->{INTERVAL} > 0) { - if ($hash->{INTERVAL} eq 300) { + if ($hash->{INTERVAL} == 300) { # align interval to hh:00:ss, hh:05:ss, ... hh:55:ss my $n = gettimeofday(); @@ -129,21 +130,44 @@ PWMR_CalcDesiredTemp($) } my $name = $hash->{NAME}; - if ($hash->{READINGS}{"desired-temp"}{TIME} gt TimeNow()) { - Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: desired-temp was manualy set until ". - $hash->{READINGS}{"desired-temp"}{TIME}); - $hash->{STATE} = "ManualSetUntil"; - return undef; - } else { - Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: calc desired-temp"); + if (defined($hash->{READINGS}{"desired-temp-until"})) { + if ($hash->{READINGS}{"desired-temp-until"}{VAL} ne "no" ) { + + if ($hash->{READINGS}{"desired-temp-until"}{VAL} gt TimeNow()) { + + Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: desired-temp was manualy set until ". + $hash->{READINGS}{"desired-temp"}{TIME}); + $hash->{STATE} = "ManualSetUntil"; + return undef; + } + else + { + readingsSingleUpdate ($hash, "desired-temp-until", "no", 1); + Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: calc desired-temp"); + } + } } + #if ($hash->{READINGS}{"desired-temp"}{TIME} gt TimeNow()) { + # Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: desired-temp was manualy set until ". + # $hash->{READINGS}{"desired-temp"}{TIME}); + # + # $hash->{STATE} = "ManualSetUntil"; + # return undef; + #} else { + # Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: calc desired-temp"); + #} + #################### # frost protection if ($hash->{c_frostProtect} > 0) { - readingsSingleUpdate ($hash, "desired-temp", $hash->{c_tempFrostProtect}, 1); + if ($hash->{READINGS}{"desired-temp"}{VAL} ne $hash->{c_tempFrostProtect}) { + readingsSingleUpdate ($hash, "desired-temp", $hash->{c_tempFrostProtect}, 1); + } else { + readingsSingleUpdate ($hash, "desired-temp", $hash->{c_tempFrostProtect}, 0); + } #$hash->{READINGS}{"desired-tem"}{TIME} = TimeNow(); #$hash->{READINGS}{"desired-temp"}{VAL} = $hash->{c_tempFrostProtect}; @@ -160,6 +184,8 @@ PWMR_CalcDesiredTemp($) if ($hash->{c_autoCalcTemp} > 0) { + $hash->{STATE} = "Calculating"; + my @time = localtime(); my $wday = $time[6]; my $cmptime = sprintf ("%02d%02d", $time[2], $time[1]); @@ -202,7 +228,11 @@ PWMR_CalcDesiredTemp($) Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: match i:$i $points[$i] ($tempV/$temperature)"); - readingsSingleUpdate ($hash, "desired-temp", $temperature, 1); + if ($hash->{READINGS}{"desired-temp"}{VAL} ne $temperature) { + readingsSingleUpdate ($hash, "desired-temp", $temperature, 1); + } else { + readingsSingleUpdate ($hash, "desired-temp", $temperature, 0); + } #$hash->{READINGS}{"desired-temp"}{TIME} = TimeNow(); #$hash->{READINGS}{"desired-temp"}{VAL} = $temperature; @@ -221,7 +251,11 @@ PWMR_CalcDesiredTemp($) my $act_dtemp = $hash->{READINGS}{"desired-temp"}{VAL}; Log3 ($hash, 4, "PWMR_CalcDesiredTemp $name: use last value ($act_dtemp)"); - readingsSingleUpdate ($hash, "desired-temp", $newTemp, 1); + if ($act_dtemp ne $newTemp) { + readingsSingleUpdate ($hash, "desired-temp", $newTemp, 1); + #} else { + # readingsSingleUpdate ($hash, "desired-temp", $newTemp, 0); + } #$hash->{READINGS}{"desired-temp"}{TIME} = TimeNow(); #$hash->{READINGS}{"desired-temp"}{VAL} = $newTemp; @@ -237,7 +271,7 @@ PWMR_CalcDesiredTemp($) $hash->{STATE} = "Manual"; } - DoTrigger($name, undef); + #DoTrigger($name, undef); return undef; } @@ -289,7 +323,7 @@ PWMR_Set($@) # manualTempDuration if ( $cmd eq "manualTempDuration" ) { - readingsSingleUpdate ($hash, "manualTempDuration", $a[2], 0); + readingsSingleUpdate ($hash, "manualTempDuration", $a[2], 1); #$hash->{READINGS}{"manualTempDuration"}{VAL} = $a[2]; #$hash->{READINGS}{"manualTempDuration"}{TIME} = TimeNow(); @@ -311,18 +345,29 @@ PWMR_Set($@) $duration = int($a[3]) * 60; } - #$hash->{READINGS}{$cmd}{TIME} = TimeNow(); - # manual set desired-temp will be set for 1 hour (default) # afterwards it will be overwritten by auto calc my $now = time(); - $hash->{READINGS}{$cmd}{TIME} = FmtDateTime($now + $duration); - $hash->{READINGS}{$cmd}{VAL} = $val; + readingsBeginUpdate ($hash); + readingsBulkUpdate ($hash, "desired-temp", $a[2]); + if ($hash->{c_autoCalcTemp} == 0) { + $hash->{STATE} = "Manual"; + } else { + $hash->{STATE} = "ManualSetUntil"; + readingsBulkUpdate ($hash, "desired-temp-until", FmtDateTime($now + $duration)); + } + readingsEndUpdate($hash, 1); + + #readingsSingleUpdate ($hash, "desired-temp", $a[2], 1); - $hash->{STATE} = "ManualSetUntil"; + #$hash->{READINGS}{$cmd}{TIME} = FmtDateTime($now + $duration); + #$hash->{READINGS}{$cmd}{VAL} = $val; + + #push @{$hash->{CHANGED}}, "$cmd: $val"; + #DoTrigger($hash, undef); return undef } @@ -526,27 +571,26 @@ PWMR_SetRoom(@) Log3 ($room, 4, "PWMR_SetRoom $name <$newState>"); - my $nowR = TimeNow(); - my $now = time(); - - $room->{READINGS}{energyused}{TIME} = $nowR; - $room->{READINGS}{energyusedp}{TIME} = $nowR; - if (!defined($room->{READINGS}{energyused}{VAL})) { - $room->{READINGS}{energyused}{VAL} = ""; + my $energyused = ""; + if (defined($room->{READINGS}{energyused}{VAL})) { + $energyused = substr ( $room->{READINGS}{energyused}{VAL}, -29); } - - my $energyused = substr ( $room->{READINGS}{energyused}{VAL}, -29); + # newState may be "", "on", "off" if ($newState eq "") { $energyused = $energyused.substr ( $energyused ,-1); } else { $energyused = $energyused.($newState eq "on" ? "1" : "0"); } - $room->{READINGS}{energyused}{VAL} = $energyused; - $room->{READINGS}{energyusedp}{VAL} = sprintf ("%.2f", ($energyused =~ tr/1//) /30); + + readingsBeginUpdate ($room); + readingsBulkUpdate ($room, "energyused", $energyused); + readingsBulkUpdate ($room, "energyusedp", sprintf ("%.2f", ($energyused =~ tr/1//) /30)); + readingsEndUpdate($room, 0); - - return if ($newState eq ""); + if ($newState eq "") { + return; + } if ($room->{actor}) { @@ -555,12 +599,8 @@ PWMR_SetRoom(@) Log3 ($room, 2, "PWMR_SetRoom $room->{NAME}: set $room->{actor} $newState"); $room->{actorState} = $newState; + readingsSingleUpdate ($room, "lastswitch", time(), 1); - $room->{READINGS}{lastswitch}{TIME} = $nowR; - $room->{READINGS}{lastswitch}{VAL} = $now; - - push @{$room->{CHANGED}}, "actor $newState"; - DoTrigger($name, undef); } else { Log3 ($room, 2, "PWMR_SetRoom $name: set $room->{actor} $newState failed ($ret)"); } @@ -630,20 +670,17 @@ PWMR_ReadRoom(@) if (!$room->{READINGS}{"desired-temp"}{TIME}) { - $room->{READINGS}{"desired-temp"}{VAL} = 6.0; - $room->{READINGS}{"desired-temp"}{TIME} = TimeNow(); + readingsSingleUpdate ($room, "desired-temp", 6.0, 0); } if (!$room->{READINGS}{oldpulse}{TIME}) { - $room->{READINGS}{oldpulse}{VAL} = 0.0; - $room->{READINGS}{oldpulse}{TIME} = TimeNow(); + readingsSingleUpdate ($room, "oldpulse", 0.0, 0); } if (!$room->{READINGS}{lastswitch}{TIME}) { - $room->{READINGS}{lastswitch}{VAL} = time(); - $room->{READINGS}{lastswitch}{TIME} = TimeNow(); + readingsSingleUpdate ($room, "lastswitch", time(), 0); } $factor = $room->{FACTOR}; @@ -850,6 +887,7 @@ PWMR_Attr(@) $hash->{c_frostProtect} = 0; } elsif ($attr eq "autoCalcTemp") { $hash->{c_autoCalcTemp} = 1; + $hash->{STATE} = "Calculating"; } } @@ -871,10 +909,15 @@ PWMR_Attr(@) } } elsif ($attr eq "autoCalcTemp") { # autoCalcTemp 0/1 - if ($val eq 0 or $val eq 1) { - $hash->{c_autoCalcTemp} = $val; + if ($val eq 0) { + $hash->{c_autoCalcTemp} = 0; + $hash->{STATE} = "Manual"; + } elsif ( $val eq 1) { + $hash->{c_autoCalcTemp} = 1; + $hash->{STATE} = "Calculating"; } elsif ($val eq "") { $hash->{c_autoCalcTemp} = 1; + $hash->{STATE} = "Calculating"; } else { return "valid values are 0 or 1"; } @@ -947,12 +990,18 @@ PWMR_Boost(@) "temp($temperaturV) desired-temp($desiredTemp) -> boost"); my $now = time(); - $room->{READINGS}{"desired-temp"}{TIME} = FmtDateTime($now + $boostDuration * 60); - $room->{READINGS}{"desired-temp"}{VAL} = $desiredTemp + $desiredOffset; - my $t = $room->{READINGS}{"desired-temp"}{VAL}; - push @{$room->{CHANGED}}, "desired-temp $t"; - DoTrigger($name, undef); + readingsBeginUpdate ($room); + readingsBulkUpdate ($room, "desired-temp", $desiredTemp + $desiredOffset); + readingsBulkUpdate ($room, "desired-temp-until", FmtDateTime($now + $boostDuration * 60)); + readingsEndUpdate($room, 1); + + #$room->{READINGS}{"desired-temp"}{TIME} = FmtDateTime($now + $boostDuration * 60); + #$room->{READINGS}{"desired-temp"}{VAL} = $desiredTemp + $desiredOffset; + + #my $t = $room->{READINGS}{"desired-temp"}{VAL}; + #push @{$room->{CHANGED}}, "desired-temp $t"; + #DoTrigger($name, undef); Log3 ($room, 4, "PWMR_Boost: $name ". "set desiredtemp ".$room->{READINGS}{"desired-temp"}{TIME}." ". diff --git a/fhem/contrib/94_PWM.pm b/fhem/contrib/94_PWM.pm index a82debd36..4e7939bdc 100644 --- a/fhem/contrib/94_PWM.pm +++ b/fhem/contrib/94_PWM.pm @@ -6,6 +6,10 @@ # # 21.09.15 GA update, use Log3 # 07.10.15 GA initial version published +# 13.10.15 GA add event-on-change-reading +# 13.10.15 GA add several readings +# 15.10.15 GA add reading for avg pulses + ############################################## # $Id: @@ -42,7 +46,6 @@ sub PWM_Set($@); sub PWM_Define($$); sub PWM_Calculate($); sub PWM_Undef($$); -sub PWM_State($$$$); sub PWM_CalcRoom(@); my %roomsWaitOffset = (); @@ -57,9 +60,8 @@ PWM_Initialize($) $hash->{SetFn} = "PWM_Set"; $hash->{DefFn} = "PWM_Define"; $hash->{UndefFn} = "PWM_Undef"; - #$hash->{StateFn} = "PWM_State"; - $hash->{AttrList} = ""; + $hash->{AttrList} = "event-on-change-reading"; } @@ -77,6 +79,7 @@ PWM_Calculate($) my %RoomsPulses = (); my $roomsActive = 0; my $newpulseSum = 0; + my $newpulseMax = 0; my $wkey = ""; if($hash->{INTERVAL} > 0) { @@ -85,9 +88,11 @@ PWM_Calculate($) Log3 ($hash, 3, "PWM_Calculate $name"); + readingsBeginUpdate ($hash); + #$hash->{STATE} = "lastrun: ".TimeNow(); #$hash->{STATE} = "calculating"; - readingsSingleUpdate ($hash, "lastrun", "calculating", 1); + readingsBulkUpdate ($hash, "lastrun", "calculating"); $hash->{STATE} = "lastrun: ".$hash->{READINGS}{lastrun}{TIME}; # loop over all devices @@ -127,6 +132,7 @@ PWM_Calculate($) $roomsActive++; $RoomsPulses{$d} = $newpulse; $newpulseSum += $newpulse; + $newpulseMax = max($newpulseMax, $newpulse); # $newstate ne "" -> state changed "on" -> "off" or "off" -> "on" if ((int($hash->{MINONOFFTIME}) > 0) && @@ -263,7 +269,6 @@ PWM_Calculate($) #my $maxRoomsOn = $roomsActive * 0.6; # 11 rooms -> max 6 active #$maxRoomsOn = (8 * 0.7) if ($roomsActive < 8); - # HERE my $maxRoomsOn = $roomsActive - $hash->{NoRoomsToStayOff}; # @@ -309,8 +314,8 @@ PWM_Calculate($) # $minRoomsOn = 0; #} - # HERE my $minRoomsOn = $hash->{NoRoomsToStayOn}; + my $minRoomsOnList = ""; if ($minRoomsOn > 0) { @@ -322,9 +327,11 @@ PWM_Calculate($) last if ($roomsCounted == $minRoomsOn); Log3 ($hash, 3, "PWM_Calculate: loop $roomsCounted $room $RoomsPulses{$room}"); + $minRoomsOnList .= "$room,"; $pulseSum += $RoomsPulses{$room}; $roomsCounted++; } + $minRoomsOnList =~ s/,$//; #if ($roomsActive == 0 or $hash->{NoRoomsToStayOnThreshold} == 0 or $newpulseSum/$roomsActive < $hash->{NoRoomsToStayOnThreshold}) { @@ -369,22 +376,36 @@ PWM_Calculate($) # # now process the calculated actions # - + + my $cntRoomsOn = 0; + my $cntRoomsOff = 0; + my $pulseRoomsOn = 0; + my $pulseRoomsOff = 0; + foreach my $roomStay (sort keys %RoomsToStayOff) { PWMR_SetRoom ($defs{$roomStay}, ""); + $cntRoomsOff++; + $pulseRoomsOff += $RoomsPulses{$roomStay}; + } foreach my $roomStay (sort keys %RoomsToStayOn) { PWMR_SetRoom ($defs{$roomStay}, ""); + $cntRoomsOn++; + $pulseRoomsOn += $RoomsPulses{$roomStay}; + } foreach my $roomOff (sort keys %RoomsToSwitchOff) { PWMR_SetRoom ($defs{$roomOff}, "off"); + + $cntRoomsOff++; + $pulseRoomsOff += $RoomsPulses{$roomOff}; } foreach my $roomOn (sort keys %RoomsToSwitchOn) { @@ -393,7 +414,26 @@ PWM_Calculate($) $roomsWaitOffset{$wkey} = 0; PWMR_SetRoom ($defs{$roomOn}, "on"); + $cntRoomsOn++; + $pulseRoomsOn += $RoomsPulses{$roomOn}; + } + + + readingsBulkUpdate ($hash, "roomsActive", $roomsActive); + readingsBulkUpdate ($hash, "roomsOn", $cntRoomsOn); + readingsBulkUpdate ($hash, "roomsOff", $cntRoomsOff); + readingsBulkUpdate ($hash, "avgPulseRoomsOn", ($cntRoomsOn > 0 ? sprintf ("%.2f", $pulseRoomsOn / $cntRoomsOn) : 0)); + readingsBulkUpdate ($hash, "avgPulseRoomsOff", ($cntRoomsOff > 0 ? sprintf ("%.2f", $pulseRoomsOff /$cntRoomsOff) : 0)); + readingsBulkUpdate ($hash, "pulseMax", $newpulseMax); + readingsBulkUpdate ($hash, "pulseSum", $newpulseSum); + + if ( $hash->{NoRoomsToStayOn} > 0) { + readingsBulkUpdate ($hash, "roomsToStayOn", $minRoomsOn); + readingsBulkUpdate ($hash, "roomsToStayOnList", $minRoomsOnList); + } + + readingsEndUpdate($hash, 1); # if(!$hash->{LOCAL}) { # DoTrigger($name, undef) if($init_done); @@ -662,26 +702,6 @@ sub PWM_Undef($$) return undef; -} -################################### -sub PWM_State($$$$) -{ - my ($hash, $time, $var, $value) = @_; - - my $name = $hash->{NAME}; - Log3 ($hash, 3, "PWM States $name: $time $var $value"); - - $hash->{READINGS}{$var}{VAL} = $value; - $hash->{READINGS}{$var}{TIME} = $time; - - #if ($var =~ /INTERVAL|SCOPE|CYCLETIME/) - #{ - # Log3 ($hash, 3, "PWM States $name: set $var $value"); - # $hash->{$var} = $value; - #} - - return undef; - } 1;