# $Id$ ############################################## # # Dewpoint computing # # based / modified from 98_average.pm (C) by Rudolf Koenig # # Copyright (C) 2012 Willi Herzig # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # The GNU General Public License may also be found at http://www.gnu.org/licenses/gpl-2.0.html . # package main; use strict; use warnings; use vars qw(%defs); sub Log3($$$); # default maximum time_diff for dewpoint my $dewpoint_time_diff_default = 1; # 1 Second ########################## sub dewpoint_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "dewpoint_Define"; $hash->{NotifyFn} = "dewpoint_Notify"; $hash->{AttrFn} = "dewpoint_Attr"; $hash->{NotifyOrderPrefix} = "10-"; # Want to be called before the rest $hash->{AttrList} = "disable:0,1 legacyStateHandling:0,1 verbose max_timediff absFeuchte" . " absoluteHumidity vapourPressure"; } ########################## sub dewpoint_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); return "wrong syntax: define dewpoint (dewpoint|fan|alarm) devicename [options]" if(@a < 4); my $name = $a[0]; my $cmd_type = $a[2]; # dewpoint, fan, alarm my $devname = $a[3]; if ($cmd_type eq "dewpoint") { # define dewpoint dewpoint devicename-regex [temp_name hum_name new_name] if(@a == 7) { $hash->{TEMP_NAME} = $a[4]; $hash->{HUM_NAME} = $a[5]; $hash->{NEW_NAME} = $a[6]; } elsif (@a == 4) { $hash->{TEMP_NAME} = "temperature"; $hash->{HUM_NAME} = "humidity"; $hash->{NEW_NAME} = "dewpoint"; } else { return "wrong syntax: define dewpoint dewpoint devicename-regex [temp_name hum_name new_name]" } } elsif ($cmd_type eq "fan") { # define dewpoint fan devicename-regex devicename-outside min_temp if (@a == 6 || @a == 7) { $hash->{DEVNAME_OUT} = $a[4]; $hash->{MIN_TEMP} = $a[5]; if (@a == 6) { $hash->{DIFF_TEMP} = 0; } else { $hash->{DIFF_TEMP} = $a[6]; } } else { return "wrong syntax: define dewpoint fan devicename-regex devicename-outside min_temp [diff_temp]" } } elsif ($cmd_type eq "alarm") { # define dewpoint alarm devicename-regex devicename-reference diff_temp if (@a == 6) { $hash->{DEVNAME_REF} = $a[4]; $hash->{DIFF_TEMP} = $a[5]; } else { return "wrong syntax: define dewpoint alarm devicename-regex devicename-reference diff_temp" } } else { return "wrong syntax: define dewpoint (dewpoint|fan|alarm) devicename-regex [options]" } $hash->{CMD_TYPE} = $cmd_type; eval { "Hallo" =~ m/^$devname$/ }; return "Bad regexp: $@" if($@); $hash->{DEV_REGEXP} = $devname; # set NOTIFYDEV notifyRegexpChanged($hash, $devname); $hash->{STATE} = "active"; return undef; } ########################## sub dewpoint_Attr(@) { my ($cmd, $name, $a_name, $a_val) = @_; my $hash = $defs{$name}; if ($cmd eq "set" && $a_name eq "absFeuchte") { Log(1, "dewpoint $name: attribute 'absFeuchte' is deprecated, please use 'absoluteHumidity'"); return undef; } if ($cmd eq "set" && ($a_name eq "absoluteHumidity" || $a_name eq "vapourPressure")) { if (! goodReadingName($a_val)) { return "Value of $a_name is not a valid reading name"; } } return undef; } ########################## sub dewpoint_Notify($$) { my ($hash, $dev) = @_; my $hashName = $hash->{NAME}; my $devName = $dev->{NAME}; my $re = $hash->{DEV_REGEXP}; # fast exit return "" if (!defined($re) || $devName !~ m/^$re$/); return "" if (AttrVal($hashName, "disable", undef)); my $cmd_type = $hash->{CMD_TYPE}; # dewpoint my $temp_name = "temperature"; my $hum_name = "humidity"; my $new_name = "dewpoint"; # fan my $devname_out = ""; my $min_temp = 0; # alarm my $devname_ref = ""; my $diff_temp = 0; if ($cmd_type eq "dewpoint") { if (!defined($hash->{TEMP_NAME}) || !defined($hash->{HUM_NAME}) || !defined($hash->{NEW_NAME})) { # should never happen! Log3($hashName, 1, "Error dewpoint: TEMP_NAME || HUM_NAME || NEW_NAME undefined"); return ""; } $temp_name = $hash->{TEMP_NAME}; $hum_name = $hash->{HUM_NAME}; $new_name = $hash->{NEW_NAME}; Log3($hashName, 4, "dewpoint_notify: cmd_type=$cmd_type devname=$devName dewname=$hashName, dev=$devName, " . "dev_regex=$re temp_name=$temp_name hum_name=$hum_name"); } elsif ($cmd_type eq "fan") { if (!defined($hash->{DEVNAME_OUT}) || !defined($hash->{MIN_TEMP})) { # should never happen! Log3($hashName, 1, "Error dewpoint: DEVNAME_OUT || MIN_TEMP undefined"); return ""; } $devname_out = $hash->{DEVNAME_OUT}; $min_temp = $hash->{MIN_TEMP}; $diff_temp = $hash->{DIFF_TEMP}; Log3($hashName, 4, "dewpoint_notify: cmd_type=$cmd_type devname=$devName dewname=$hashName, dev=$devName, " . " dev_regex=$re, devname_out=$devname_out, min_temp=$min_temp, diff_temp=$diff_temp"); } elsif ($cmd_type eq "alarm") { if (!defined($hash->{DEVNAME_REF}) || !defined($hash->{DIFF_TEMP})) { # should never happen! Log3($hashName, 1, "dewpoint_notify: error: DEVNAME_REF || DIFF_TEMP undefined"); return ""; } $devname_ref = $hash->{DEVNAME_REF}; $diff_temp = $hash->{DIFF_TEMP}; Log3($hashName, 4, "dewpoint_notify: cmd_type=$cmd_type devname=$devName dewname=$hashName, dev=$devName, " . "dev_regex=$re, devname_ref=$devname_ref, diff_temp=$diff_temp"); } else { # should never happen: Log3($hashName, 1, "dewpoint_notify: error: unknown cmd_type ".$cmd_type); return ""; } my $nev = int(@{$dev->{CHANGED}}); # if we use the "T H" syntax we must track the index of the state event my $i_state_ev; my $temperature = ""; my $humidity = ""; for (my $i = 0; $i < $nev; $i++) { my $s = $dev->{CHANGED}[$i]; Log3($hashName, 5, "dewpoint_notify: s='$s'"); ################ # Filtering next if(!defined($s)); my ($evName, $val, $rest) = split(" ", $s, 3); # resets $1 next if(!defined($evName)); next if(!defined($val)); Log3($hashName, 5, "dewpoint_notify: evName='$evName' val=$val'"); if (($evName eq "T:") && ($temp_name eq "T")) { $i_state_ev = $i; #my ($evName1, $val1, $evName2, $val2, $rest) = split(" ", $s, 5); # resets $1 if ($s =~ /T: ([-+]?[0-9]*\.[0-9]+|[-+]?[0-9]+)/) { $temperature = $1; } if ($s =~ /H: [-+]?([0-9]*\.[0-9]+|[0-9]+)/) { $humidity = $1; } Log3($hashName, 5, "dewpoint_notify: T: H:, temp=$temperature hum=$humidity"); } elsif ($evName eq $temp_name.":") { $temperature = $val; Log3($hashName, 5, "dewpoint_notify: temperature! dev=$devName, temp_name=$temp_name, temp=$temperature"); } elsif ($evName eq $hum_name.":") { $humidity = $val; Log3($hashName, 5, "dewpoint_notify: humidity! dev=$devName, hum_name=$hum_name, hum=$humidity"); } } #if (($temperature eq "") || ($humidity eq "")) { return undef; } # no way to calculate dewpoint! # Check if Attribute timeout is set my $timeout = AttrVal($hash->{NAME}, "max_timediff", $dewpoint_time_diff_default); Log3($hashName, 5,"dewpoint_notify: max_timediff=$timeout"); if (($humidity eq "") && (($temperature eq ""))) { return undef; # no way to calculate dewpoint! } elsif (($humidity eq "") && (($temperature ne ""))) { # temperature set, but humidity not. Try to use a valid value from the appropriate reading $humidity = ReadingsNum($devName, $hum_name, undef); my $time_diff = ReadingsAge($devName, $hum_name, undef); if (defined($humidity) && defined($time_diff)) { Log3($hashName, 5, ">dev=$devName, hum_name=$hum_name, reference humidity=$humidity ($time_diff)," . " temp=$temperature"); } else { return undef; } if ($time_diff > 0 && $time_diff > $timeout) { return undef; } } elsif (($temperature eq "") && ($humidity ne "")) { # humdidity set, but temperature not. Try to use a valid value from the appropriate reading $temperature = ReadingsNum($devName, $temp_name, undef); my $time_diff = ReadingsAge($devName, $temp_name, undef); if (defined($temperature) && defined($time_diff)) { Log3($hashName, 5, ">dev=$devName, temp_name=$temp_name, reference temperature=$temperature ($time_diff)," . " hum=$humidity"); } else { return undef; } if ($time_diff > 0 && $time_diff > $timeout) { return undef; } } # We found temperature and humidity. so we can calculate dewpoint first # Prüfen, ob humidity im erlaubten Bereich ist if (($humidity <= 0) || ($humidity >= 110)){ Log3($hashName, 1, "dewpoint_notify: humidity device $devName ($hum_name) invalid: $humidity"); return undef; } my $dewpoint = dewpoint_dewpoint($temperature, $humidity); Log3($hashName, 5, "dewpoint_notify: dewpoint=$dewpoint"); my $tn = TimeNow(); if ($cmd_type eq "dewpoint") { # >define dewpoint dewpoint [ ] # # Calculates dewpoint for device from temperature and humidity and write it # to new Reading dewpoint. # If optional , and is specified # then read temperature from reading , humidity from reading # and write dewpoint to reading . # if temp_name eq "T" then use temperature from state T: H:, add to the state # Example: # define dewtest1 dewpoint dewpoint .* # define dewtest2 dewpoint dewpoint .* T H D readingsBeginUpdate($dev); my $rval; my $rname; my $abs_humidity = dewpoint_absFeuchte($temperature, $humidity); my $aFeuchte = AttrVal($hashName, "absFeuchte", undef); if (defined($aFeuchte)) { $rname = "absFeuchte"; readingsBulkUpdate($dev, $rname, $abs_humidity); Log3($hashName, 5, "dewpoint_notify: absFeuchte= $abs_humidity"); $aFeuchte = "A: " . $abs_humidity; } my $ah_rname = AttrVal($hashName, "absoluteHumidity", undef); if (defined($ah_rname)) { readingsBulkUpdate($dev, $ah_rname, $abs_humidity); Log3($hashName, 5, "dewpoint_notify: $ah_rname= $abs_humidity"); $aFeuchte = "A: " . $abs_humidity if !defined($aFeuchte); } my $vp_rname = AttrVal($hashName, "vapourPressure", undef); if (defined($vp_rname)) { my $vp = round(10 * dewpoint_vp($temperature, $humidity), 1); readingsBulkUpdate($dev, $vp_rname, $vp); Log3($hashName, 5, "dewpoint_notify: $vp_rname= $vp"); } $rname = $new_name; my $has_state_format = defined(AttrVal($dev->{NAME}, "stateFormat", undef)); my $legacy_sh = AttrVal($hash->{NAME}, "legacyStateHandling", 0); if ($temp_name ne "T" || ($has_state_format && ! $legacy_sh)) { $rval = $dewpoint; readingsBulkUpdate($dev, $rname, $rval); readingsEndUpdate($dev, 1); } else { # explicit manipulation of STATE here # first call readingsEndUpdate to finish STATE processing in the referenced device... readingsEndUpdate($dev, 1); # ... then update STATE # STATE begins with "T:". append dewpoint or insert before BAT my $lastval = $dev->{CHANGED}[$i_state_ev]; if ($lastval =~ /BAT:/) { $rval = $lastval; $rval =~ s/BAT:/$rname: $dewpoint BAT:/g; } elsif ($lastval =~ /<{STATE} = $rval; # the state event must be REPLACED $dev->{CHANGED}[$i_state_ev] = $rval; } # remove cached "state:..." events if any $dev->{CHANGEDWITHSTATE} = []; Log3($hashName, 5, "dewpoint_notify: rval=$rval"); } elsif ($cmd_type eq "fan") { # >define dewpoint fan devicename devicename-outside min-temp [diff-temp] # # This define may be used to turn an fan on or off if the outside air has less # water # # - Generate reading/event "fan: on" if (dewpoint of ) + diff_temp is lower # than dewpoint of and temperature of is >= min-temp # and reading "fan" was not already "on". # - Generate reading/event "fan: off": else and if reading "fan" was not already "off". Log3($hashName, 5, "dewpoint_notify: fan devname_out=$devname_out, min_temp=$min_temp, diff_temp=$diff_temp"); my $rname; my $rval; if (exists $defs{$devname_out}{READINGS}{temperature}{VAL} && exists $defs{$devname_out}{READINGS}{humidity}{VAL}) { my $temperature_out = $defs{$devname_out}{READINGS}{temperature}{VAL}; my $humidity_out = $defs{$devname_out}{READINGS}{humidity}{VAL}; my $dewpoint_out = dewpoint_dewpoint($temperature_out, $humidity_out); Log3($hashName, 5, "dewpoint_notify: fan dewpoint_out=$dewpoint_out"); if (($dewpoint_out + $diff_temp) < $dewpoint && $temperature_out >= $min_temp) { $rval = "on"; Log3($hashName, 4, "dewpoint_notify: fan ON"); } else { $rval = "off"; Log3($hashName, 4, "dewpoint_notify: fan OFF"); } $rname = "fan"; if (!exists $defs{$devName}{READINGS}{$rname}{VAL} || $defs{$devName}{READINGS}{$rname}{VAL} ne $rval) { Log3($hashName, 4, "dewpoint_notify: CHANGE fan $rval"); $dev->{READINGS}{$rname}{TIME} = $tn; $dev->{READINGS}{$rname}{VAL} = $rval; $dev->{CHANGED}[$nev++] = $rname . ": " . $rval; } } else { Log3($hashName, 1, "dewpoint_notify: fan devname_out=$devname_out no temperature or humidity available" . " for dewpoint calculation"); } } elsif ($cmd_type eq "alarm") { # >define dewpoint alarm devicename devicename-reference diff # # - Generate reading/event "alarm: on" if temperature of - is lower # than dewpoint of and reading "alarm" was not already "on". # - Generate reading/event "alarm: off" if temperature of - is higher # than dewpoint of and reading "alarm" was not already "off". # # You have different options to use this define: # * Use a temperature sensor in or on the wall () and use a temp/hum sensor # to measure the dewpoint of the air. Alarm if the temperature of the wall is lower than the dewpoint of the air. # In this case the water of the air will condense on the wall because the wall is cold. # Example: define alarmtest dewpoint alarm roomsensor wallsensor 0 # * If you do not have a temperature sensor in/on the wall, you may also compare the rooms dewpoint to the # temperature of the same or another inside sensor. If you think that your walls are normally 5 degrees colder # than the inside temperature, set diff to 5. # Example: define alarmtest dewpoint alarm roomsensor roomsensor 5 Log3($hashName, 5, "dewpoint_notify: alarm devname_ref=$devname_ref, diff_temp=$diff_temp"); my $rname; my $rval; if (exists $defs{$devname_ref}{READINGS}{temperature}{VAL}) { my $temperature_ref = $defs{$devname_ref}{READINGS}{temperature}{VAL}; Log3($hashName, 5, "dewpoint_notify: alarm temperature_ref=$temperature_ref"); if ($temperature_ref - $diff_temp < $dewpoint) { $rval = "on"; Log3($hashName, 4, "dewpoint_notify: alarm ON"); } else { $rval = "off"; Log3($hashName, 4, "dewpoint_notify: alarm OFF"); } $rname = "alarm"; if (!exists $defs{$devName}{READINGS}{$rname}{VAL} || $defs{$devName}{READINGS}{$rname}{VAL} ne $rval) { Log3($hashName, 5, "dewpoint_notify: CHANGE alarm $rval"); $dev->{READINGS}{$rname}{TIME} = $tn; $dev->{READINGS}{$rname}{VAL} = $rval; $dev->{CHANGED}[$nev++] = $rname . ": " . $rval; } } else { Log3($hashName, 1, "dewpoint_notify: alarm devname_out=$devname_out no temperature or humidity available" . " for dewpoint calculation"); } } else { # should never happen: Log3($hashName, 1, "dewpoint_notify: unknown cmd_type ".$cmd_type); return ""; } return undef; } # ----------------------------- # Dewpoint calculation. # 'Magnus formula' # # Parameters from https://de.wikipedia.org/wiki/Taupunkt#S.C3.A4ttigungsdampfdruck # Good summary of formulas in http://www.wettermail.de/wetter/feuchte.html my $E0 = 0.6112; # saturation pressure at T=0 °C my @ab_gt0 = (17.62, 243.12); # T>0 my @ab_le0 = (22.46, 272.6); # T<=0 over ice ### ** Public interface ** keep stable # vapour pressure in kPa sub dewpoint_vp($$) { my ($T, $Hr) = @_; my ($a, $b); if ($T > 0) { ($a, $b) = @ab_gt0; } else { ($a, $b) = @ab_le0; } return 0.01 * $Hr * $E0 * exp($a * $T / ($T + $b)); } ### ** Public interface ** keep stable # dewpoint in °C sub dewpoint_dewpoint($$) { my ($T, $Hr) = @_; if ($Hr == 0) { Log(1, "Error: dewpoint() Hr==0 !: temp=$T, hum=$Hr"); return undef; } my ($a, $b); if ($T > 0) { ($a, $b) = @ab_gt0; } else { ($a, $b) = @ab_le0; } # solve vp($dp, 100) = vp($T,$Hr) for $dp my $v = log(dewpoint_vp($T, $Hr) / $E0); my $D = $a - $v; # can this ever happen for valid input? if ($D == 0) { Log(1, "Error: dewpoint() D==0 !: temp=$T, hum=$Hr"); return undef; } return round($b * $v / $D, 1); } ### ** Public interface ** keep stable # absolute Feuchte in g Wasserdampf pro m3 Luft sub dewpoint_absFeuchte ($$) { my ($T, $Hr) = @_; # 110 ? if (($Hr < 0) || ($Hr > 110)) { Log(1, "Error dewpoint: humidity invalid: $Hr"); return ""; } my $DD = dewpoint_vp($T, $Hr); my $AF = 1.0E6 * (18.016 / 8314.3) * ($DD / (273.15 + $T)); return round($AF, 1); } 1; =pod =item helper =item summary compute dewpoint and/or generate events for starting a fan =item summary_DE berechne Taupunkt und/oder erzeuge events zum starten eines Lüfters =begin html

