33_readingsChange.pm 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. ##############################################
  2. # $Id: 33_readingsChange.pm 15609 2017-12-14 22:19:18Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use vars qw($FW_ME); # webname (default is fhem)
  7. #####################################
  8. sub
  9. readingsChange_Initialize($)
  10. {
  11. my ($hash) = @_;
  12. $hash->{DefFn} = "readingsChangeDefine";
  13. $hash->{NotifyFn} = "readingsChangeExec";
  14. $hash->{AttrList} ="disable:1,0 disabledForIntervals addStateEvent:1,0";
  15. $hash->{NotifyOrderPrefix} = "00-"; # be the first
  16. }
  17. #####################################
  18. sub
  19. readingsChangeDefine($$)
  20. {
  21. my ($hash, $def) = @_;
  22. my ($name, $type, @re) = split("[ \t]+", $def, 6);
  23. return "Usage: define <name> readingsChange ".
  24. "<device> <readingName> <toReplace> <replaceWith>"
  25. if(int(@re) != 4);
  26. $hash->{".re"} = \@re;
  27. # Checking for misleading regexps
  28. for(my $idx = 0; $idx < 3; $idx++) {
  29. my $re = $re[$idx];
  30. return "Bad regexp: starting with *" if($re =~ m/^\*/);
  31. eval { "Hallo" =~ m/^$re$/ };
  32. return "Bad regexp $re: $@" if($@);
  33. }
  34. if($re[3] =~ m/^{.*}/) {
  35. $hash->{".isPerl"} = 1;
  36. my %specials= ();
  37. my $err = perlSyntaxCheck($re[3], %specials);
  38. return "$re[3]: $err" if($err);
  39. }
  40. readingsSingleUpdate($hash, "state", "active", 0);
  41. notifyRegexpChanged($hash, $re[0]);
  42. return undef;
  43. }
  44. #####################################
  45. sub
  46. readingsChangeExec($$)
  47. {
  48. my ($rc, $dev) = @_;
  49. my $SELF = $rc->{NAME};
  50. return "" if(IsDisabled($SELF));
  51. my $re = $rc->{".re"};
  52. my $NAME = $dev->{NAME};
  53. return if($NAME !~ m/$re->[0]/ || !$dev->{READINGS});
  54. my $events = deviceEvents($dev, AttrVal($SELF, "addStateEvent", 0));
  55. return if(!$events);
  56. my $max = int(@{$events});
  57. my $matched=0;
  58. for (my $i = 0; $i < $max; $i++) {
  59. my $EVENT = $events->[$i];
  60. next if(!defined($EVENT) || $EVENT !~ m/^([^ ]+): (.+)/);
  61. my ($rg, $val) = ($1, $2);
  62. next if($rg !~ m/$re->[1]/ || !$dev->{READINGS}{$rg});
  63. Log3 $SELF, 5, "Changing $NAME:$rg $val via $SELF";
  64. $matched++;
  65. if($rc->{".isPerl"}) {
  66. eval "\$val =~ s/$re->[2]/$re->[3]/ge";
  67. } else {
  68. eval "\$val =~ s/$re->[2]/$re->[3]/g";
  69. }
  70. $events->[$i] = "$rg: $val";
  71. $dev->{READINGS}{$rg}{VAL} = $val;
  72. }
  73. evalStateFormat($dev) if($matched);
  74. return undef;
  75. }
  76. 1;
  77. =pod
  78. =item helper
  79. =item summary modify reading value upon change
  80. =item summary_DE Reading-Werte modifizieren bei &Auml;nderung
  81. =begin html
  82. <a name="readingsChange"></a>
  83. <h3>readingsChange</h3>
  84. <ul>
  85. <br>
  86. <a name="readingsChangedefine"></a>
  87. <b>Define</b>
  88. <ul>
  89. <code>define &lt;name&gt; readingsChange &lt;device&gt; &lt;readingName&gt;
  90. &lt;toReplace&gt; &lt;replaceWith&gt;"</code>
  91. <br><br>
  92. Change the content of a reading if it changes, with the perl string
  93. substitute mechanism. Note: As some modules rely on the known format of
  94. some readings, changing such readings may cause these modules to stop
  95. working.
  96. <br><br>
  97. &lt;device&gt;, &lt;readingName&gt; and &lt;toReplace&gt; are regular
  98. expressions, and are not allowed to contain whitespace.
  99. If replaceWith is enclosed in {}, then the content will be executed as a
  100. perl expression for each match.<br>
  101. Notes:<ul>
  102. <li>after a Reading is set by a module, first the event-* attributes are
  103. evaluated, then userReadings, then stateFormat, then the
  104. readingsChange definitions (in alphabetical order), and after this the
  105. notifies, FileLogs, etc. again in alphabetical order.</li>
  106. <li>if stateFormat for the matched device is set, then it will be
  107. executed multiple times: once before the readingsChange, and once for
  108. every matching readingsChange.</li>
  109. </ul>
  110. <br><br>
  111. Examples:
  112. <ul><code>
  113. # shorten the reading power 0.5 W previous: 0 delta_time: 300<br>
  114. # to just power 0.5 W<br>
  115. define pShort readingsChange pm power (.*W).* $1<br>
  116. <br>
  117. # format each decimal number in the power reading to 2 decimal places<br>
  118. define p2dec readingsChange pm power (\d+\.\d+) {sprintf("%0.2f", $1)}
  119. </code></ul>
  120. </ul>
  121. <br>
  122. <a name="readingsChangeset"></a>
  123. <b>Set</b> <ul>N/A</ul><br>
  124. <a name="readingsChangeget"></a>
  125. <b>Get</b> <ul>N/A</ul><br>
  126. <a name="readingsChangeattr"></a>
  127. <b>Attributes</b>
  128. <ul>
  129. <li><a href="#disable">disable</a></li>
  130. <li><a href="#disabledForIntervals">disabledForIntervals</a></li>
  131. <li><a href="#addStateEvent">addStateEvent</a></li>
  132. </ul>
  133. <br>
  134. </ul>
  135. =end html
  136. =cut