70_SISPM.pm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. ################################################################
  2. #
  3. # Copyright notice
  4. #
  5. # (c) 2009 Copyright: Kai 'wusel' Siering (wusel+fhem at uu dot org)
  6. # All rights reserved
  7. #
  8. # This code is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # The GNU General Public License can be found at
  14. # http://www.gnu.org/copyleft/gpl.html.
  15. # A copy is found in the textfile GPL.txt and important notices to the license
  16. # from the author is found in LICENSE.txt distributed with these scripts.
  17. #
  18. # This script is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. # GNU General Public License for more details.
  22. #
  23. # This copyright notice MUST APPEAR in all copies of the script!
  24. ###############################################
  25. ###########################
  26. # 70_SISPM.pm
  27. # Module for FHEM
  28. #
  29. # Contributed by Kai 'wusel' Siering <wusel+fhem@uu.org> in 2010
  30. # Based in part on work for FHEM by other authors ...
  31. # $Id: 70_SISPM.pm 2076 2012-11-04 13:49:43Z rudolfkoenig $
  32. ###########################
  33. package main;
  34. use strict;
  35. use warnings;
  36. #####################################
  37. sub
  38. SISPM_Initialize($)
  39. {
  40. my ($hash) = @_;
  41. # Consumer
  42. $hash->{DefFn} = "SISPM_Define";
  43. $hash->{Clients} =
  44. ":SIS_PMS:";
  45. my %mc = (
  46. "1:SIS_PMS" => "^socket ..:..:..:..:.. .+ state o.*",
  47. );
  48. $hash->{MatchList} = \%mc;
  49. $hash->{AttrList}= "model:SISPM loglevel:0,1,2,3,4,5,6";
  50. $hash->{ReadFn} = "SISPM_Read";
  51. $hash->{WriteFn} = "SISPM_Write";
  52. $hash->{UndefFn} = "SISPM_Undef";
  53. }
  54. #####################################
  55. sub FixSISPMSerial($) {
  56. my $serial=$_[0];
  57. if(length($serial)!=length("..:..:..:..:..")){
  58. my ($sn1, $sn2, $sn3, $sn4, $sn5) = split(":", $serial);
  59. $serial=sprintf("%2s:%2s:%2s:%2s:%2s", substr($sn1, -2, 2), substr($sn2, -2, 2), substr($sn3, -2, 2), substr($sn4, -2, 2), substr($sn5, -2, 2));
  60. $serial =~ s/ /0/g;
  61. }
  62. return $serial;
  63. }
  64. #####################################
  65. sub
  66. SISPM_GetCurrentConfig($)
  67. {
  68. my ($hash) = @_;
  69. my $numdetected=0;
  70. my $currentdevice=0;
  71. my $FH;
  72. my $i;
  73. my $dev = sprintf("%s", $hash->{DeviceName});
  74. Log 3, "SISPM_GetCurrentConfig: Using \"$dev\" as parameter to open(); trying ...";
  75. # First, clear the old data! As we're addressing by hashes, keeping old data would be unwise.
  76. if(defined($hash->{NUMUNITS}) && $hash->{NUMUNITS}>0) {
  77. for($i=0; $i<$hash->{NUMUNITS}; $i++) {
  78. my $serial;
  79. if(defined($hash->{UNITS}{$i}{SERIAL})) {
  80. $serial=$hash->{UNITS}{$i}{SERIAL};
  81. delete $hash->{SERIALS}{$serial}{UNIT};
  82. delete $hash->{SERIALS}{$serial}{USB};
  83. }
  84. if(defined($hash->{UNITS}{$i}{USB})) {
  85. delete $hash->{UNITS}{$i}{USB};
  86. delete $hash->{UNITS}{$i}{SERIAL};
  87. }
  88. }
  89. }
  90. $hash->{NUMUNITS}=0;
  91. my $tmpdev=sprintf("%s -s 2>&1 |", $dev);
  92. open($FH, $tmpdev);
  93. if(!$FH) {
  94. Log 3, "SISPM_GetCurrentConfig: Can't start $tmpdev: $!";
  95. return "Can't start $tmpdev: $!";
  96. }
  97. my $tmpnr=-1;
  98. local $_;
  99. while (<$FH>) {
  100. if(/^(No GEMBIRD SiS-PM found.)/) {
  101. Log 3, "SISPM_GetCurrentConfig: Whoops? $1";
  102. }
  103. if(/^Gembird #(\d+) is USB device (\d+)./) {
  104. Log 3, "SISPM_GetCurrentConfig: Found SISPM device number $1 as USB $2";
  105. $hash->{UNITS}{$1}{USB}=$2;
  106. $currentdevice=$1;
  107. $numdetected++;
  108. $hash->{NUMUNITS}=$numdetected;
  109. }
  110. if(/^Gembird #(\d+)$/) {
  111. Log 3, "SISPM_GetCurrentConfig: Found SISPM device number $1 (sispmctl v3)";
  112. $currentdevice=$1;
  113. $numdetected++;
  114. $hash->{NUMUNITS}=$numdetected;
  115. }
  116. if(/^USB information: bus .*, device (\d+)/) {
  117. Log 3, "SISPM_GetCurrentConfig: SISPM device number $currentdevice is USB device $1 (sispmctl v3)";
  118. $hash->{UNITS}{$currentdevice}{USB}=$1;
  119. }
  120. if(/^This device has a serial number of (.*)/) {
  121. my $serial=$1;
  122. Log 3, "SISPM_GetCurrentConfig: Device number " . $currentdevice . " has serial $serial";
  123. if(length($serial)!=length("..:..:..:..:..")){
  124. $serial = FixSISPMSerial($serial);
  125. Log 3, "SISPM_GetCurrentConfig: Whoopsi, weird serial format; fixing to $serial.";
  126. }
  127. $hash->{UNITS}{$currentdevice}{SERIAL}=$serial;
  128. $hash->{SERIALS}{$serial}{UNIT}=$currentdevice;
  129. $hash->{SERIALS}{$serial}{USB}=$hash->{UNITS}{$currentdevice}{USB};
  130. }
  131. if(/^serial number:\s+(.*)/) { # sispmctl v3
  132. my $serial=$1;
  133. Log 3, "SISPM_GetCurrentConfig: Device number " . $currentdevice . " has serial $serial (sispmctl v3)";
  134. if(length($serial)!=length("..:..:..:..:..")){
  135. $serial = FixSISPMSerial($serial);
  136. Log 3, "SISPM_GetCurrentConfig: Whoopsi, weird serial format; fixing to $serial.";
  137. }
  138. $hash->{UNITS}{$currentdevice}{SERIAL}=$serial;
  139. $hash->{SERIALS}{$serial}{UNIT}=$currentdevice;
  140. $hash->{SERIALS}{$serial}{USB}=$hash->{UNITS}{$currentdevice}{USB};
  141. }
  142. }
  143. close($FH);
  144. Log 3, "SISPM_GetCurrentConfig: Initial read done";
  145. if ($numdetected==0) {
  146. Log 3, "SISPM_GetCurrentConfig: No SISPM devices found.";
  147. return "no SISPM devices found.";
  148. }
  149. $hash->{NUMUNITS} = $numdetected;
  150. $hash->{STATE} = "initialized";
  151. return undef;
  152. }
  153. #####################################
  154. sub
  155. SISPM_Define($$)
  156. {
  157. my ($hash, $def) = @_;
  158. my @a = split("[ \t][ \t]*", $def);
  159. my $numdetected=0;
  160. my $currentdevice=0;
  161. my $retval;
  162. return "Define the /path/to/sispmctl as a parameter" if(@a != 3);
  163. my $FH;
  164. my $dev = sprintf("%s", $a[2]);
  165. $hash->{DeviceName} = $dev;
  166. Log 3, "SISPM using \"$dev\" as parameter to open(); trying ...";
  167. $retval=SISPM_GetCurrentConfig($hash);
  168. Log 3, "SISPM GetCurrentConfing done";
  169. if(defined($retval)) {
  170. Log 3, "SISPM: An error occured: $retval";
  171. return $retval;
  172. }
  173. if($hash->{NUMUNITS} < 1) {
  174. return "SISPM no SISPM devices found.";
  175. }
  176. $hash->{Timer} = 30;
  177. Log 3, "SISPM setting callback timer";
  178. my $oid = $init_done;
  179. $init_done = 1;
  180. InternalTimer(gettimeofday()+ $hash->{Timer}, "SISPM_GetStatus", $hash, 1);
  181. $init_done = $oid;
  182. Log 3, "SISPM initialized";
  183. return undef;
  184. }
  185. #####################################
  186. sub
  187. SISPM_Undef($$)
  188. {
  189. my ($hash, $def) = @_;
  190. my @a = split("[ \t][ \t]*", $def);
  191. my $name = $hash->{NAME};
  192. if(defined($hash->{FD})) {
  193. close($hash->{FD});
  194. delete $hash->{FD};
  195. }
  196. delete $selectlist{"$name.pipe"};
  197. $hash->{STATE}='undefined';
  198. Log 3, "$name shutdown complete";
  199. return undef;
  200. }
  201. #####################################
  202. sub
  203. SISPM_GetStatus($)
  204. {
  205. my ($hash) = @_;
  206. my $dnr = $hash->{DEVNR};
  207. my $name = $hash->{NAME};
  208. my $dev = $hash->{DeviceName};
  209. my $FH;
  210. my $i;
  211. # Call us in n seconds again.
  212. # InternalTimer(gettimeofday()+ $hash->{Timer}, "SISPM_GetStatus", $hash, 1);
  213. Log 4, "SISPM contacting device";
  214. my $tmpdev=sprintf("%s -s ", $dev);
  215. for($i=0; $i<$hash->{NUMUNITS}; $i++) {
  216. $tmpdev=sprintf("%s -d %d -g all ", $tmpdev, $i);
  217. }
  218. $tmpdev=sprintf("%s 2>&1 |", $tmpdev);
  219. open($FH, $tmpdev);
  220. if(!$FH) {
  221. return "SISPM Can't open pipe: $dev: $!";
  222. }
  223. $hash->{FD}=$FH;
  224. $selectlist{"$name.pipe"} = $hash;
  225. Log 4, "SISPM pipe opened";
  226. $hash->{STATE} = "running";
  227. $hash->{pipeopentime} = time();
  228. # InternalTimer(gettimeofday() + 6, "SISPM_Read", $hash, 1);
  229. # return $hash->{STATE};
  230. }
  231. #####################################
  232. sub
  233. SISPM_Read($)
  234. {
  235. my ($hash) = @_;
  236. my $dnr = $hash->{DEVNR};
  237. my $name = $hash->{NAME};
  238. my $dev = $hash->{DeviceName};
  239. my $FH;
  240. my $inputline;
  241. Log 4, "SISPM Read entered";
  242. if(!defined($hash->{FD})) {
  243. Log 3, "Oops, SISPM FD undef'd";
  244. return undef;
  245. }
  246. if(!$hash->{FD}) {
  247. Log 3, "Oops, SISPM FD empty";
  248. return undef;
  249. }
  250. $FH = $hash->{FD};
  251. Log 4, "SISPM reading started";
  252. my @lines;
  253. my $eof;
  254. my $i=0;
  255. my $tn = TimeNow();
  256. my $reading;
  257. my $readingforstatus;
  258. my $currentserial="none";
  259. my $currentdevice=0;
  260. my $currentusbid=0;
  261. my $renumbered=0;
  262. my $newPMfound=0;
  263. my $tmpnr=-1;
  264. ($eof, @lines) = nonblockGetLinesSISPM($FH);
  265. if(!defined($eof)) {
  266. Log 4, "SISPM FIXME: eof undefined?!";
  267. $eof=0;
  268. }
  269. Log 4, "SISPM reading ended with eof==$eof";
  270. # FIXME! Current observed behaviour is "would block", then read of only EOF.
  271. # Not sure if it's always that way; more correct would be checking
  272. # for empty $inputline or undef'd $rawreading,$val. -wusel, 2010-01-04
  273. if($eof != 1) {
  274. foreach my $inputline ( @lines ) {
  275. $inputline =~ s/\s+$//;
  276. Log 5, "SISPM_Read: read /$inputline/";
  277. # wusel, 2010-01-16: Seems as if reading not always works as expected;
  278. # throw away the whole readings if there's a NULL
  279. # serial number.
  280. if($currentserial eq "00:00:00:00:00") {
  281. next;
  282. }
  283. # wusel, 2010-01-19: Multiple (2) SIS PM do work now. But USB renumbering will still
  284. # break things rather badly. Thinking about dropping it altogether,
  285. # that is wipe old state data ($hash->{UNITS} et. al.) and rebuild
  286. # data each time from scratch. That should work as SIS_PMS uses the
  287. # serial as key; unfortunately, sispmctl doesn't offer this (and it
  288. # wont work due to those FFFFFFxx readings), so we need to keep
  289. # track of unit number <-> serial ... But if between reading this
  290. # data and a "set" statement something changes, we still could switch
  291. # the wrong socket.
  292. #
  293. # As sispmctl 2.7 is broken already for multiple invocations with -d,
  294. # I consider fixing both the serial number issue as well as add the
  295. # serial as selector ... Drat. Instead of getting the ToDo list shorter,
  296. # it just got longer ;-)
  297. if($inputline =~ /^(No GEMBIRD SiS-PM found.)/) {
  298. Log 3, "SISPM Whoopsie? $1";
  299. next;
  300. }
  301. if($inputline =~ /^Gembird #(\d+) is USB device (\d+)\./ ||
  302. $inputline =~ /^Accessing Gembird #(\d+) USB device (\d+)/) {
  303. Log 5, "SISPM found SISPM device number $1 as USB $2";
  304. if($1 < $hash->{NUMUNITS}) {
  305. if($hash->{UNITS}{$1}{USB}!=$2) {
  306. Log 3, "SISPM: USB ids changed (unit $1 is now USB $2 but was " . $hash->{UNITS}{$1}{USB} . "); will fix.";
  307. $renumbered=1;
  308. $hash->{FIXRENUMBER}="yes";
  309. }
  310. } else { # Something wonderful has happened, we have a new SIS PM!
  311. Log 3, "SISPM: Wuuuhn! Found a new unit $1 as USB $2. Will assimilate it.";
  312. $newPMfound=1;
  313. $hash->{FIXNEW}="yes";
  314. }
  315. $currentdevice=$1;
  316. $currentusbid=$2;
  317. $currentserial="none";
  318. if(defined($hash->{UNITS}{$currentdevice}{SERIAL})) {
  319. $currentserial=$hash->{UNITS}{$currentdevice}{SERIAL};
  320. }
  321. }
  322. # New for SiS PM Control for Linux 3.1
  323. if($inputline =~ /^Gembird #(\d+)$/) {
  324. Log 5, "SISPM found SISPM device number $1 (sispmctl v3)";
  325. $tmpnr=$1;
  326. }
  327. if($tmpnr >= 0 && $inputline =~ /^USB information: bus 001, device (\d+)/) {
  328. Log 5, "SISPM found SISPM device number $tmpnr as USB $1";
  329. if($tmpnr < $hash->{NUMUNITS}) {
  330. if($hash->{UNITS}{$tmpnr}{USB}!=$1) {
  331. Log 3, "SISPM: USB ids changed (unit $tmpnr is now USB $1 but was " . $hash->{UNITS}{$tmpnr}{USB} . "); will fix.";
  332. $renumbered=1;
  333. $hash->{FIXRENUMBER}="yes";
  334. }
  335. } else { # Something wonderful has happened, we have a new SIS PM!
  336. Log 3, "SISPM: Wuuuhn! Found a new unit $tmpnr as USB $1 with sispmctl v3. Will assimilate it.";
  337. $newPMfound=1;
  338. $hash->{FIXNEW}="yes";
  339. }
  340. $currentdevice=$tmpnr;
  341. $currentusbid=$1;
  342. $currentserial="none";
  343. if(defined($hash->{UNITS}{$currentdevice}{SERIAL})) {
  344. $currentserial=$hash->{UNITS}{$currentdevice}{SERIAL};
  345. }
  346. $tmpnr=-1;
  347. }
  348. if($inputline =~ /^This device has a serial number of (.*)/ ||
  349. $inputline =~ /^serial number:\s+(.*)/) {
  350. $currentserial=FixSISPMSerial($1);
  351. if($currentserial eq "00:00:00:00:00") {
  352. Log 3, "SISPM Whooopsie! Your serial nullified ($currentserial). Skipping ...";
  353. next;
  354. }
  355. if($newPMfound==1) {
  356. $hash->{UNITS}{$currentdevice}{USB}=$currentusbid;
  357. $hash->{UNITS}{$currentdevice}{SERIAL}=$currentserial;
  358. $hash->{SERIALS}{$currentserial}{UNIT}=$currentdevice;
  359. $hash->{SERIALS}{$currentserial}{USB}=$currentusbid;
  360. $hash->{NUMUNITS}+=1;
  361. }
  362. }
  363. if($inputline =~ /^Status of outlet (\d):\s+(.*)/) {
  364. if($currentserial ne "none") {
  365. Log 5, "SISPM found socket $1 on $currentserial, state $2";
  366. my $dmsg="socket " . $currentserial . " $1 state " . $2;
  367. my %addvals;
  368. Dispatch($hash, $dmsg, \%addvals);
  369. } else {
  370. Log 3, "SISPM Whooopsie! Found socket $1, state $2, but no serial (serial is $currentserial)?";
  371. }
  372. }
  373. }
  374. }
  375. if($eof) {
  376. close($FH);
  377. delete $hash->{FD};
  378. delete $selectlist{"$name.pipe"};
  379. InternalTimer(gettimeofday()+ $hash->{Timer}, "SISPM_GetStatus", $hash, 1);
  380. $hash->{STATE} = "read";
  381. Log 4, "SISPM done reading pipe";
  382. if(defined($hash->{FIXRENUMBER}) || defined($hash->{FIXNEW})) {
  383. my $retval;
  384. Log 3, "SISPM now adapts to new environment ...";
  385. $retval=SISPM_GetCurrentConfig($hash);
  386. if(defined($retval)) {
  387. Log 3, "SISPM an error occured during reconfiguration: $retval";
  388. }
  389. if(defined($hash->{FIXRENUMBER})) {
  390. delete $hash->{FIXRENUMBER};
  391. }
  392. if(defined($hash->{FIXNEW})) {
  393. delete $hash->{FIXNEW};
  394. }
  395. }
  396. } else {
  397. $hash->{STATE} = "reading";
  398. Log 4, "SISPM (further) reading would block";
  399. }
  400. }
  401. #####################################
  402. sub SISPM_Write($$$) {
  403. my ($hash,$fn,$msg) = @_;
  404. my $dev = $hash->{DeviceName};
  405. # Log 3, "SISPM_Write entered for $hash->{NAME} with $fn and $msg";
  406. my ($serial, $socket, $what) = split(' ', $msg);
  407. my $deviceno;
  408. my $cmdline;
  409. my $cmdletter="t";
  410. if($what eq "on") {
  411. $cmdletter="o";
  412. } elsif($what eq "off") {
  413. $cmdletter="f";
  414. }
  415. if(defined($hash->{SERIALS}{$serial}{UNIT})) {
  416. $deviceno=($hash->{SERIALS}{$serial}{UNIT});
  417. $cmdline=sprintf("%s -d %d -%s %d 2>&1 >/dev/null", $dev, $deviceno, $cmdletter, $socket);
  418. system($cmdline);
  419. } else {
  420. Log 2, "SISPM_Write can not find SISPM device with serial $serial";
  421. }
  422. return;
  423. }
  424. # From http://www.perlmonks.org/?node_id=713384 / http://davesource.com/Solutions/20080924.Perl-Non-blocking-Read-On-Pipes-Or-Files.html
  425. #
  426. # Used, hopefully, with permission ;)
  427. #
  428. # An non-blocking filehandle read that returns an array of lines read
  429. # Returns: ($eof,@lines)
  430. my %nonblockGetLines_lastSISPM;
  431. sub nonblockGetLinesSISPM {
  432. my ($fh,$timeout) = @_;
  433. $timeout = 0 unless defined $timeout;
  434. my $rfd = '';
  435. $nonblockGetLines_lastSISPM{$fh} = ''
  436. unless defined $nonblockGetLines_lastSISPM{$fh};
  437. vec($rfd,fileno($fh),1) = 1;
  438. return unless select($rfd, undef, undef, $timeout)>=0;
  439. # I'm not sure the following is necessary?
  440. return unless vec($rfd,fileno($fh),1);
  441. my $buf = '';
  442. my $n = sysread($fh,$buf,1024*1024);
  443. # If we're done, make sure to send the last unfinished line
  444. return (1,$nonblockGetLines_lastSISPM{$fh}) unless $n;
  445. # Prepend the last unfinished line
  446. $buf = $nonblockGetLines_lastSISPM{$fh}.$buf;
  447. # And save any newly unfinished lines
  448. $nonblockGetLines_lastSISPM{$fh} =
  449. (substr($buf,-1) !~ /[\r\n]/ && $buf =~ s/([^\r\n]*)$//)
  450. ? $1 : '';
  451. $buf ? (0,split(/\n/,$buf)) : (0);
  452. }
  453. 1;
  454. =pod
  455. =begin html
  456. <a name="SISPM"></a>
  457. <h3>SISPM</h3>
  458. <ul>
  459. <br>
  460. <a name="SISPMdefine"></a>
  461. <b>Define</b>
  462. <ul>
  463. <code>define &lt;name&gt; SISPM &lt;/path/to/sispmctl&gt;</code>
  464. <br><br>
  465. <!--<div style="background-color: #ffaaaa;"> -->
  466. <div>
  467. When <i>using multiple SIS PMs on one host</i>, sispmctl up to and including V 2.7 has a bug:
  468. <pre>plug-2:# sispmctl -v -s -d 1 -g all -d 2 -g all
  469. SiS PM Control for Linux 2.7
  470. (C) 2004, 2005, 2006, 2007, 2008 by Mondrian Nuessle, (C) 2005, 2006 by Andreas Neuper.
  471. This program is free software.
  472. [...]
  473. Gembird #0 is USB device 013.This device is a 4-socket SiS-PM.
  474. [...]
  475. Gembird #1 is USB device 015.This device is a 4-socket SiS-PM.
  476. [...]
  477. Accessing Gembird #1 USB device 015
  478. Status of outlet 1: on
  479. Status of outlet 2: on
  480. Status of outlet 3: on
  481. Status of outlet 4: on
  482. Error performing requested action
  483. Libusb error string: error sending control message: Invalid argument
  484. Terminating
  485. *** glibc detected *** sispmctl: double free or corruption (fasttop): 0x000251e0 ***
  486. [...]</pre>
  487. Well, the fix is simple and will be sent upstream, but in case it's not incorporated
  488. at the time you need it, here it is; it's easy to apply even by hand ;-)
  489. <pre>
  490. --- src/main.c-old 2010-01-19 16:56:15.000000000 +0100
  491. +++ src/main.c 2010-01-19 16:54:56.000000000 +0100
  492. @@ -441,7 +441,7 @@
  493. }
  494. break;
  495. case 'd': // replace previous (first is default) device by selected one
  496. - if(udev!=NULL) usb_close (udev);
  497. + if(udev!=NULL) { usb_close (udev); udev=NULL; }
  498. devnum = atoi(optarg);
  499. if(devnum>=count) devnum=count-1;
  500. break;
  501. </pre></div><br>
  502. Defines a path to the program "sispmctl", which is used to control (locally attached)
  503. "Silver Shield Power Manager" devices. Usually these are connected to the local computer
  504. via USB, more than one "sispm" device per computer is supported. (Please note that, due
  505. to neglections in their USB driver, AVM's Fritz!Box 7170 (and derivates, like Deutsche
  506. Telekom's Speedport W901V) <b>is not</b> able to talk to these devices ... The Fritz!Box
  507. 72xx and 73xx should be fine.)
  508. The communication between FHEM and the Power Manager device is done by using the open
  509. source <a href="http://sispmctl.sourceforge.net/">sispmctl</a> program. Thus, for the
  510. time being, THIS functionality is only available running FHEM on Linux (or any other platform
  511. where you can get the sispmctl program compiled and running). On the bright side: by
  512. interfacing via commandline, it is possible to define multiple SISPM devices, e. g. with
  513. a wrapper that does execute sispmctl on a remote (Linux) system. And: sispmctl runs happily
  514. on Marvells SheevaPlug ;) <i>Please note:</i> if you're not running FHEM as root, you most likely
  515. have to make sispmctl setuid root (<code>chmod 4755 /path/to/sispmctl</code>) or fiddle with
  516. udev so that the devices of the Power Manager are owned by the user running FHEM.
  517. After defining a SISPM device, a first test is done, identifying attached PMs. If this
  518. succeeds, an internal task is scheduled to read the status every 30 seconds. (Reason
  519. being that someone else could have switched sockets externally to FHEM.)
  520. To actually control any power sockets, you need to define a <a href="#SIS_PMS">SIS_PMS</a>
  521. device ;) If autocreate is enabled, those should be autocreated for your convenience as
  522. soon as the first scan took place (30 seconds after the define).
  523. Implementation of SISPM.pm tries to be nice, that is it reads from the pipe only
  524. non-blocking (== if there is data), so it should be safe even to use it via ssh or
  525. a netcat-pipe over the Internet, but this, as well, has not been tested extensively yet.
  526. <br><br>
  527. Attributes:
  528. <ul>
  529. <li><code>model</code>: <code>SISPM</code> (ignored for now)</li>
  530. </ul>
  531. <br>
  532. Example:
  533. <ul>
  534. <code>define PMS_Terrarium SISPM /usr/bin/sispmctl</code><br>
  535. </ul>
  536. <br>
  537. </ul>
  538. <a name="SISPMset"></a>
  539. <b>Set</b> <ul>N/A</ul><br>
  540. <a name="SISPMget"></a>
  541. <b>Get</b> <ul>N/A</ul><br>
  542. <a name="SISPMattr"></a>
  543. <b>Attributes</b>
  544. <ul>
  545. <li><a href="#model">model</a> (SISPM)</li>
  546. </ul>
  547. <br>
  548. </ul>
  549. =end html
  550. =cut