dewpoint

    Dewpoint calculations. Offers three different ways to use dewpoint:
    • dewpoint
      Compute additional reading dewpoint from a sensor offering temperature and humidity.
    • fan
      Generate a event to turn a fan on if the outside air has less water than the inside.
    • alarm
      Generate a mold alarm if a reference temperature is lower than the current dewpoint.

    Define
      define <name> dewpoint dewpoint <devicename-regex> [<temp_name> <hum_name> <new_name>]

        Calculates dewpoint for device <devicename-regex> from temperature and humidity and write it to a new reading named dewpoint. If optional <temp_name>, <hum_name> and <new_name> is specified then read temperature from reading <temp_name>, humidity from reading <hum_name> and write the calculated dewpoint to reading <new_name>.
        Obsolete, avoid for new definitions
          If <temp_name> is T then use temperature from state T: H:, add <new_name> to the STATE. The addition to STATE only occurs if the target device does not define attribute "stateFormat".
        If the obsolete behaviour of STATE is mandatory set attribute legacyStateHandling.


      Example:
          # Compute the dewpoint for the temperature/humidity
          # events of the temp1 device and generate reading dewpoint.
          define dew_temp1 dewpoint dewpoint temp1
          define dew_temp1 dewpoint dewpoint temp1 temperature humidity dewpoint
      
          # Compute the dewpoint for the temperature/humidity
          # events of all devices offering temperature and humidity
          # and generate reading dewpoint.
          define dew_all dewpoint dewpoint .*
          define dew_all dewpoint dewpoint .* temperature humidity dewpoint
      
          # Compute the dewpoint for the temperature/humidity
          # events of the device Aussen_1 offering temperature and humidity
          # and insert is into STATE unless Aussen_1 has attribute "stateFormat" defined.
          # If "stateFormat" is defined then a reading D will be generated.
          define dew_state dewpoint dewpoint Aussen_1 T H D
      
          # Compute the dewpoint for the temperature/humidity
          # events of all devices offering temperature and humidity
          # and insert the result into the STATE. (See example above).
          # Example STATE: "T: 10 H: 62.5" will change to
          # "T: 10 H: 62.5 D: 3.2"
          define dew_state dewpoint dewpoint .* T H D
      
          
      define <name> dewpoint fan <devicename> <devicename-outside> <min-temp> [<diff_temp>]

        May be used to turn an fan on or off if the outside air has less water.
        • Generate event "fan: on" if (dewpoint of <devicename-outside>) + <diff_temp> is lower than dewpoint of <devicename> and temperature of <devicename-outside> is >= min-temp and reading "fan" was not already "on". The event will be generated for <devicename>. Parameter <diff-temp> is optional
        • Generate event "fan: off": else and if reading "fan" was not already "off".

      Example:
          # Generate event "fan: on" when dewpoint of Aussen_1 is first
          # time lower than basement_tempsensor and outside temperature is >= 0
          # and change it to "fan: off" is this condition changes.
          # Set a switch on/off (fan_switch) depending on the state.
          define dew_fan1 dewpoint fan basement_tempsensor Aussen_1 0
          define dew_fan1_on notify basement_tempsensor.*fan:.*on set fan_switch on
          define dew_fan1_off notify basement_tempsensor.*fan:.*off set fan_switch off
      
          
      define <name> dewpoint alarm <devicename> <devicename-reference> <diff-temp>

        Generate a mold alarm if a reference temperature is lower than the current dewpoint.
        • Generate reading/event "alarm: on" if temperature of <devicename-reference> - <diff-temp> is lower than dewpoint of <devicename> and reading "alarm" was not already "on". The event will be generated for <devicename>.
        • Generate reading/event "alarm: off" if temperature of <devicename-reference> - <diff-temp> is higher than dewpoint of <devicename> and reading "alarm" was not already "off".

      Example:
          # Using a wall temperature sensor (wallsensor) and a temp/hum sensor
          # (roomsensor) to alarm if the temperature of the wall is lower than
          # the dewpoint of the air. In this case the water of the air will
          # condense on the wall because the wall is cold.
          # Set a switch on (alarm_siren) if alarm is on using notify.
          define dew_alarm1 dewpoint alarm roomsensor wallsensor 0
          define roomsensor_alarm_on notify roomsensor.*alarm:.*on set alarm_siren on
          define roomsensor_alarm_off notify roomsensor.*alarm:.*off set alarm_siren off
      
          # If you do not have a temperature sensor in/on the wall, you may also
          # compare the rooms dewpoint to the temperature of the same or another
          # inside sensor. Alarm is temperature is 5 degrees colder than the
          # inside dewpointinside.
          define dev_alarm2 dewpoint alarm roomsensor roomsensor 5
      
          
    Set
      N/A

    Get
      N/A

    Attributes
    • disable
    • absoluteHumidity <reading_name>
      • In addition the absolute humidity in g/m³ will be computed as reading <reading_name>.

    • vapourPressure <reading_name>
      • In addition the vapour pressure in hPa will be computed as reading <reading_name>.

    • max_timediff
      • Maximum time difference in seconds allowed between the temperature and humidity values for a device. dewpoint uses the Readings for temperature or humidity if they are not delivered in the event. This is necessary for using dewpoint with event-on-change-reading. Also needed for sensors that do deliver temperature and humidity in different events like for example technoline sensors TX3TH.
        If not set default is 1 second.

        Examples:
        		# allow maximum time difference of 60 seconds
        		define dew_all dewpoint dewpoint .*
        		attr dew_all max_timediff 60
            
