99_Utils.pm 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. ##############################################
  2. # $Id: 99_Utils.pm 15713 2017-12-28 11:01:02Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. sub
  7. Utils_Initialize($$)
  8. {
  9. my ($hash) = @_;
  10. }
  11. sub
  12. time_str2num($)
  13. {
  14. my ($str) = @_;
  15. my @a;
  16. if($str) {
  17. @a = split("[T: -]", $str);
  18. return mktime($a[5],$a[4],$a[3],$a[2],$a[1]-1,$a[0]-1900,0,0,-1);
  19. } else {
  20. my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  21. return mktime($sec, $min, $hour, $mday, $mon, $year, 0, 0, -1);
  22. }
  23. }
  24. sub
  25. min($@)
  26. {
  27. my ($min, @vars) = @_;
  28. for (@vars) {
  29. $min = $_ if $_ lt $min;
  30. }
  31. return $min;
  32. }
  33. sub
  34. max($@)
  35. {
  36. my ($max, @vars) = @_;
  37. for (@vars) {
  38. $max = $_ if $_ gt $max;
  39. }
  40. return $max;
  41. }
  42. sub
  43. minNum($@)
  44. {
  45. my ($min, @vars) = @_;
  46. for (@vars) {
  47. $min = $_ if $_ < $min;
  48. }
  49. return $min;
  50. }
  51. sub
  52. maxNum($@)
  53. {
  54. my ($max, @vars) = @_;
  55. for (@vars) {
  56. $max = $_ if $_ > $max;
  57. }
  58. return $max;
  59. }
  60. sub
  61. abstime2rel($)
  62. {
  63. my ($h,$m,$s) = split(":", shift);
  64. $m = 0 if(!$m);
  65. $s = 0 if(!$s);
  66. my $t1 = 3600*$h+60*$m+$s;
  67. my @now = localtime;
  68. my $t2 = 3600*$now[2]+60*$now[1]+$now[0];
  69. my $diff = $t1-$t2;
  70. $diff += 86400 if($diff <= 0);
  71. return sprintf("%02d:%02d:%02d", $diff/3600, ($diff/60)%60, $diff%60);
  72. }
  73. sub
  74. defInfo($;$)
  75. {
  76. my ($search,$internal) = @_;
  77. $internal = 'DEF' unless defined($internal);
  78. my @ret;
  79. my @etDev = devspec2array($search);
  80. foreach my $d (@etDev) {
  81. next unless $d;
  82. next if($d eq $search && !$defs{$d});
  83. push @ret, $defs{$d}{$internal};
  84. }
  85. return @ret;
  86. }
  87. my ($SVG_lt, $SVG_ltstr);
  88. sub
  89. SVG_time_to_sec($)
  90. {
  91. my ($str) = @_;
  92. if(!$str) {
  93. return 0;
  94. }
  95. my ($y,$m,$d,$h,$mi,$s) = split("[-_:]", $str);
  96. $s = 0 if(!$s);
  97. $mi= 0 if(!$mi);
  98. $h = 0 if(!$h);
  99. $d = 1 if(!$d);
  100. $m = 1 if(!$m);
  101. if(!$SVG_ltstr || $SVG_ltstr ne "$y-$m-$d-$h") { # 2.5x faster
  102. $SVG_lt = mktime(0,0,$h,$d,$m-1,$y-1900,0,0,-1);
  103. $SVG_ltstr = "$y-$m-$d-$h";
  104. }
  105. return $s+$mi*60+$SVG_lt;
  106. }
  107. ######## trim #####################################################
  108. # What : cuts blankspaces from the beginning and end of a string
  109. # Call : { trim(" Hello ") }
  110. # Source: http://www.somacon.com/p114.php ,
  111. # http://www.fhemwiki.de/wiki/TRIM-Funktion-Anfangs/EndLeerzeichen_aus_Strings_entfernen
  112. sub trim($)
  113. {
  114. my $string = shift;
  115. $string =~ s/^\s+//;
  116. $string =~ s/\s+$//;
  117. return $string;
  118. }
  119. ######## ltrim ####################################################
  120. # What : cuts blankspaces from the beginning of a string
  121. # Call : { ltrim(" Hello") }
  122. # Source: http://www.somacon.com/p114.php ,
  123. # http://www.fhemwiki.de/wiki/TRIM-Funktion-Anfangs/EndLeerzeichen_aus_Strings_entfernensub ltrim($)
  124. sub ltrim($)
  125. {
  126. my $string = shift;
  127. $string =~ s/^\s+//;
  128. return $string;
  129. }
  130. ######## rtrim ####################################################
  131. # What : cuts blankspaces from the end of a string
  132. # Call : { rtrim("Hello ") }
  133. # Source: http://www.somacon.com/p114.php ,
  134. # http://www.fhemwiki.de/wiki/TRIM-Funktion-Anfangs/EndLeerzeichen_aus_Strings_entfernensub ltrim($)
  135. sub rtrim($)
  136. {
  137. my $string = shift;
  138. $string =~ s/\s+$//;
  139. return $string;
  140. }
  141. ######## UntoggleDirect ###########################################
  142. # What : For devices paired directly, converts state 'toggle' into 'on' or 'off'
  143. # Call : { UntoggleDirect("myDevice") }
  144. # define untoggle_myDevice notify myDevice { UntoggleDirect("myDevice") }
  145. # Source: http://www.fhemwiki.de/wiki/FS20_Toggle_Events_auf_On/Off_umsetzen
  146. sub UntoggleDirect($)
  147. {
  148. my ($obj) = shift;
  149. Log 4, "UntoggleDirect($obj)";
  150. if (Value($obj) eq "toggle"){
  151. if (OldValue($obj) eq "off") {
  152. {fhem ("setstate ".$obj." on")}
  153. }
  154. else {
  155. {fhem ("setstate ".$obj." off")}
  156. }
  157. }
  158. else {
  159. {fhem "setstate ".$obj." ".Value($obj)}
  160. }
  161. }
  162. ######## UntoggleIndirect #########################################
  163. # What : For devices paired indirectly, switches the target device 'on' or 'off' also when a 'toggle' was sent from the source device
  164. # Call : { UntoggleIndirect("mySensorDevice","myActorDevice","50%") }
  165. # define untoggle_mySensorDevice_myActorDevice notify mySensorDevice { UntoggleIndirect("mySensorDevice","myActorDevice","50%%") }
  166. # Source: http://www.fhemwiki.de/wiki/FS20_Toggle_Events_auf_On/Off_umsetzen
  167. sub UntoggleIndirect($$$)
  168. {
  169. my ($sender, $actor, $dimvalue) = @_;
  170. Log 4, "UntoggleIndirect($sender, $actor, $dimvalue)";
  171. if (Value($sender) eq "toggle")
  172. {
  173. if (Value($actor) eq "off") {fhem ("set ".$actor." on")}
  174. else {fhem ("set ".$actor." off")}
  175. }
  176. ## workaround for dimming currently not working with indirect pairing
  177. ## (http://culfw.de/commandref.html: "TODO/Known BUGS - FS20 dim commands should not repeat.")
  178. elsif (Value($sender) eq "dimup") {fhem ("set ".$actor." dim100%")}
  179. elsif (Value($sender) eq "dimdown") {fhem ("set ".$actor." ".$dimvalue)}
  180. elsif (Value($sender) eq "dimupdown")
  181. {
  182. if (Value($actor) eq $dimvalue) {fhem ("set ".$actor." dim100%")}
  183. ## Heuristic above doesn't work if lamp was dimmed, then switched off, then switched on, because state is "on", but the lamp is actually dimmed.
  184. else {fhem ("set ".$actor." ".$dimvalue)}
  185. sleep 1;
  186. }
  187. ## end of workaround
  188. else {fhem ("set ".$actor." ".Value($sender))}
  189. return;
  190. }
  191. sub
  192. IsInt($)
  193. {
  194. defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
  195. }
  196. # Small NC replacement: fhemNc("ip:port", "text", waitForReturn);
  197. sub
  198. fhemNc($$$)
  199. {
  200. my ($addr, $txt, $waitForReturn) = @_;
  201. my $client = IO::Socket::INET->new(PeerAddr => $addr);
  202. return "Can't connect to $addr\n" if(!$client);
  203. syswrite($client, $txt);
  204. return "" if(!$waitForReturn);
  205. my ($ret, $buf) = ("", "");
  206. shutdown($client, 1);
  207. alarm(5);
  208. while(sysread($client, $buf, 256) > 0) {
  209. $ret .= $buf;
  210. }
  211. alarm(0);
  212. close($client);
  213. return $ret;
  214. }
  215. sub
  216. round($$)
  217. {
  218. my($v,$n) = @_;
  219. return sprintf("%.${n}f",$v);
  220. }
  221. 1;
  222. =pod
  223. =item helper
  224. =item summary FHEM utility functions
  225. =item summary_DE FHEM Hilfsfunktionen
  226. =begin html
  227. <a name="Utils"></a>
  228. <h3>Utils</h3>
  229. <ul>
  230. This is a collection of functions that can be used module-independant
  231. in all your own development<br/>
  232. </br>
  233. <b>Defined functions</b><br/><br/>
  234. <ul>
  235. <li><b>abstime2rel("HH:MM:SS")</b><br>tells you the difference as HH:MM:SS
  236. between now and the argument</li><br/>
  237. <li><b>ltrim("string")</b><br>returns string without leading
  238. spaces</li><br/>
  239. <li><b>max(str1, str2, ...)</b><br>returns the highest value from a given
  240. list (sorted alphanumeric)</li><br/>
  241. <li><b>maxNum(num1, num2, ...)</b><br>returns the highest value from a
  242. given list (sorted numeric)</li><br/>
  243. <li><b>min(str1, str2, ...)</b><br>returns the lowest value from a given
  244. list (sorted alphanumeric)</li><br/>
  245. <li><b>minNum(num1, num2, ...)</b><br>returns the lowest value from a given
  246. list (sorted numeric)</li><br/>
  247. <li><b>rtrim("string")</b><br>returns string without trailing
  248. spaces</li><br/>
  249. <li><b>time_str2num("YYYY-MM-DD HH:MM:SS")</b><br>convert a time string to
  250. number of seconds since 1970</li><br/>
  251. <li><b>trim("string")</b><br>returns string without leading and without
  252. trailing spaces</li><br/>
  253. <li><b>UntoggleDirect("deviceName")</b><br>For devices paired directly,
  254. converts state 'toggle' into 'on' or 'off'</li><br/>
  255. <li><b>UntoggleIndirect()</b><br>For devices paired indirectly, switches
  256. the target device 'on' or 'off', also when a 'toggle' was sent from the
  257. source device</li><br/>
  258. <li><b>defInfo("devspec", "internal")</b><br>return an array with the
  259. internal values of all devices found with devspec, e.g.
  260. defInfo("TYPE=SVG", "GPLOTFILE").</li><br/>
  261. <li><b>SVG_time_to_sec("YYYY-MM-DD_HH:MM:SS")</b><br>converts the argument
  262. to the number of seconds since 1970. Optimized for repeated use of similar
  263. timestamps.</li></br>
  264. <li><b>fhemNc("host:port", "textToSend", waitForReturn)</b><br>
  265. sends textToSend to host:port, and if waitForReturn is set, then read
  266. the answer (wait up to 5 seconds) and return it. Intended as small
  267. nc replacement.
  268. </li></br>
  269. <li><b>round(value, digits)</b><br>
  270. round &lt;value&gt; to given digits behind comma
  271. </li></br>
  272. <li><b>getUniqueId()</b><br>
  273. return the FHEM uniqueID used by the fheminfo command. Uses the
  274. getKeyValue / setKeyValue functions.
  275. </li></br>
  276. <li><b>setKeyValue(keyName, value)</b><br>
  277. store the value in the file $modpath/FHEM/FhemUtils/uniqueID (the name is
  278. used for backward compatibility), or in the database, if using configDB.
  279. value may not contain newlines, and only one value per key is stored.
  280. The file/database entry will be written immediately, no explicit save is
  281. required. If the value is undef, the entry will be deleted.
  282. Returns an error-string or undef.
  283. </li></br>
  284. <li><b>getKeyValue(keyName)</b><br>
  285. return ($error, $value), stored previously by setKeyValue.
  286. $error is set if there was an error. Both are undef, if there is no
  287. value yet for this key.
  288. </li></br>
  289. </ul>
  290. </ul>
  291. =end html
  292. =cut