|
From: <ma...@us...> - 2012-01-03 21:07:09
|
Revision: 632
http://openautomation.svn.sourceforge.net/openautomation/?rev=632&view=rev
Author: mayerch
Date: 2012-01-03 21:07:03 +0000 (Tue, 03 Jan 2012)
Log Message:
-----------
* Change from Telnet to Socket
* Implement a few missing commands for the Russound
* Write status messages of the Russound (aquired by the WATCH command) to the KNX status addresses
Modified Paths:
--------------
wiregate/plugin/generic/Russound_RIO.pl
wiregate/plugin/generic/conf.d/Russound_RIO.conf_sample
Modified: wiregate/plugin/generic/Russound_RIO.pl
===================================================================
--- wiregate/plugin/generic/Russound_RIO.pl 2012-01-03 18:03:24 UTC (rev 631)
+++ wiregate/plugin/generic/Russound_RIO.pl 2012-01-03 21:07:03 UTC (rev 632)
@@ -12,6 +12,8 @@
#
#############################################################################
+#return; # uncomment to disable plugin
+
#############################################################################
# Configuration:
# --> change values in the conf.d directory!
@@ -20,6 +22,8 @@
my $numzones;
my $KNX_Start_Address;
+my $socknum; # unique number of the Socket
+
my $reset ; # set to 1 to reset the states, run script and change to 0 again
my $show_debug; # switches debug information that will be shown in the log
#############################################################################
@@ -27,6 +31,15 @@
#############################################################################
#############################################################################
+# Constants:
+my $MAX_ZONES = 31;
+my $ZONES_PER_CONTROLLER = 6;
+
+#############################################################################
+# Collect log information
+my $retval = '';
+
+#############################################################################
# Read config file in conf.d
my $confFile = '/etc/wiregate/plugin/generic/conf.d/'.basename($plugname,'.pl').'.conf';
if (! -f $confFile)
@@ -56,49 +69,88 @@
}
#############################################################################
-# External libraries:
-use Net::Telnet ();
+# Configure socket
+if (!$socket[$socknum]) { # if it doesn't exist: create socket
+ if ($IP_of_Russound) {
+ $socket[$socknum] = IO::Socket::INET->new(
+ PeerAddr => $IP_of_Russound,
+ PeerPort => '9621',
+ Proto => 'tcp',
+ Timeout => 120,
+ Blocking => 0
+ );
+ if(!$socket[$socknum]) # retry with WOL if first try didn't work
+ {
+ `wakeonlan $MAC_of_Russound`;
+ $socket[$socknum] = IO::Socket::INET->new(
+ PeerAddr => $IP_of_Russound,
+ PeerPort => '9621',
+ Proto => 'tcp',
+ Timeout => 120,
+ Blocking => 0
+ );
+ }
+ if(!$socket[$socknum]) { # fail if second try also didn't work
+ return "open of $IP_of_Russound failed: $!";
+ }
+ } else {
+ return "ERROR: No IP address configured!";
+ }
-#############################################################################
-# Constants:
-my $MAX_ZONES = 31;
-my $ZONES_PER_CONTROLLER = 6;
+ $socksel->add($socket[$socknum]); # add socket to select
+ $plugin_socket_subscribe{$socket[$socknum]} = $plugname; # subscribe plugin
+ $retval .= "opened Socket $socknum!" if $show_debug;
+}
+
#############################################################################
-# Collect log information
-my $retval = '';
-
my $destReadable = $msg{'dst'};
my $val = hex $msg{'data'};
# Convert to numeric GA
-(my $a, my $b, my $c) = split(/\//, $KNX_Start_Address );
-my $knxstartaddress = (($a << 11) + ($b << 8) + $c);
+my $knxstartaddress = str2addr( $KNX_Start_Address );
+my $dest = str2addr( $destReadable );
-# Convert to numeric GA
-($a,$b,$c) = split(/\//, $destReadable );
-my $dest = (($a << 11) + ($b << 8) + $c);
-
# Eigenen Aufruf-Zyklus ausschalten
$plugin_info{$plugname.'_cycle'} = 0;
-# aboniere alle relevanten GAs
-for (my $zone=0;$zone<$numzones;$zone++)
-{
- my $ctrl = int($zone/$ZONES_PER_CONTROLLER);
- my $czone = int($zone%$ZONES_PER_CONTROLLER);
- my $base = $knxstartaddress + 10 + ($czone*40) + ($ctrl*256);
- for( my $i = 0; $i < 13; $i++ ) # iterate funcnames
+if (%msg) { # KNX telegramm
+ $retval .= 'KNX:' if $show_debug;
+} elsif ($fh) { # incoming network message
+ my $sockInfo .= 'Socket: [';
+ my $cnt = 0;
+ my $line;
+ $/ = "\r\n"; # remove all new line
+ while( defined ($line = <$fh>) )
{
- my $a = $base + $i;
- my $gastr = sprintf "%d/%d/%d", ($a >> 11) & 0xf, ($a >> 8) & 0x7, $a & 0xff;
- $plugin_subscribe{$gastr}{$plugname} = 1;
+ chomp( $line );
+ $sockInfo .= ($cnt++) . ': ' . $line .';';
+ handleRussResponse( $line );
}
- for( my $i = 0; $i < 10; $i++ ) # iterate stateames
+ $retval .= $sockInfo if $show_debug;
+} else
+{ # called during init or on cycle intervall
+ syswrite( $socket[$socknum], "VERSION\r" );
+ syswrite( $socket[$socknum], "WATCH System ON\r" );
+
+ # aboniere alle relevanten GAs
+ for (my $zone=0;$zone<$numzones;$zone++)
{
- my $a = $base + $i + 20;
- my $gastr = sprintf "%d/%d/%d", ($a >> 11) & 0xf, ($a >> 8) & 0x7, $a & 0xff;
- $plugin_subscribe{$gastr}{$plugname} = 1;
+ my $ctrl = int($zone/$ZONES_PER_CONTROLLER);
+ my $czone = int($zone%$ZONES_PER_CONTROLLER);
+ my $base = $knxstartaddress + 10 + ($czone*40) + ($ctrl*256);
+ for( my $i = 0; $i < 13; $i++ ) # iterate funcnames
+ {
+ my $a = $base + $i;
+ my $gastr = sprintf "%d/%d/%d", ($a >> 11) & 0xf, ($a >> 8) & 0x7, $a & 0xff;
+ $plugin_subscribe{$gastr}{$plugname} = 1;
+ }
+ for( my $i = 0; $i < 10; $i++ ) # iterate stateames
+ {
+ my $a = $base + $i + 20;
+ my $gastr = sprintf "%d/%d/%d", ($a >> 11) & 0xf, ($a >> 8) & 0x7, $a & 0xff;
+ $plugin_subscribe{$gastr}{$plugname} = 1;
+ }
}
}
@@ -121,7 +173,10 @@
$controller = ($dest - $knxstartaddress) / 256;
}
- sendrussFunc( $controller, $zone, $func, $val );
+ if( $func < 20) # >= 20 = response addresses
+ {
+ $retval .= sendrussFunc( $controller, $zone, $func, $val );
+ }
}
return $retval;
@@ -131,19 +186,8 @@
sub sendcmd
{
my $cmd = shift;
- my $t = new Net::Telnet (
- Timeout => 10,
- Host => $IP_of_Russound,
- Port => 9621,
- Prompt => '/^/',
- Telnetmode => 0
- );
- $t->open();
- $t->print( $cmd );
- $t->close();
- my $res = $t->getline();
- $retval .= $cmd . '->' . $res if $show_debug;
- return $res;
+ syswrite( $socket[$socknum], "$cmd\r" );
+ return;
}
sub sendrussFunc
@@ -160,9 +204,15 @@
return 'Func ' . $func . ' not implemented or known';
} elsif( 0 == $func ) #power
{
- `wakeonlan $MAC_of_Russound`; # just to be sure
- sendcmd("EVENT $cz!ZoneOff") if( $val == 0 );
- sendcmd("EVENT $cz!ZoneOn" ) if( $val == 1 );
+ if( $val == 0 )
+ {
+ sendcmd("EVENT $cz!ZoneOff");
+ sendcmd("WATCH $cz OFF" );
+ } else {
+ `wakeonlan $MAC_of_Russound`; # just to be sure
+ sendcmd("EVENT $cz!ZoneOn" );
+ sendcmd("WATCH $cz ON" );
+ }
} elsif( 1 == $func ) #src
{
my $mapped = $val + 1;
@@ -181,17 +231,17 @@
sendcmd("SET $cz.treble=\"$mapped\"");
} elsif( 5 == $func ) #loud
{
- return 'Func ' . $func . ' not implemented or known';
+ sendcmd("SET $cz.loudness=\"" . ($val?'ON':'OFF') . '"');
} elsif( 6 == $func ) #bal
{
my $mapped = $val > 10 ? $val-256 : $val;
sendcmd("SET $cz.balance=\"$mapped\"");
} elsif( 7 == $func ) #party
{
- return 'Func ' . $func . ' not implemented or known';
+ sendcmd("EVENT $cz!PartyMode " . ($val?'ON':'OFF') );
} elsif( 8 == $func ) #dnd
{
- return 'Func ' . $func . ' not implemented or known';
+ sendcmd("EVENT $cz!DoNotDisturb " . ($val?'ON':'OFF') );
} elsif( 9 == $func ) #turnonvol
{
my $mapped = int( $val * 50/255 );
@@ -199,8 +249,104 @@
#TODO: 10 src cmd and 11 keypadcmd
} elsif( 12 == $func ) #volume relative up/down
{
- return 'Func ' . $func . ' not implemented or known';
+ sendcmd("EVENT $cz!KeyPress Volume" . ($val?'Up':'Down') );
} else {
- return 'Func ' . $func . ' not implemented or known';
+ return 'Func ' . $func . ' not implemented or known('.$val.')';
}
}
+
+sub handleRussResponse
+{
+ my $response = shift;
+
+ return if $response eq 'S';
+
+ if( $response =~ /^N C\[([0-9]*)\].Z\[([0-9]*)\].(.*)="(.*)"/ )
+ { # WATCH message from a controller
+ my $index = "${plugname}_$1_$2_$3";
+ return if $plugin_info{$index} eq $4; # no change
+
+ $plugin_info{$index} = $4;
+ sendKNXfuncCZ( $1, $2, $3, $4 );
+ } elsif( $response =~ /^N S\[([0-9]*)\].(.*)="(.*)"/ )
+ {
+ #$retval .= 'S:'.$1.'>'.$2.'>'.$3.';';
+ } elsif( $response =~ /^N System.(.*)="(.*)"/ )
+ {
+ #$retval .= 'System:'.$1.'>'.$2.';';
+ } elsif( $response =~ /^S / )
+ {
+ return; # don't care about response code...
+ } else {
+ $retval .= "<Unknown: $response>";
+ }
+}
+
+sub sendKNXfuncCZ
+{
+ my $C = shift;
+ my $Z = shift;
+ my $state = shift;
+ my $val = shift;
+ my $func; # KNX func number
+ my $dpt;
+
+ if( $state eq 'status' )
+ {
+ $func = 0;
+ $val = $val eq 'ON' ? 1 : 0;
+ $dpt = 1;
+ } elsif( $state eq 'currentSource' )
+ {
+ $func = 1;
+ $val = $val - 1;
+ $dpt = 5.004;
+ } elsif( $state eq 'volume' )
+ {
+ $func = 2;
+ $val = int($val * 255 / 50);
+ $dpt = 5.004;
+ } elsif( $state eq 'bass' )
+ {
+ $func = 3;
+ $val = $val < 0 ? 256+$val : $val;
+ $dpt = 5.004;
+ } elsif( $state eq 'treble')
+ {
+ $func = 4;
+ $val = $val < 0 ? 256+$val : $val;
+ $dpt = 5.004;
+ } elsif( $state eq 'loudness' )
+ {
+ $func = 5;
+ $val = $val eq 'ON' ? 1 : 0;
+ $dpt = 1;
+ } elsif( $state eq 'balance' )
+ {
+ $func = 6;
+ $val = $val < 0 ? 256+$val : $val;
+ $dpt = 5.004;
+ } elsif( $state eq 'partyMode' )
+ {
+ $func = 7;
+ $val = ($val eq 'ON' || $val eq 'MASTER') ? 1 : 0;
+ $dpt = 1;
+ } elsif( $state eq 'doNotDisturb' )
+ {
+ $func = 8;
+ $val = $val eq 'ON' ? 1 : 0;
+ $dpt = 1;
+ } elsif( $state eq 'turnOnVolume' )
+ {
+ $func = 9;
+ $val = int($val * 255 / 50);
+ $dpt = 5.004;
+ } else {
+ $retval .= "ERROR: Unknown state '$state' with value '$val'!";
+ return;
+ }
+
+ my $knxGA = $knxstartaddress+30+$func + (($Z-1)*40) + (($C-1)*256);
+ knx_write( addr2str( $knxGA, 1 ), $val, $dpt );
+ $retval .= 'KNX[' . addr2str( $knxGA, 1 ) . ',' . $dpt . ']:' . $val . ';' if $show_debug;
+}
\ No newline at end of file
Modified: wiregate/plugin/generic/conf.d/Russound_RIO.conf_sample
===================================================================
--- wiregate/plugin/generic/conf.d/Russound_RIO.conf_sample 2012-01-03 18:03:24 UTC (rev 631)
+++ wiregate/plugin/generic/conf.d/Russound_RIO.conf_sample 2012-01-03 21:07:03 UTC (rev 632)
@@ -10,6 +10,8 @@
$numzones = 6;
$KNX_Start_Address = '10/1/0';
+$socknum = 4711; # unique number of the Socket
+
$reset = 0; # set to 1 to reset the states, run script and change to 0 again
$show_debug = 1; # switches debug information that will be shown in the log
#############################################################################
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|