99_Utils.pm 9.1 KB

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