Multiple SIS_PM units now work. (After fixing sispmctl-bug, see commandref.html.)

NOTE: Changing the order of the units on the USB while fhem.pl is running WILL STILL BREAK THINGS!


git-svn-id: https://fhem.svn.sourceforge.net/svnroot/fhem/trunk/fhem@551 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
painseeker
2010-01-19 19:33:01 +00:00
parent c0a5ef204e
commit 4e3a7c64fc
2 changed files with 103 additions and 25 deletions

View File

@@ -29,7 +29,7 @@
# #
# Contributed by Kai 'wusel' Siering <wusel+fhem@uu.org> in 2010 # Contributed by Kai 'wusel' Siering <wusel+fhem@uu.org> in 2010
# Based in part on work for FHEM by other authors ... # Based in part on work for FHEM by other authors ...
# $Id: 70_SISPM.pm,v 1.2 2010-01-18 01:12:34 painseeker Exp $ # $Id: 70_SISPM.pm,v 1.3 2010-01-19 19:33:01 painseeker Exp $
########################### ###########################
package main; package main;
@@ -102,6 +102,7 @@ SISPM_Define($$)
if(!$FH) { if(!$FH) {
return "SISPM Can't start $dev: $!"; return "SISPM Can't start $dev: $!";
} }
$hash->{NUMUNITS}=0;
local $_; local $_;
while (<$FH>) { while (<$FH>) {
if(/^(No GEMBIRD SiS-PM found.)/) { if(/^(No GEMBIRD SiS-PM found.)/) {
@@ -111,9 +112,11 @@ SISPM_Define($$)
if(/^Gembird #(\d+) is USB device (\d+)./) { if(/^Gembird #(\d+) is USB device (\d+)./) {
Log 3, "SISPM found SISPM device number $1 as USB $2"; Log 3, "SISPM found SISPM device number $1 as USB $2";
$hash->{UNITS}{$1}{USB}=$2; $hash->{UNITS}{$1}{USB}=$2;
$currentdevice=$numdetected; $currentdevice=$1;
$numdetected++; $numdetected++;
$hash->{NUMUNITS}=$numdetected;
} }
if(/^This device has a serial number of (.*)/) { if(/^This device has a serial number of (.*)/) {
my $serial=$1; my $serial=$1;
Log 3, "SISPM device number " . $currentdevice . " has serial $serial"; Log 3, "SISPM device number " . $currentdevice . " has serial $serial";
@@ -179,13 +182,19 @@ SISPM_GetStatus($)
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $dev = $hash->{DeviceName}; my $dev = $hash->{DeviceName};
my $FH; my $FH;
my $i;
# Call us in n seconds again. # Call us in n seconds again.
# InternalTimer(gettimeofday()+ $hash->{Timer}, "SISPM_GetStatus", $hash, 1); # InternalTimer(gettimeofday()+ $hash->{Timer}, "SISPM_GetStatus", $hash, 1);
Log 4, "SISPM contacting device"; Log 4, "SISPM contacting device";
my $tmpdev=sprintf("%s -s -g all 2>&1 |", $dev); my $tmpdev=sprintf("%s -s ", $dev);
for($i=0; $i<$hash->{NUMUNITS}; $i++) {
$tmpdev=sprintf("%s -d %d -g all ", $tmpdev, $i);
}
$tmpdev=sprintf("%s 2>&1 |", $tmpdev);
open($FH, $tmpdev); open($FH, $tmpdev);
if(!$FH) { if(!$FH) {
return "SISPM Can't open pipe: $dev: $!"; return "SISPM Can't open pipe: $dev: $!";
@@ -232,6 +241,10 @@ SISPM_Read($)
my $reading; my $reading;
my $readingforstatus; my $readingforstatus;
my $currentserial="none"; my $currentserial="none";
my $currentdevice=0;
my $currentusbid=0;
my $renumbered=0;
my $newPMfound=0;
($eof, @lines) = nonblockGetLinesSISPM($FH); ($eof, @lines) = nonblockGetLinesSISPM($FH);
@@ -255,39 +268,65 @@ SISPM_Read($)
next; next;
} }
# wusel, 2010-01-19: Multiple (2) SIS PM do work now. But USB renumbering will still
# break things rather badly. Thinking about dropping it altogether,
# that is wipe old state data ($hash->{UNITS} et. al.) and rebuild
# data each time from scratch. That should work as SIS_PMS uses the
# serial as key; unfortunately, sispmctl doesn't offer this (and it
# wont work due to those FFFFFFxx readings), so we need to keep
# track of unit number <-> serial ... But if between reading this
# data and a "set" statement something changes, we still could switch
# the wrong socket.
#
# As sispmctl 2.7 is broken already for multiple invocations with -d,
# I consider fixing both the serial number issue as well as add the
# serial as selector ... Drat. Instead of getting the ToDo list shorter,
# it just got longer ;-)
if($inputline =~ /^(No GEMBIRD SiS-PM found.)/) { if($inputline =~ /^(No GEMBIRD SiS-PM found.)/) {
Log 3, "SISPM woops? $1"; Log 3, "SISPM Whoopsie? $1";
next;
} }
if($inputline =~ /^Gembird #(\d+) is USB device (\d+)\./ || if($inputline =~ /^Gembird #(\d+) is USB device (\d+)\./ ||
$inputline =~ /^Accessing Gembird #(\d+) USB device (\d+)/) { $inputline =~ /^Accessing Gembird #(\d+) USB device (\d+)/) {
Log 5, "SISPM found SISPM device number $1 as USB $2"; Log 5, "SISPM found SISPM device number $1 as USB $2";
if($1 < $hash->{NUMUNITS}) {
if($hash->{UNITS}{$1}{USB}!=$2) { if($hash->{UNITS}{$1}{USB}!=$2) {
# -wusel, 2010-01-15: FIXME! Verify that this IS the device we're Log 3, "SISPM: USB ids changed (unit $1 is now USB $2 but was " . $hash->{UNITS}{$1}{USB} . "); will fix.";
# looking for. As USB renumbering can happen, $renumbered=1;
# if the $hash->{UNITS}{$1}{USB}=$2 not matches }
# we'd need to redo a "sispmctl -s", maybe by } else { # Something wonderful has happened, we have a new SIS PM!
# going to SISPM_Define() again? Log 3, "SISPM: Wuuuhn! Found a new unit $1 as USB $2. Will assimilate it.";
# $newPMfound=1;
# Hoping the best for now -- DON'T TOUCH RUNNING }
# BOX WITH MORE THAN ONE SISPM CONNECTED OR HELL $currentdevice=$1;
# MAY BREAK LOOSE ;) $currentusbid=$2;
Log 3, "SISPM: Odd, got unit $1 as USB $2, have $1 on file as " . $hash->{UNITS}{$1}{USB} . "?"; $currentserial="none";
if(defined($hash->{UNITS}{$currentdevice}{SERIAL})) {
$currentserial=$hash->{UNITS}{$currentdevice}{SERIAL};
} }
} }
# -wusel, 2010-01-15: FIXME! This will break on >1 PMS!
if($inputline =~ /^This device has a serial number of (.*)/) { if($inputline =~ /^This device has a serial number of (.*)/) {
$currentserial=FixSISPMSerial($1); $currentserial=FixSISPMSerial($1);
if($currentserial eq "00:00:00:00:00") { if($currentserial eq "00:00:00:00:00") {
Log 3, "SISPM Whooopsie! Your serial nullified ($currentserial). Skipping ..."; Log 3, "SISPM Whooopsie! Your serial nullified ($currentserial). Skipping ...";
next; next;
} }
if($newPMfound==1) {
$hash->{UNITS}{$currentdevice}{USB}=$currentusbid;
$hash->{UNITS}{$currentdevice}{SERIAL}=$currentserial;
$hash->{SERIALS}{$currentserial}{UNIT}=$currentdevice;
$hash->{SERIALS}{$currentserial}{USB}=$currentusbid;
$hash->{NUMUNITS}+=1;
}
} }
if($inputline =~ /^Status of outlet (\d):\s+(.*)/) { if($inputline =~ /^Status of outlet (\d):\s+(.*)/) {
if($currentserial ne "none") { if($currentserial ne "none") {
Log 5, "SISPM found socket $1 on $currentserial, state $2"; Log 3, "SISPM found socket $1 on $currentserial, state $2";
my $dmsg="socket " . $currentserial . " $1 state " . $2; my $dmsg="socket " . $currentserial . " $1 state " . $2;
my %addvals; my %addvals;
Dispatch($hash, $dmsg, \%addvals); Dispatch($hash, $dmsg, \%addvals);
@@ -332,7 +371,7 @@ sub SISPM_Write($$$) {
} }
if(defined($hash->{SERIALS}{$serial}{UNIT})) { if(defined($hash->{SERIALS}{$serial}{UNIT})) {
$deviceno=($hash->{SERIALS}{$serial}{UNIT})+1; $deviceno=($hash->{SERIALS}{$serial}{UNIT});
$cmdline=sprintf("%s -d %d -%s %d 2>&1 >/dev/null", $dev, $deviceno, $cmdletter, $socket); $cmdline=sprintf("%s -d %d -%s %d 2>&1 >/dev/null", $dev, $deviceno, $cmdletter, $socket);
system($cmdline); system($cmdline);
} else { } else {

View File

@@ -3467,13 +3467,52 @@ Forecast Cloudy</pre>
<code>define &lt;name&gt; SISPM &lt;/path/to/sispmctl&gt;</code> <code>define &lt;name&gt; SISPM &lt;/path/to/sispmctl&gt;</code>
<br><br> <br><br>
<i><b>PLEASE NOTE:</b> This module is to be considered alpha quality; it has not been <div style="background-color: #ffaaaa;">
tested extensively, especially the interaction between "set" commands and the sheduled <i><b>PLEASE NOTE:</b> This module is still work in progess; please treat it as such.
status reading needs more obervation. (Testing with FIFOs seems as if it's working (That is, don't but your central heating on SISPM in a cold winter just yet ;))</i><br><br>
without blocking nor interference, but that's on a mostly unloaded, fast system.)<br><br> Further tests should be done regarding the interaction between "set" commands and the sheduled
BE CAREFUL when using multiple PMs on one host; the parser in SISPM_Define() is MOST status reading. (Testing with FIFOs seems as if it's working without blocking nor interference,
PROBABLY broken here, I haven't had the opportunity to test this yet. YOU HAVE BEEN but that's on a mostly unloaded, fast system.)<br><br>
WARNED.</i> And now to what's this disclaimer tries to prevent you from using ;)<br><br> When <i>using multiple SIS PMs on one host</i>, sispmctl up to and including V 2.7 has a bug:
<pre>plug-2:# sispmctl -v -s -d 1 -g all -d 2 -g all
SiS PM Control for Linux 2.7
(C) 2004, 2005, 2006, 2007, 2008 by Mondrian Nuessle, (C) 2005, 2006 by Andreas Neuper.
This program is free software.
[...]
Gembird #0 is USB device 013.This device is a 4-socket SiS-PM.
[...]
Gembird #1 is USB device 015.This device is a 4-socket SiS-PM.
[...]
Accessing Gembird #1 USB device 015
Status of outlet 1: on
Status of outlet 2: on
Status of outlet 3: on
Status of outlet 4: on
Error performing requested action
Libusb error string: error sending control message: Invalid argument
Terminating
*** glibc detected *** sispmctl: double free or corruption (fasttop): 0x000251e0 ***
[...]</pre>
Well, the fix is simple and will be sent upstream, but in case it's not incorporated
at the time you need it, here it is; it's easy to apply even by hand ;-)
<pre>
--- src/main.c-old 2010-01-19 16:56:15.000000000 +0100
+++ src/main.c 2010-01-19 16:54:56.000000000 +0100
@@ -441,7 +441,7 @@
}
break;
case 'd': // replace previous (first is default) device by selected one
- if(udev!=NULL) usb_close (udev);
+ if(udev!=NULL) { usb_close (udev); udev=NULL; }
devnum = atoi(optarg);
if(devnum>=count) devnum=count-1;
break;
</pre></div><br>
Defines a path to the program "sispmctl", which is used to control (locally attached) Defines a path to the program "sispmctl", which is used to control (locally attached)
"Silver Shield Power Manager" devices. Usually these are connected to the local computer "Silver Shield Power Manager" devices. Usually these are connected to the local computer