hier ein teil eines moduls das ich gerade in arbeit habe. warmwassersteuerung mißt die temperatur und schaltet die ladepumpe ein und aus. zusätzlich kann ein boost relais definiert werden, welches die (bei mir vorhandene) analoge max.temperatur begrenzung übergeht.
weiter wird die temperaturkurve erfaßt, und ein fallender winkel von 1 grad pro minute erkannt, um die pumpe sofort zu starten und einen start-befehl für den kesselbrenner zu triggern.
so kann ich die wasserspeicher-temp auf absolutem minimum einstellen und habe trotzdem genug warmwasser für ausgiebige dusche ohne daß das nachströmende kaltwasser während der entnahme mich einfriert.
alle parameter sind über attr. einstellbar.
sub WarmWasserRegler($){
my $hash = $_[0];
my $name = $hash->{NAME};
#desired-temp aus dummy, based on time schedule
#kurve stark fallend => sofortiger brenner-start
my $now = gettimeofday();
my $zhkWwSollTemp = ReadingsVal($name, "zhkWwSollTemp", 30); #user setting
my $zhkWwTempSensorFhemDev = AttrVal($name, "zhkWwTempSensorFhemDev", "5_15_WarmWasser_EB6F98050000");
my $zhkWwTempSensorReading = AttrVal($name, "zhkWwTempSensorReading", "temperature");
#sensor ignorieren wenn state-age > x seconds
my $zhkWwTempSensorMaxAge = AttrVal($name, "zhkWwTempSensorMaxAge", 30);
my $zhkWwTempSensorDefaultOnFailure = AttrVal($name, "zhkWwTempSensorDefaultOnFailure", "70");
#get sensor reading or fallback to Age-default
my $zhkWwIstTempVal = ReadingsVal($zhkWwTempSensorFhemDev, $zhkWwTempSensorReading, $zhkWwTempSensorDefaultOnFailure);
my $zhkWwIstTempTimestamp = ReadingsTimestamp($zhkWwTempSensorFhemDev,$zhkWwTempSensorReading,0);
$zhkWwIstTempTimestamp = time_str2num($zhkWwIstTempTimestamp);
if($zhkWwIstTempTimestamp<($now-$zhkWwTempSensorMaxAge)){
$zhkWwIstTempVal = $zhkWwTempSensorDefaultOnFailure;
#bogus reading may appear: ToDo...
}
#relais um analoge temperaturbegrenzug zu übergehen, zB für monatliches kochen
my $zhkWwBoostStartTemp = AttrVal($name, "zhkWwBoostStartTemp", 45);
if($zhkWwSollTemp>$zhkWwBoostStartTemp){ WwBoostStopStart($hash,1); }else{ WwBoostStopStart($hash,0) }
#alpha der $zhkWwIstTempVal errechnen falls letzter wert im cache existiert
#seconds age actual reading
my $newAge = $now-$zhkWwIstTempTimestamp;
my ($zhkWwIstLastReading,$zhkWwIstLastReadingTimestamp) = split(/=/,ReadingsVal($name, "zhkWwIstLastReading", "0=1401111111"));
#seconds age last reading olther than new one
my $oldAgeDiffToNew = $now-$zhkWwIstLastReadingTimestamp-$newAge;
#change $zhkWwIstLastReading, calc linear for 1 minute before new
if($oldAgeDiffToNew==0){ return; } #nothing more to to if no temp.reading present
$zhkWwIstLastReading = $zhkWwIstTempVal+($zhkWwIstLastReading-$zhkWwIstTempVal)/$oldAgeDiffToNew*60;
#get the temp diff for past 1 minute
my $zhkWwAlphaActualVal = $zhkWwIstTempVal-$zhkWwIstLastReading; #minus=fallend, plus=steigend
readingsSingleUpdate($hash, "zhkWwAlphaActualVal", $zhkWwAlphaActualVal, 1); #update temp-reading-cache
readingsSingleUpdate($hash, "zhkWwIstLastReading", $zhkWwIstTempVal."=".$zhkWwIstTempTimestamp, 1); #update temp-reading-cache
#debug alpha here
#readingsSingleUpdate($hash, "zhkWwIstLastReading", ($zhkWwIstTempVal+1)."=".$zhkWwIstTempTimestamp, 1); #update temp-reading-cache
#debug alpha here
my $zhkWwAlphaDownAlarmDiffDeg = AttrVal($name, "zhkWwAlphaDownAlarmDiffDeg",0.8);
my $zhkWwAlphaUpAlarmDiffDeg = AttrVal($name, "zhkWwAlphaUpAlarmDiffDeg", 5);
#minus=fallend, plus=steigend
my $tempIsFalling = ((abs($zhkWwAlphaActualVal)==$zhkWwAlphaActualVal)?0:1);
$zhkWwAlphaActualVal=abs($zhkWwAlphaActualVal);
if($tempIsFalling and ($zhkWwAlphaActualVal>$zhkWwAlphaDownAlarmDiffDeg)){
#falling and diff already over limit
#trigger immediate burn start, begin of warmWater use
BrennerStopStart($hash,0); #will remain on for 5min ($zhkBrennerTaktMinOnSec)
readingsSingleUpdate($hash, "zhkWwPriorityOn", "1", 0); #update priority-active-reading
#}elsif(!$tempIsFalling and ($zhkWwAlphaActualVal>$zhkWwAlphaUpAlarmDiffDeg)){
##raising and diff already over limit ->do nothing
}
#classic pump on/off handling
my $zhkWwAlphaThreshold = AttrVal($name, "zhkWwAlphaThreshold", 1);
if(ReadingsVal($name, "zhkWwPriorityOn", 0) or abs($zhkWwIstTempVal-$zhkWwSollTemp)>$zhkWwAlphaThreshold){
WwPumpStopStart($hash,0);
}elsif(abs($zhkWwIstTempVal-$zhkWwSollTemp)<$zhkWwAlphaThreshold){
#untergrenze erreicht, priority wieder abschalten
readingsSingleUpdate($hash, "zhkWwPriorityOn", "0", 0); #update priority-active-reading
}elsif($zhkWwIstTempVal>$zhkWwSollTemp){
WwPumpStopStart($hash,1);
}
#Log3($name, 3, "ZHK $name abnachrechts: zhkWwAlphaActualVal: $zhkWwAlphaActualVal :\n");
#readingsSingleUpdate($hash, "now", $now, 1);
#Log3($name, 3, "ZHK $name abnachrechts: zhkWwIstTempVal: $zhkWwIstTempVal :");
#Log3($name, 3, "ZHK $name abnachrechts: zhkWwIstLastReading: $zhkWwIstLastReading :C end of sub");
#return;
return;
}
sub WwPumpStopStart($$){
my ($hash, $startstop) = @_;
my $name = $hash->{NAME};
my $zhkWwPumpLaststart = ReadingsVal($name, "zhkWwPumpLaststart", 0);
my $zhkWwTaktMinOnSec = AttrVal($name, "zhkWwTaktMinOnSec", 60);
#laststart: min takt before off/on
if($startstop==0 and ($zhkWwPumpLaststart+$zhkWwTaktMinOnSec)<gettimeofday()){
#turn on without delay
}elsif($startstop==1 and ($zhkWwPumpLaststart+$zhkWwTaktMinOnSec)<gettimeofday()){
return; #delay before turning off
}
my $zhkWwPumpFhemDev = AttrVal($name, "zhkWwPumpFhemDev", "P7_WwStop");
#set on/off if state-change desired (refuse to set same state again)
if(ReadingsVal($zhkWwPumpFhemDev,"state",2) eq $startstop){return;}
# fhem("set ".$zhkWwPumpFhemDev." ".$startstop);
readingsSingleUpdate($hash, "zhkWwPumpStopStatus", ($startstop==0?"off":"on") , 1); #update reading for frontend
Log3($name, 3, "ZHK $name: WwPumpStopStart:".$startstop);
return;
}
sub WwBoostStopStart($$){
my ($hash, $startstop) = @_;
my $name = $hash->{NAME};
my $zhkWwPumpLaststart = ReadingsVal($name, "zhkWwPumpLaststart", 0);
my $zhkWwTaktMinOnSec = AttrVal($name, "zhkWwTaktMinOnSec", 60);
#laststart: min takt before off/on
my $zhkWwBoostFhemDev = AttrVal($name, "zhkWwBoostFhemDev", "P2_WwBoost");
#set on/off if state-change desired (refuse to set same state again)
if(ReadingsVal($zhkWwBoostFhemDev,"state",2) eq $startstop){return;}
# fhem("set ".$zhkWwBoostFhemDev." ".$startstop);
readingsSingleUpdate($hash, "zhkWwBoostStatus", ($startstop==0?"off":"on") , 1); #update reading for frontend
Log3($name, 3, "ZHK $name: WwPumpStopStart:".$startstop);
return;
}
zhkWwAlphaDownAlarmDiffDeg attr float 0.8 zhk Ww Alpha DownAlarm DiffDeg mindest-temp-diff für sofort-aufheizung
zhkWwAlphaUpAlarmDiffDeg attr float 5 zhk Ww Alpha UpAlarm DiffDeg min.diff zu abschaltung hot für AlphaUp
zhkWwAlphaThreshold attr float 1 zhk Ww Alpha Threshold Meßtoleranz ww-temp °C
zhkWwAlphaActualVal cache float zhk Ww Alpha Actual Val zuletzt berechneter wert für alpha
zhkWwIstLastReading cache string zhk Ww Ist LastReading cached last OW temp for alpha-calc
zhkWwIstLastReading2 cache string zhk Ww Ist LastReading2 cached last OW temp for alpha-calc
zhkWwPumpStopStatus cache string off zhk Ww Pump StopStatus
zhkWwBoostStatus cache string off zhk Ww Boost Status
zhkWwTaktMinOnSec attr int 60 zhk Ww Takt MinOnSec delay before off when WwPump started
zhkWwPumpLaststart cache int zhk Ww Pump Laststart
zhkWwSollTemp set-reading float 30 zhk Ww Soll Temp einstellung User (zeitplan mit at möglich)
zhkWwPriorityOn reading int 0 sub kessel? zhk Ww Priority On wenn 1, dann brenner sofort starten
zhkWwPumpFhemDev attr string P7_WwStop zhk Ww Pump FhemDev WW pumpe, 0=on / 1=off
zhkWwBoostFhemDev attr string P2_WwBoost zhk Ww Boost FhemDev relais um analoge temperaturbegrenzug zu übergehen
zhkWwBoostStartTemp attr int 45 zhk Ww Boost StartTemp temp. ab der die umgehung notwendig ist
zhkWwTempSensorFhemDev attr string 5_15_WarmWasser_EB6F98050000 zhk Ww TempSensor FhemDev
zhkWwTempSensorReading attr string temperature zhk Ww TempSensor Reading
zhkWwTempSensorMaxAge attr int 300 5min zhk Ww TempSensor MaxAge sensor ignorieren wenn state-age > x seconds
zhkWwTempSensorDefaultOnFailure attr int 70 zhk Ww TempSensor DefaultOnFailure
zhkWwIstTempVal cache float OW value zhk Ww Ist Temp Val OW lesen, wenn fehler dann default MAX
zhkWwIstTempTimestamp cache string 35 OW value zhk Ww Ist Temp Timestamp timestamp last OW update
Internals:
CFGFN
DEF autocontrol
NAME zhk4
NOTIFYDEV global
NR 352
NTFY_ORDER 50-zhk4
STATE active
TYPE ZHK
Readings:
2014-05-29 09:07:07 autocontrol autocontrol
2014-05-29 09:46:12 state active
2014-05-29 09:46:02 zhkWwAlphaActualVal 0.375
2014-05-29 09:46:12 zhkWwIstLastReading 42.375=1401349565
2014-05-29 09:46:12 zhkWwPriorityOn 0
2014-05-29 09:10:55 zhkWwSollTemp 32
Attributes:
zhkBrennerFhemDev P3_BrennerStop
zhkBrennerTaktMinOffSec 30
zhkBrennerTaktMinOnSec 300
zhkGlobalIncludeAussentemp 1
zhkGlobalIncludeHolzofen 1
zhkGlobalIncludeKessel 1
zhkGlobalIncludeValvePositions 1
zhkGlobalIncludeVorlauf 1
zhkGlobalIncludeWarmwasser 1
zhkINTpollInterval 10
zhkWwAlphaDownAlarmDiffDeg 0.8
zhkWwAlphaThreshold 1
zhkWwAlphaUpAlarmDiffDeg 5
zhkWwBoostFhemDev P2_WwBoost
zhkWwBoostStartTemp 45
zhkWwPumpFhemDev P7_WwStop
zhkWwTaktMinOnSec 60
zhkWwTempSensorDefaultOnFailure 70
zhkWwTempSensorFhemDev 5_15_WarmWasser_EB6F98050000
zhkWwTempSensorMaxAge 300
zhkWwTempSensorReading temperature
hier noch ein plot dazu, die temp. geht noch weit herunter da die neue warmwassersteuerung derzeit nur einen dummy steuert. die kurve fallwinkel reagiert frühzeitig auf die entnahme gegen 07:28h.
(http://scellius.de/admin/tmp/2014-05-29_alpha.png)
(http://scellius.de/admin/tmp/2014-05-29_temp.png)
gruß, florian