98_rain.pm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. # $Id: 98_rain.pm 6916 2014-11-08 11:28:26Z baumrasen $
  2. ##############################################
  3. #
  4. # Rain computing
  5. #
  6. # based / modified from dewpoint.pm (C) by Rudolf Koenig
  7. #
  8. # Copyright (C) 2012 Andreas Vogt
  9. #
  10. # This program is free software; you can redistribute it and/or
  11. # modify it under the terms of the GNU General Public License
  12. # as published by the Free Software Foundation; either version 2
  13. # of the License, or (at your option) any later version.
  14. #
  15. # This program is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License
  21. # along with this program; if not, write to the Free Software
  22. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  23. #
  24. # The GNU General Public License may also be found at http://www.gnu.org/licenses/gpl-2.0.html .
  25. #
  26. package main;
  27. use strict;
  28. use warnings;
  29. use Time::Local;
  30. # Debug this module? YES = 1, NO = 0
  31. my $rain_debug = 0;
  32. ##########################
  33. sub
  34. rain_Initialize($)
  35. {
  36. my ($hash) = @_;
  37. $hash->{DefFn} = "rain_Define";
  38. $hash->{NotifyFn} = "rain_Notify";
  39. $hash->{NotifyOrderPrefix} = "10-"; # Want to be called before the rest
  40. $hash->{AttrList} = "disable:0,1 ".
  41. "DayChangeTime ".
  42. "CorrectionValue ".
  43. "DontUseIsRaining:1,0 ".
  44. $readingFnAttributes;
  45. }
  46. ##########################
  47. sub
  48. rain_Define($$)
  49. {
  50. my ($hash, $def) = @_;
  51. my @a = split("[ \t][ \t]*", $def);
  52. return "wrong syntax: define <name> rain devicename [rain_name] [israining_name] [new_name]"
  53. if(@a < 3);
  54. my $name = $a[0];
  55. my $devname = $a[2];
  56. if(@a == 6) {
  57. $hash->{RAIN_NAME} = $a[3];
  58. $hash->{ISRAINING_NAME} = $a[4];
  59. $hash->{NEW_NAME} = $a[5];
  60. } elsif (@a == 3) {
  61. $hash->{RAIN_NAME} = "rain";
  62. $hash->{ISRAINING_NAME} = "israining";
  63. $hash->{NEW_NAME} = "rain_calc";
  64. } else {
  65. return "wrong syntax: define <name> rain devicename-regex [rain_name israining_name new_name]"
  66. }
  67. eval { "Hallo" =~ m/^$devname$/ };
  68. return "Bad regecaxp: $@" if($@);
  69. $hash->{DEV_REGEXP} = $devname;
  70. $hash->{STATE} = "active";
  71. return undef;
  72. }
  73. ##########################
  74. sub
  75. rain_Notify($$)
  76. {
  77. my ($hash, $dev) = @_;
  78. my $hashName = $hash->{NAME};
  79. return "" if(AttrVal($hashName, "disable", undef));
  80. return "" if(!defined($hash->{DEV_REGEXP}));
  81. my @txt = ( "rain", "rain_h", "rain_d", "humidity", "temperature",
  82. "israining", "unknown1", "unknown2", "unknown3");
  83. my @sfx = ( "(counter)", "(l/m2)", "(km/h)", "(%)", "(Celsius)",
  84. "(yes/no)", "","","");
  85. my %repchanged = ("rain"=>1, "wind"=>1, "humidity"=>1, "temperature"=>1,
  86. "israining"=>1, "rain_all"=>1);
  87. # time
  88. my $tm = TimeNow();
  89. my $tsecs= time(); # number of non-leap seconds since January 1, 1970, UTC
  90. ##### disabled because of creating a READING rain in some definitions
  91. ### The next instr wont work for empty hashes, so we init it now
  92. # $dev->{READINGS}{$txt[0]}{VAL} = 0 if(!$dev->{READINGS});
  93. my $r = $dev->{READINGS};
  94. my $devName = $dev->{NAME};
  95. my $re = $hash->{DEV_REGEXP};
  96. # rain
  97. my $rain_name = "rain";
  98. my $israining_name = "israining";
  99. my $new_name = "rain_calc";
  100. # fan
  101. my $devname_out = "";
  102. my $min_rain = 0;
  103. # alarm
  104. my $devname_ref = "";
  105. my $diff_rain = 0;
  106. if (!defined($hash->{RAIN_NAME}) || !defined($hash->{ISRAINING_NAME}) || !defined($hash->{NEW_NAME})) {
  107. # should never happen!
  108. Log3 $hash, 1, "Error rain: RAIN_NAME || ISRAINING_NAME || NEW_NAME undefined";
  109. return "";
  110. }
  111. $rain_name = $hash->{RAIN_NAME};
  112. $israining_name = $hash->{ISRAINING_NAME};
  113. $new_name = $hash->{NEW_NAME};
  114. Log3 $hash, 5, "rain_notify: devname=$devName rainname=$hashName, dev=$devName, dev_regex=$re rain_name=$rain_name israining_name=$israining_name";
  115. my $DayChangeTime = "0730";
  116. my $DayChangeTimeHour = "07"; #use as checked value
  117. my $DayChangeTimeMinutes = "30"; #use as checked value
  118. my $HourChangeTimeMinutes = "30"; #use as checked value
  119. my $CorrectionValue = 1;
  120. my $DontUseIsRaining = 0;
  121. Log3 $hash, 1, "rain_notify: rain_Notify Defaults: DayChangeTime='$DayChangeTime' DontUseIsRaining='$DontUseIsRaining' CorrectionValue='$CorrectionValue'" if ($rain_debug == 1);
  122. if(defined($attr{$hashName}) &&
  123. defined($attr{$hashName}{"DayChangeTime"}) &&
  124. !($attr{$hashName}{"DayChangeTime"} eq "")) {
  125. my $DayChangeTimeCheck = $attr{$hashName}{"DayChangeTime"}; #do not overwrite the default value until value is check
  126. #(\d{2})(\d{2}) <-RegExp for 2x2 digits
  127. #([012][\d])([012345][\d]) <-RegExp for 4 digit with timecode
  128. #\([012][\d]\)\([012345][\d]\) <-RegExp for 4 digit with timecode
  129. if ($DayChangeTimeCheck =~ /([012][\d])([012345][\d])/) {
  130. #my $FistDigits = $DayChangeTimeCheck =~ s/([012][\d])([012345][\d])/$1/ ;
  131. #my $SecondDigits = $DayChangeTimeCheck =~ s/([012][\d])([012345][\d])/$2/ ;
  132. $DayChangeTimeHour = $1;
  133. $DayChangeTimeMinutes = $2;
  134. $HourChangeTimeMinutes = $DayChangeTimeMinutes;
  135. Log3 $hash, 4, "Attribut matchs TimeCode DayChangeTime='$DayChangeTimeHour:$DayChangeTimeMinutes' ";
  136. # tue etwas ...
  137. }
  138. else
  139. {
  140. Log3 $hash, 1, "Attribut DayChangeTime is not a correct timecode. will use '$DayChangeTimeHour:$DayChangeTimeMinutes' ";
  141. }
  142. Log3 $hash, 1, "rain_notify: rain_Notify Attribut use DayChangeTime='$DayChangeTime' " if ($rain_debug == 1);
  143. }
  144. #my $cache = AttrVal($hashName, "DayChangeTime", undef);
  145. #if(defined($cache)){
  146. #AttrVal($hashName, "DayChangeTime", "");
  147. # Log3 $hash, 1, "rain_notify: rain_Notify D Attribut defined CacheDayChangeTime='$cache' " if ($rain_debug == 1);
  148. #}
  149. #my $cache= (AttrVal($hash->{RAIN_NAME},"DayChangeTime","")) ? "default" : (AttrVal($hash->{RAIN_NAME},"DayChangeTime",""));
  150. #Log3 $hash, 1, "rain_notify: rain_Notify D Attribut defined CacheDayChangeTime='$cache' " if ($rain_debug == 1);
  151. if(defined($attr{$hashName}) &&
  152. defined($attr{$hashName}{"CorrectionValue"}) &&
  153. !($attr{$hashName}{"CorrectionValue"} eq "")) {
  154. $CorrectionValue = $attr{$hashName}{"CorrectionValue"};
  155. Log3 $hash, 1, "rain_notify: rain_Notify Attribut defined CorrectionValue='$CorrectionValue' " if ($rain_debug == 1);
  156. }
  157. if(defined($attr{$hashName}) &&
  158. defined($attr{$hashName}{"DontUseIsRaining"}) &&
  159. !($attr{$hashName}{"DontUseIsRaining"} eq "")) {
  160. $DontUseIsRaining = $attr{$hashName}{"DontUseIsRaining"};
  161. Log3 $hash, 1, "rain_notify: rain_Notify Attribut defined DontUseIsRaining='$DontUseIsRaining' " if ($rain_debug == 1);
  162. }
  163. Log3 $hash, 1, "rain_notify: rain_Notify DayChangeTime='$DayChangeTimeHour:$DayChangeTimeMinutes' DontUseIsRaining='$DontUseIsRaining' CorrectionValue='$CorrectionValue'" if ($rain_debug == 1);
  164. $rain_name = $hash->{RAIN_NAME};
  165. my $max = int(@{$dev->{CHANGED}});
  166. my $n = -1;
  167. my $lastval;
  168. return "" if($devName !~ m/^$re$/);
  169. Log3 $hash, 1, "rain_notify: max='$max'" if ($rain_debug == 1);
  170. my $rain_value = "";
  171. my $israining = "";
  172. for (my $i = 0; $i < $max; $i++) {
  173. my $s = $dev->{CHANGED}[$i];
  174. Log3 $hash, 1, "rain_notify: s='$s'" if ($rain_debug == 1);
  175. ################
  176. # Filtering
  177. next if(!defined($s));
  178. my ($evName, $val, $rest) = split(" ", $s, 3); # resets $1
  179. next if(!defined($evName));
  180. next if(!defined($val));
  181. Log3 $hash, 1, "rain_notify: evName='$evName' val=$val'" if ($rain_debug == 1);
  182. if (($evName eq "R:") && ($rain_name eq "R")) {
  183. $n = $i;
  184. #my ($evName1, $val1, $evName2, $val2, $rest) = split(" ", $s, 5); # resets $1
  185. #$lastval = $evName1." ".$val1." ".$evName2." ".$val2;
  186. $lastval = $s;
  187. if ($s =~ /T: [-+]?([0-9]*\.[0-9]+|[0-9]+)/) {
  188. $rain_value = $1;
  189. }
  190. if ($s =~ /H: [-+]?([0-9]*\.[0-9]+|[0-9]+)/) {
  191. $israining = $1;
  192. }
  193. Log3 $hash, 1, "rain_notify T: H:, rain=$rain_value unit=$israining" if ($rain_debug == 1);
  194. } elsif ($evName eq $rain_name.":") {
  195. $rain_value = $val;
  196. Log3 $hash, 1, "rain_notify rain_value! rain=$rain_value" if ($rain_debug == 1);
  197. } elsif ($evName eq $israining_name.":") {
  198. $israining = $val;
  199. Log3 $hash, 1, "rain_notify israining! unit=$israining" if ($rain_debug == 1);
  200. }
  201. }
  202. #if Attribut DontUSeIsRaining is set to 1 - set israining also to 1 / ignors device entry
  203. $israining = 1 if ($DontUseIsRaining == 1);
  204. Log3 $hash, 3, "rain_notify: n='$n'" if ($rain_debug == 1);
  205. Log3 $hash, 3, "rain_notify: rain_name='$rain_name'" if ($rain_debug == 1);
  206. if ($n == -1) { $n = $max; }
  207. Log3 $hash, 5, "rain_notify: get the following values rain_value=$rain_value " . ($rain_value eq "") . " israining=$israining " . ($israining eq "") if ($rain_debug == 1);
  208. if (($rain_value eq "") || ($israining eq "")) { Log3 $hash, 1, "rain_notify: no values for calculation found!"; }
  209. if (($rain_value eq "") || ($israining eq "")) { return undef; } # no way to calculate rain!
  210. # We found rain_value and israining. so we can calculate rain first
  211. # my $rain = sprintf("%.1f", rain($rain_value,$israining));
  212. my $rain = sprintf("%.1f", $rain_value * $CorrectionValue);
  213. Log3 $hash, 1, "rain_notify: rain=$rain" if ($rain_debug == 1);
  214. # >define <name> rain <devicename> [<rain_name> <israining_name> <new_name>]
  215. #
  216. # Calculates rain for device <devicename> from rain_value and israining and write it
  217. # to new Reading rain.
  218. # If optional <rain_name>, <israining_name> and <newname> is specified
  219. # then read rain_value from reading <rain_name>, israining from reading <israining_name>
  220. # and write rain to reading <rain_name>.
  221. # if rain_name eq "R" then use rain_value from state T: H: R:, add <newname> to the state
  222. # Example:
  223. # define raintest1 rain rain .*
  224. # define raintest2 rain rain .* T H D
  225. my $sensor = $new_name;
  226. my $current;
  227. $current = $rain;
  228. # $dev->{READINGS}{$sensor}{TIME} = $tm;
  229. # $dev->{READINGS}{$sensor}{VAL} = $current;
  230. # $dev->{CHANGED}[$n++] = $sensor . ": " . $current;
  231. my $rain_value_prev=0;
  232. my $rain_h_last=0;
  233. my $rain_h_curr=0;
  234. my $rain_h_start;
  235. my $rain_d_last=0;
  236. my $rain_d_curr=0;
  237. my $rain_d_start;
  238. my $rain_h_trig_tsecs;
  239. my $rain_d_trig_tsecs;
  240. my $rain_tsecs_prev;
  241. # get previous tsecs
  242. if(defined($r->{$sensor ."_tsecs"})) {
  243. $rain_tsecs_prev= $r->{$sensor ."_tsecs"}{VAL};
  244. } else{
  245. $rain_tsecs_prev= 0; # 1970-01-01
  246. }
  247. $r->{$sensor ."_tsecs"}{TIME} = $tm;
  248. $r->{$sensor ."_tsecs"}{VAL} = $tsecs;
  249. $dev->{CHANGED}[$n++] = $sensor . "_tsecs: " . $tsecs;
  250. #TODO there should be a handling for new created devices (rain is existing with a large value for the last day)
  251. #TODO there should be a handling batterie replacement (rain could not be negativ)
  252. #TODO is the value "israining" needed?
  253. # get previous value
  254. if(defined($r->{$sensor ."_now_value"})) {
  255. $rain_value_prev= $r->{$sensor ."_now_value"}{VAL};
  256. } else{
  257. $rain_value_prev= 0; # 0
  258. }
  259. $r->{$sensor ."_now_value"}{TIME} = $tm;
  260. $r->{$sensor ."_now_value"}{VAL} = $current;
  261. $dev->{CHANGED}[$n++] = $sensor . "_now_value: " . $current;
  262. my $rain_diff = $current - $rain_value_prev;
  263. $r->{$sensor ."_now_diff"}{TIME} = $tm;
  264. $r->{$sensor ."_now_diff"}{VAL} = $rain_diff;
  265. $dev->{CHANGED}[$n++] = $sensor . "_now_diff: " . $rain_diff;
  266. # get previous tsecs
  267. if(defined($r->{$sensor ."_h_start"})) {
  268. $rain_h_start= $r->{$sensor ."_h_start"}{VAL};
  269. } else{
  270. $rain_h_start= 0; # 1970-01-01
  271. }
  272. # get previous tsecs
  273. if(defined($r->{$sensor ."_d_start"})) {
  274. $rain_d_start= $r->{$sensor ."_d_start"}{VAL};
  275. } else{
  276. $rain_d_start= 0; # 1970-01-01
  277. }
  278. # get previous rain_h_last
  279. if(defined($r->{$sensor ."_h_last"})) {
  280. $rain_h_last= $r->{$sensor ."_h_last"}{VAL};
  281. } else{
  282. $rain_h_last= 0;
  283. }
  284. # get previous rain_d_last
  285. if(defined($r->{$sensor ."_d_last"})) {
  286. $rain_d_last= $r->{$sensor ."_d_last"}{VAL};
  287. } else{
  288. $rain_d_last= 0;
  289. }
  290. # get previous tsecs
  291. if(defined($r->{$sensor ."_h_trig_tsecs"})) {
  292. $rain_h_trig_tsecs= $r->{$sensor ."_h_trig_tsecs"}{VAL};
  293. } else{
  294. $rain_h_trig_tsecs= 0; # 1970-01-01
  295. }
  296. # get previous tsecs
  297. if(defined($r->{$sensor ."_d_trig_tsecs"})) {
  298. $rain_d_trig_tsecs= $r->{$sensor ."_d_trig_tsecs"}{VAL};
  299. } else{
  300. $rain_d_trig_tsecs= 0; # 1970-01-01
  301. }
  302. Log3 $hash, 1, "get rain_h_trig IS " . localtime($rain_h_trig_tsecs) if ($rain_debug == 1);
  303. Log3 $hash, 1, "get rain_d_trig IS " . localtime($rain_d_trig_tsecs) if ($rain_debug == 1);
  304. # look forward to the next hour trigger event
  305. my @th=localtime($tsecs+1800);
  306. # time for the hour-trigger (every houre at) 30 min by default
  307. #my $rain_h_trig=sprintf("%04d-%02d-%02d_%02d:%02d",$th[5]+1900,$th[4]+1,$th[3],$th[2],"30");
  308. my $rain_h_trig=sprintf("%04d-%02d-%02d_%02d:%02d",$th[5]+1900,$th[4]+1,$th[3],$th[2],$HourChangeTimeMinutes);
  309. Log3 $hash, 1, "NEW rain_h_trigger would be = $rain_h_trig" if ($rain_debug == 1);
  310. Log3 $hash, 1, "rain_h_trigger_tsecs = $rain_h_trig_tsecs" if ($rain_debug == 1);
  311. Log3 $hash, 1, "secunds until hour-reset = " . ($rain_h_trig_tsecs-$tsecs) if ($rain_debug == 1);
  312. if (($rain_h_trig_tsecs-$tsecs)>3600){ # something is wrong
  313. ### debughelper -->
  314. #$DB::single = 1;
  315. Log3 $hash, 1, "something is wrong! the diff until next reset should not be greater than one hour. Now set New Trigger" if ($rain_debug == 1);
  316. #my @timeData = gmtime(time);
  317. #Debug "timeData: ". join(' ', @timeData);
  318. #my @utcData = utcdate(time);
  319. #Debug "utcData: ". join(' ', @utcData);
  320. #my @gmData = gmtime(time);
  321. #Debug "gmData: ". join(' ', @gmData);
  322. #TODO should be 5:30 UTC?
  323. #$rain_h_trig_tsecs = timelocal(0,30,7,$th[3],$th[4],$th[5]+1900);
  324. $rain_h_trig_tsecs = timelocal(0,$DayChangeTimeMinutes,$DayChangeTimeHour,$th[3],$th[4],$th[5]+1900);
  325. # remember $rain_d_trig_tsecs / trigger-time for next event to zero rain
  326. $r->{$sensor ."_h_trig_tsecs"}{TIME} = $tm;
  327. $r->{$sensor ."_h_trig_tsecs"}{VAL} = "$rain_h_trig_tsecs";
  328. }
  329. if($tsecs>$rain_h_trig_tsecs){ # wenn now groesser ist, als der letzte trigger-wert, dann beginnt eine neue einheit
  330. Log3 $hash, 1, "Detect new rain hour!" if ($rain_debug == 1);
  331. Log3 $hash, 1, "NEW rain_h_trigger IS = $rain_h_trig" if ($rain_debug == 1);
  332. #$time = timelocal($sec,$min,$hour,$mday,$mon,$year);
  333. #$rain_h_trig_tsecs = timelocal(0,30,$th[2],$th[3],$th[4],$th[5]+1900);
  334. $rain_h_trig_tsecs = timelocal(0,$HourChangeTimeMinutes,$th[2],$th[3],$th[4],$th[5]+1900);
  335. Log3 $hash, 1, "rain_h_trigger_tsecs = $rain_h_trig_tsecs" if ($rain_debug == 1);
  336. #$rain_h_last = sprintf("%0.1f", ($rain_raw_adj-$rain_raw_h_start) * $def->{RAINUNIT} / 1000);
  337. $rain_h_last = sprintf("%0.1f", $current-$rain_h_start);
  338. # remember $rain_h_last
  339. $r->{$sensor ."_h_last"}{TIME} = $tm;
  340. $r->{$sensor ."_h_last"}{VAL} = "$rain_h_last";
  341. # set new rain_raw_hour_start_value
  342. $rain_h_start = $current;
  343. # remember $rain_raw_h_start
  344. $r->{$sensor ."_h_start"}{TIME} = $tm;
  345. $r->{$sensor ."_h_start"}{VAL} = "$rain_h_start";
  346. # remember $rain_h_trig_tsecs / trigger-time for next event to zero rain
  347. $r->{$sensor ."_h_trig_tsecs"}{TIME} = $tm;
  348. $r->{$sensor ."_h_trig_tsecs"}{VAL} = "$rain_h_trig_tsecs";
  349. }
  350. # look forward to the next day trigger event
  351. @th=localtime($tsecs+86400);
  352. # the time for the day-trigger: 7:30 Uhr
  353. #my $rain_d_trig=sprintf("%04d-%02d-%02d_%02d:%02d",$th[5]+1900,$th[4]+1,$th[3],"7","30");
  354. my $rain_d_trig=sprintf("%04d-%02d-%02d_%02d:%02d",$th[5]+1900,$th[4]+1,$th[3],$DayChangeTimeHour,$DayChangeTimeMinutes);
  355. Log3 $hash, 1, "NEW rain_d_trigger would be= $rain_d_trig" if ($rain_debug == 1);
  356. Log3 $hash, 1, "rain_d_trigger_tsecs = $rain_d_trig_tsecs" if ($rain_debug == 1);
  357. Log3 $hash, 1, "secunds until day-reset = " . ($rain_d_trig_tsecs-$tsecs) if ($rain_debug == 1);
  358. if (($rain_d_trig_tsecs-$tsecs)>86400){ # something is wrong
  359. Log3 $hash, 1, "something is wrong! the diff until next reset should not be greater than one day. Now set New Trigger" if ($rain_debug == 1);
  360. #$rain_d_trig_tsecs = timelocal(0,30,7,$th[3],$th[4],$th[5]+1900);
  361. $rain_d_trig_tsecs = timelocal(0,$DayChangeTimeMinutes,$DayChangeTimeHour,$th[3],$th[4],$th[5]+1900);
  362. # remember $rain_d_trig_tsecs / trigger-time for next event to zero rain
  363. $r->{$sensor ."_d_trig_tsecs"}{TIME} = $tm;
  364. $r->{$sensor ."_d_trig_tsecs"}{VAL} = "$rain_d_trig_tsecs";
  365. }
  366. if($tsecs>$rain_d_trig_tsecs){
  367. Log3 $hash, 1, "Detect new rain day!" if ($rain_debug == 1);
  368. Log3 $hash, 1, "NEW rain_d_trigger IS= $rain_d_trig" if ($rain_debug == 1);
  369. # $time = timelocal($sec,$min,$hour,$mday,$mon,$year);
  370. #$rain_d_trig_tsecs = timelocal(0,30,7,$th[3],$th[4],$th[5]+1900);
  371. $rain_d_trig_tsecs = timelocal(0,$DayChangeTimeMinutes,$DayChangeTimeHour,$th[3],$th[4],$th[5]+1900);
  372. Log3 $hash, 1, "rain_d_trigger_tsecs = $rain_d_trig_tsecs" if ($rain_debug == 1);
  373. $rain_d_last = sprintf("%0.1f", ($current-$rain_d_start));
  374. # remember $rain_h_last
  375. $r->{$sensor ."_d_last"}{TIME} = $tm;
  376. $r->{$sensor ."_d_last"}{VAL} = "$rain_d_last";
  377. # set new rain_raw_day_start_value
  378. $rain_d_start=$current;
  379. # remember $rain_raw_h_start
  380. $r->{$sensor ."_d_start"}{TIME} = $tm;
  381. $r->{$sensor ."_d_start"}{VAL} = "$rain_d_start";
  382. # remember $rain_d_trig_tsecs / trigger-time for next event to zero rain
  383. $r->{$sensor ."_d_trig_tsecs"}{TIME} = $tm;
  384. $r->{$sensor ."_d_trig_tsecs"}{VAL} = "$rain_d_trig_tsecs";
  385. }
  386. $rain_h_curr = sprintf("%0.1f", ($current-$rain_h_start));
  387. #remember $rain_raw_h_start
  388. $r->{$sensor ."_h_curr"}{TIME} = $tm;
  389. $r->{$sensor ."_h_curr"}{VAL} = $rain_h_curr;
  390. $rain_d_curr = sprintf("%0.1f", ($current-$rain_d_start));
  391. #remember $rain_raw_d_start
  392. $r->{$sensor ."_d_curr"}{TIME} = $tm;
  393. $r->{$sensor ."_d_curr"}{VAL} = $rain_d_curr;
  394. Log3 $hash, 1, "Rain Curr h: $rain_h_curr / Rain Last h: $rain_h_last" if ($rain_debug == 1);
  395. Log3 $hash, 1, "Rain Curr d: $rain_d_curr / Rain Last d: $rain_d_last" if ($rain_debug == 1);
  396. Log3 $hash, 1, "r1(prev) and r2: $rain_value_prev / $current" if ($rain_debug == 1);
  397. my $tsecs_dif = $tsecs-$rain_tsecs_prev;
  398. my $rain_now_rate=0;
  399. if ($tsecs_dif!=0){
  400. $rain_now_rate=sprintf("%0.1f",($current-$rain_value_prev)*3600/$tsecs_dif);
  401. }
  402. Log3 $hash, 1, "rdif r2-r1=" . ($current-$rain_value_prev) if ($rain_debug == 1);
  403. Log3 $hash, 1, "rain_nowrate (tsec_dif=". ($tsecs_dif) .") $rain_now_rate" if ($rain_debug == 1);
  404. # remember $rain_d_trig_tsecs / trigger-time for next event to zero rain
  405. $r->{$sensor ."_now_rate"}{TIME} = $tm;
  406. $r->{$sensor ."_now_rate"}{VAL} = "$rain_now_rate";
  407. # For logging/summary
  408. my $rain_all = "cH: $rain_h_curr lH: $rain_h_last cD: $rain_d_curr lD: $rain_d_last IR: $israining Rnow: $rain_now_rate Rdif: $rain_diff";
  409. # Log GetLogLevel($def->{NAME},4), "KS300 $dev: $rain_all" if ($rain_debug == 1);
  410. Log3 $hash, 1, "$rain_all" if ($rain_debug == 1);
  411. # remember rain
  412. $r->{$sensor ."_all"}{TIME} = $tm;
  413. $r->{$sensor ."_all"}{VAL} = "$rain_all";
  414. #$dev->{STATE} = $val;
  415. $dev->{CHANGED}[$n++] = $sensor ."_all: $rain_all";
  416. Log3 $hash, 1, "rain_notify: current=$current" if ($rain_debug == 1);
  417. return undef;
  418. }
  419. 1;
  420. =pod
  421. =begin html
  422. <a name="rain"></a>
  423. <h3>rain</h3>
  424. <ul>
  425. Rain calculations. Offers different values from a rain sensor. <br>
  426. <a name="raindefine"></a>
  427. <b>Define</b>
  428. <ul>
  429. <code>define &lt;name&gt; rain &lt;devicename-regex&gt; [&lt;rain_name&gt; &lt;israining_name&gt; &lt;new_name&gt;]</code><br>
  430. <br>
  431. <ul>
  432. Calculates rain values for device &lt;devicename-regex&gt; from incremental rain-value and israining-state
  433. and write it to some new readings named rain_calc_???????.
  434. If optional &lt;rain_name&gt;, &lt;israining_name&gt; and &lt;new_name&gt; is specified
  435. then read rain from reading &lt;rain_name&gt;, israining from reading &lt;israining_name&gt;
  436. and write the calculated rain to reading &lt;new_name&gt;.
  437. </ul>
  438. The following values are generated:
  439. <ul>
  440. <li>rain_calc_all --> all values in one line</li>
  441. <li>rain_calc_d_curr --> liter rain at the current day (from 7:30 local time)</li>
  442. <li>rain_calc_d_last --> liter rain of 24h before 7:30 local time</li>
  443. <li>rain_calc_d_start --> first incremental rain value from the rain device after 7:30 local time</li>
  444. <li>rain_calc_h_curr --> liter rain at the current hour (from XX:30)</li>
  445. <li>rain_calc_h_last --> liter rain of 1 hour before the last XX:30 time</li>
  446. <li>rain_calc_h_start --> first incremental rain value from the rain device after last XX:30</li>
  447. <li>rain_calc_now_diff --> fallen rain in liter since last value from rain device</li>
  448. <li>rain_calc_now_rate --> fallen rain in liter/hour since last value from rain device</li>
  449. </ul>
  450. <br>
  451. Example:<PRE>
  452. # Compute the rain for the rain/israining
  453. # events of the ks300 device and generate reading rain_calc.
  454. define rain_ks300 rain ks300
  455. </PRE>
  456. </ul>
  457. <a name="rainset"></a>
  458. <b>Set</b> <ul>N/A</ul><br>
  459. <a name="rainget"></a>
  460. <b>Get</b> <ul>N/A</ul><br>
  461. <a name="rainattr"></a>
  462. <b>Attributes</b>
  463. <ul>
  464. <li><a href="#disable">disable</a></li>
  465. <li>DontUseIsRaining 0/1
  466. <br>
  467. Don't use the devicevalue IsRaining, if set to 1
  468. </li>
  469. <li>DayChangeTime HHMM
  470. <br>
  471. Change the default (day)time of the 'set value to zero' time (use the timecode as four digits!)
  472. <br>
  473. The minutevalue is used to set the (hour)time of the 'set value to zero' time
  474. </li>
  475. <li>CorrectionValue 1
  476. <br>
  477. Use this value if you wish to do a correction of the rain-device-values. It is used as an factor. The value 1 will not change anything.
  478. </li>
  479. <br>
  480. </ul>
  481. </ul>
  482. =end html
  483. =cut