Turn on AMP with CEC from TCP packets recieved

434 Views Asked by At

Firstly I have a working solution but its prone to failure.

I would like to turn on my amp from Logitech Squeeze Center.

  • The server is running on 192.168.0.30
  • The Player is in the Dining Room running on 192.168.0.31
  • The player is connected via HDMI to the amp

I have been able to send CEC commands from the player to the Amp to turn it on.

I further developed (with help from snippets of code from around the web) the solution so that the interface in SqueezeCenter, when the power button has been pressed sends a TCP packet to the player where the player runs a bash script and in turn sends a CEC command to the AMP - powering it on.

Power button for the player

The Perl plugin that sends the packet when the relevant players power button is pressed Note I have it set to just send packets to the specific dining room player - but I would like it in the future to find the IP of the player that had its power button pressed and send a packet to that instead.

package Plugins::PowerMonitor::Plugin;

use strict;

use IO::Socket;
use Slim::Utils::Log;
use Slim::Control::Request;

my $log = Slim::Utils::Log->addLogCategory(
    {   category     => 'plugin.powerMonitor',
        defaultLevel => 'ERROR',
        description  => getDisplayName(),
    }
);

sub getFunctions {
    return '';
}

sub getDisplayName {
    return 'PLUGIN_POWER_MONITOR';
}

sub initPlugin {
    $log->debug("initPlugin");
    # Subscribe to power events
    Slim::Control::Request::subscribe( \&powerCallback, [ ['power'] ] );
}

sub shutdownPlugin {
    $log->debug("shutdownPlugin");
    Slim::Control::Request::unsubscribe( \&powerCallback );
}

sub powerCallback {
    $log->debug("powerCallback");

    my $request = shift;
    my $client = $request->client() || return;

    my $sock = IO::Socket::INET->new(
        Proto    => 'tcp',
        PeerPort => 6500,
        PeerAddr => '192.168.0.31',
    );
    if ( !$sock ) {
        $log->error("Could not create socket: $!");
        return;
    }

    my $msg = $client->id() . ':' . $client->name() . ':' . $client->power() . $/;
    $log->debug($msg);
    my $rc = $sock->send($msg);
    if ( !$rc ) {
        $log->error("Send error: $!");
    }
}

The Bash script on the player - this sits as a daemon on the player listening for the packet on port 6500:

#!/bin/bash

netcat -lk 6500 | while read line
do
    if echo $line | grep -q 'Dining_Room:1'
    then
        powerStatus=$(echo "pow 5" | cec-client -s -d 1 |grep "power status" |cut -d ' ' -f 3)

        if [ "$powerStatus" = "standby" ]; then
            echo "Powering On Amp....."
            echo "on 5" | cec-client -s -d 1
        fi
    elif echo $line | grep -q 'Dining_Room:0'
    then
        powerStatus=$(echo "pow 5" | cec-client -s -d 1 |grep "power status" |cut -d ' ' -f 3)

        if [ "$powerStatus" = "on" ]; then
            echo "Powering Off Amp....."
            echo "standby 5" | cec-client -s -d 1
        fi
    fi
done

A very hair brained elaborate setup but this is what I have to work with in terms of Perl plugins for Squeezebox.

I would like to know if there is a more stable way of doing this and what would that be - could I tweak the current setup to make it more stable - could I change the Perl script to write a file on the player instead of sending a packet and using netcat (this seams to be the place it breaks)

I don't know Perl but am quite versed with Linux and bash scripting

UPDATE 29/08/2014: On the topic of it sending to the IP of the player it looks like it instantiates a $client and that has a method of name - I wonder what else is available in there - man I wish I knew Perl.

1

There are 1 best solutions below

1
On BEST ANSWER

I decided to change my approach so that the server would SSH into the player and run the relevant script.

Initial tests show this is way more reliable than netcat. I couldn't get the key auth to work so had to put a password in the script.

Perl Script:

package Plugins::PowerMonitor::Plugin;

use strict;
use warnings;

use IO::Socket;

use Slim::Utils::Log;
use Slim::Control::Request;

use Net::SSH::Any;

my $log = Slim::Utils::Log->addLogCategory( {
        category     => 'plugin.powerMonitor',
        defaultLevel => 'ERROR',
        description  => getDisplayName(),
});

sub getFunctions {
        return '';
}

sub getDisplayName {
        return 'PLUGIN_POWER_MONITOR';
}

sub initPlugin {
        $log->debug("initPlugin");
        # Subscribe to power events
        Slim::Control::Request::subscribe(
                \&powerCallback,
                [['power']]
        );
}

sub shutdownPlugin {
        $log->debug("shutdownPlugin");
        Slim::Control::Request::unsubscribe( \&powerCallback );
}

sub powerCallback {
        $log->debug("powerCallback");

        my $request = shift;
        my $client  = $request->client() || return;

my $host = "192.168.0.31";

my $user = "pi";
my $pass = "myPassword";

my $ssh = Net::SSH::Any->new($host, user => $user, password => $pass);

if ($ssh->error) {
$log->error("whee...something wrong here: " . $ssh->error);
}
else {
        my @out = $ssh->capture('nohup /home/pi/ampOn > foo.out 2> foo.err < /dev/null &');
$log->debug("@out");
}

}

Altered bash script:

#!/bin/bash

                if [ ! -f /tmp/ampIsOn ]
                 then
                        powerStatus=$(echo "pow 5" | cec-client -s -d 1 |grep "power status" |cut -d ' ' -f 3)

                        if [ "$powerStatus" = "standby" ]; then
                                echo "Powering On Amp....."
                                echo "on 5" | cec-client -s -d 1
                                touch /tmp/ampIsOn
                        fi

                else
                        powerStatus=$(echo "pow 5" | cec-client -s -d 1 |grep "power status" |cut -d ' ' -f 3)

                        if [ "$powerStatus" = "on" ]; then
                                echo "Powering Off Amp....."
                                echo "standby 5" | cec-client -s -d 1
                                rm /tmp/ampIsOn
                        fi
                fi

I wont mark as correct yet in case someone has some better solutions or hints.