=end html =begin html_DE

dewpoint

    Berechnungen des Taupunkts. Es gibt drei Varianten, das Modul dewpoint zu verwenden:
    • dewpoint: Taupunkt
      Erzeugt ein zusätzliches Ereignis "dewpoint" aus Temperatur- und Luftfeuchtewerten eines Fühlers.
    • fan: Lüfter
      Erzeugt ein Ereignis, um einen Lüfter einzuschalten, wenn die Außenluft weniger Wasser als die Raumluft enthält.
    • alarm: Alarm
      Erzeugt einen Schimmel-Alarm, wenn eine Referenz-Temperatur unter den Taupunkt fällt.

    Define
      define <name> dewpoint dewpoint <devicename-regex> [<temp_name> <hum_name> <new_name>]

      Berechnet den Taupunkt des Geräts <devicename-regex> basierend auf Temperatur und Luftfeuchte und erzeugt daraus ein neues Reading namens dewpoint.
      Wenn <temp_name>, <hum_name> und <new_name> angegeben sind, werden die Temperatur aus dem Reading <temp_name>, die Luftfeuchte aus dem Reading <hum_name> gelesen und als berechneter Taupunkt ins Reading <new_name> geschrieben.

      Veraltet, für neue Definitionen nicht mehr benutzen
        Wenn <temp_name> T lautet, wird die Temperatur aus state T: H: benutzt und <new_name> zu STATE hinzugefügt. Das hinzufügen zu STATE erfolgt nur, falls im Zielgerät das Attribut "stateFormat" nicht definiert ist.
      Falls das veraltete Verhalten zum Update unbedingt gewüscht ist, kann das Attribut legacyStateHandling gesetzt werden.
      Beispiele:
          # Berechnet den Taupunkt aufgrund von Temperatur und Luftfeuchte
          # in Ereignissen, die vom Gerät temp1 erzeugt wurden und erzeugt ein Reading dewpoint.
          define dew_temp1 dewpoint dewpoint temp1
          define dew_temp1 dewpoint dewpoint temp1 temperature humidity dewpoint
      
          # Berechnet den Taupunkt aufgrund von Temperatur und Luftfeuchte
          # in Ereignissen, die von allen Geräten erzeugt wurden die diese Werte ausgeben
          # und erzeugt ein Reading dewpoint.
          define dew_all dewpoint dewpoint .*
          define dew_all dewpoint dewpoint .* temperature humidity dewpoint
      
          # Berechnet den Taupunkt aufgrund von Temperatur und Luftfeuchte
          # in Ereignissen, die vom Gerät Aussen_1 erzeugt wurden und ergänzt 
          # mit diesem Wert den Status STATE, falls in Aussen_1 das Attribut "stateFormat" nicht definiert ist.
          # Falls "stateFormat" definiert ist, wird das reading "D" angelegt.
          define dew_state dewpoint dewpoint Aussen_1 T H D
      
          # Berechnet den Taupunkt aufgrund von Temperatur und Luftfeuchte
          # in Ereignissen, die von allen Geräten erzeugt wurden die diese Werte ausgeben
          # und ergänzt mit diesem Wert den Status STATE. (Siehe Beispiel oben).
          # Beispiel STATE: "T: 10 H: 62.5" wird verändert nach
          # "T: 10 H: 62.5 D: 3.2"
          define dew_state dewpoint dewpoint .* T H D
          


      define <name> dewpoint fan <devicename> <devicename-outside> <min-temp> [<diff_temp>]

      • Erzeugt ein Ereignis, um einen Lüfter einzuschalten, wenn die Außenluft weniger Wasser als die Raumluft enthält.
      • Erzeugt das Ereignis "fan: on" wenn (Taupunkt von <devicename-outside>) + <diff_temp> ist niedriger als der Taupunkt von <devicename> und die Temperatur von <devicename-outside> >= min-temp ist. Das Ereignis wird nur erzeugt wenn das Reading "fan" nicht schon "on" war. Das Ereignis wird für das Gerät <devicename> erzeugt. Der Parameter <diff-temp> ist optional.
      • Andernfalls wird das Ereignis "fan: off" erzeugt, wenn das Reading von "fan" nicht bereits "off" war.

      Beispiel:
          # Erzeugt das Ereignis "fan: on", wenn der Taupunkt des Geräts Aussen_1 zum ersten Mal
          # niedriger ist als der Taupunkt des Geräts basement_tempsensor und die 
          # Außentemperatur >= 0 ist und wechselt nach "fan: off" wenn diese Bedingungen nicht 
          # mehr zutreffen.
          # Schaltet den Schalter fan_switch abhängig vom Zustand ein oder aus.
          define dew_fan1 dewpoint fan basement_tempsensor Aussen_1 0
          define dew_fan1_on notify basement_tempsensor.*fan:.*on set fan_switch on
          define dew_fan1_off notify basement_tempsensor.*fan:.*off set fan_switch off
          
      define <name> dewpoint alarm <devicename> <devicename-reference> <diff-temp>

      • Erzeugt einen Schimmel-Alarm, wenn eine Referenz-Temperatur unter den Taupunkt fällt.
      • Erzeugt ein Reading/Ereignis "alarm: on" wenn die Temperatur von <devicename-reference> - <diff-temp> unter den Taupunkt von <devicename> fällt und das Reading "alarm" nicht bereits "on" ist. Das Ereignis wird für <devicename> erzeugt.
      • Erzeugt ein Reading/Ereignis "alarm: off" wenn die Temperatur von <devicename-reference> - <diff-temp> über den Taupunkt von <devicename> steigt und das Reading "alarm" nicht bereits "off" ist.

      Beispiel:
          # Es wird ein Anlegefühler (Wandsensor) und ein Thermo-/Hygrometer (Raumfühler)
          # verwendet, um einen Alarm zu erzeugen, wenn die Wandtemperatur
          # unter den Taupunkt der Luft fällt. In diesem Fall würde sich Wasser an der Wand
          # niederschlagen (kondensieren), weil die Wand zu kalt ist.
          # Der Schalter einer Sirene (alarm_siren) wird über ein notify geschaltet.
          define dew_alarm1 dewpoint alarm roomsensor wallsensor 0
          define roomsensor_alarm_on notify roomsensor.*alarm:.*on set alarm_siren on
          define roomsensor_alarm_off notify roomsensor.*alarm:.*off set alarm_siren off
      
          # Ohne Wandsensor lässt sich auch der Taupunkt eines Raums mit der Temperatur desselben
          # (oder eines anderen) Fühlers vergleichen.
          # Die Alarmtemperatur ist 5 Grad niedriger gesetzt als die des Vergleichsthermostats.
          define dev_alarm2 dewpoint alarm roomsensor roomsensor 5
          
    Set
      N/A

    Get
      N/A

    Attributes
    • disable
    • absoluteHumidity <reading_name>
      • Zusätzlich wird die absolute Feuchte in g/m³ als Reading <reading_name> berechnet.

    • vapourPressure <reading_name>
      • Zusätzlich wird der Dampfdruck in hPa als Reading <reading_name> berechnet.

    • max_timediff
      • Maximale erlaubter Zeitunterschied in Sekunden zwischen den Temperatur- und Luftfeuchtewerten eines Geräts. dewpoint verwendet Readings von Temperatur oder Luftfeuchte wenn sie nicht im Ereignis mitgeliefert werden. Das ist sowohl für den Betrieb mit event-on-change-reading nötig als auch bei Sensoren die Temperatur und Luftfeuchte in getrennten Ereignissen kommunizieren (z.B. Technoline Sensoren TX3TH).
        Der Standardwert ist 1 Sekunde.

        Beispiel:
                # Maximal erlaubter Zeitunterschied soll 60 Sekunden sein
                define dew_all dewpoint dewpoint .*
                attr dew_all max_timediff 60
                
=end html_DE =cut