Hi,
inspiriert von 55er driver habe ich eine Schnittstelle für das RIO Protokoll in php geschrieben. Ich habe nicht alle Funktionen übernommen, aber eine Funktion announce eingebaut. Hier bei wird das Script zum Beispiel aufgerufen mit: http://<IP Webserver>/russound.php?Z=1&action=announce&text=Guten Morgen
Es wird zuerst die aktuellen Paramenter der Zonen gelesen, dann wird über Google Translate der text in ein mp3 umgewandelt, in /var/spool/audio zwischengespeichert, der mp3 mit mpg123 auf dem Standard Audio interface ausgeben und die Einstellungen der Zonen wieder zurück geschrieben.
Bedingung ist, dass auf dem Webserver bei korrekter, manueller Einstellung des Russound, eine mp3 Datei richtig ausgegeben wird.
Bei mir läuft das Script auf einem Raspberry und der Audio-Ausgang ist mit einer Quelle (bei mir 6) aud dem Russound MCA-C5 verbunden.
Vielleicht kann es jemand gebraucht. Das Script als russound.php abspeichert, und los geht es. Bei Bedarf kann ich auch zeigen, wie die Einbindung in den Homeserver erfolgt.
-Muecke
inspiriert von 55er driver habe ich eine Schnittstelle für das RIO Protokoll in php geschrieben. Ich habe nicht alle Funktionen übernommen, aber eine Funktion announce eingebaut. Hier bei wird das Script zum Beispiel aufgerufen mit: http://<IP Webserver>/russound.php?Z=1&action=announce&text=Guten Morgen
Es wird zuerst die aktuellen Paramenter der Zonen gelesen, dann wird über Google Translate der text in ein mp3 umgewandelt, in /var/spool/audio zwischengespeichert, der mp3 mit mpg123 auf dem Standard Audio interface ausgeben und die Einstellungen der Zonen wieder zurück geschrieben.
Bedingung ist, dass auf dem Webserver bei korrekter, manueller Einstellung des Russound, eine mp3 Datei richtig ausgegeben wird.
Bei mir läuft das Script auf einem Raspberry und der Audio-Ausgang ist mit einer Quelle (bei mir 6) aud dem Russound MCA-C5 verbunden.
Vielleicht kann es jemand gebraucht. Das Script als russound.php abspeichert, und los geht es. Bei Bedarf kann ich auch zeigen, wie die Einbindung in den Homeserver erfolgt.
-Muecke
PHP-Code:
<html>
<body>
<?php
// Russound MCA RIO php interface Version 1.0.8
// Example: http://<IP Webserver>/russound.php?debug=1&Z=1&action=announce&text=Have a nice day
// Parameter:
// Z or zone: Zone number e.g. 1 or 1,4,5 etc...
// C: Controller number e.g. 1 ( default is 1)
// volume: Volume for announcements and for fade-in (like in My Russound App 1..100)
// source: set zone Z to source number
// test: reads, print and restore MCA config for zone Z
// action:
// On - zone power on
// Off - zone power off
// AllOn - power on all zones
// AllOff - power off all zones
// fadein - power Zone on, set source fade zone to volume
// fadeout - fade zones out
// intro - Plays on intro mp3 to get attention, an not existing name will disable the intro
// VolUp - zones VolumeUp
// VolDown - zones VolumeDown
//
// Requirements:
// Apache with php enabled
// mpg123 playing MP3
// Apache user member of group audio
// Changelog:
// 1.0.4 bugfix announce volume
// 1.0.5 Change get_zone_config to one network request, change function names
// 1.0.6 Bugfixing
// 1.0.7 Add Volume up and down
// 1.0.8 Add parameter intro
// Change the following variables to your needs
//debug mode On=1 Off=0
$debug=0;
//name / ip Roussound
$rs="mcac5";
//number of zones
$maxzone=6;
//Controller number
$controller=1;
//Source number for announcements
$announce_source=6;
//Volume for announcements
$announce_volume=30;
//Directory for announcement cache
$announce_dir="/var/spool/audio/";
//Gong filename
$intro="$announce_dir/gong1.mp3";
//language of announcement
$announce_lang="de";
//Zonenames to allow using of Names instead only Numbers
$zonenames=array( 1 => 'Sauna', 2 => 'Arbeit', 3 => 'Schlafzimmer', 4 => 'Fitness', 5 => 'Wohnzimmer', 6 => 'Kind1');
// Keep your hands off starting from here
$count_zones=0;
$action="";
$text="";
$source=0;
$volume=0;
// activate full error reporting
error_reporting(E_ALL & E_STRICT);
if (isset($_GET['debug'])) {
$debug=filter_input(INPUT_GET, 'debug', FILTER_SANITIZE_STRING);
}
if (isset($_GET['source'])) {
$source=filter_input(INPUT_GET, 'source', FILTER_SANITIZE_STRING);
if ($source < 1 || $source > 6)
die("Illegal Source");
}
if (isset($_GET['action'])) {
$action=filter_input(INPUT_GET, 'action', FILTER_SANITIZE_STRING);
if ($action == "1") {
$action="on";
}
elseif ($action == "0") {
$action="off";
}
}
if (isset($_GET['lang'])) {
$announce_lang=filter_input(INPUT_GET, 'lang', FILTER_SANITIZE_STRING);
}
if (isset($_GET['intro'])) {
$intro=$announce_dir.filter_input(INPUT_GET, 'intro', FILTER_SANITIZE_STRING);
}
if (isset($_GET['C'])) {
$controller=filter_input(INPUT_GET, 'C', FILTER_SANITIZE_STRING);
}
if (isset($_GET['text'])) {
$text=filter_input(INPUT_GET, 'text', FILTER_SANITIZE_STRING);
}
if (isset($_GET['volume'])) {
$volume=filter_input(INPUT_GET, 'volume', FILTER_SANITIZE_STRING);
if ($volume > 0)
$volume = $volume / 2;
}
//Zone either Z oder zone
if (isset($_GET['Z']))
$zone=explode(",",filter_input(INPUT_GET, 'Z', FILTER_SANITIZE_STRING));
if (isset($_GET['zone']))
$zone=explode(",",filter_input(INPUT_GET, 'zone', FILTER_SANITIZE_STRING));
for($i=0; $i < count($zone); $i++) {
$key=array_search($zone[$i],$zonenames);
if ($key)
$zone[$i]=$key;
if ($zone[$i] < 1 || $zone[$i] > $maxzone)
die ("Illegal Zone:".$zone[$i]);
}
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket == false ) {
echo "socket_create() failed: " . socket_strerror(socket_last_error()) . "\n";
}
$result = socket_connect($socket, gethostbyname($rs), 9621);
if ($result == false) {
echo "socket_connect() failed: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
socket_close($socket);
die ("Unable to connect to Russound");
}
if ($debug) {
socket_write($socket, "VERSION\r", 8);
echo "MAIN: " . socket_read($socket, 1024)."<br>";
}
switch (strtolower($action)) {
case "on":
case "off":
foreach ($zone as $z)
{
if ($source)
set_zone_source($socket, $z, $source);
$debug ? print "Main: set Zone " . $z . " " . $action . "<br>" : null;
set_zone_onoff($socket, $z, $action);
}
break;
case "allon":
case "alloff":
socket_write($socket, "EVENT C[$controller].Z[1]!$action\r");
$rc = socket_read ($socket,1024);
echo $debug ? "Main: RC: $rc<br>" : null;
break;
case "source":
foreach ($zone as $z)
set_zone_source($socket, $z, $source);
break;
case "announce":
$file = text2mp3($text);
if ($volume)
$announce_volume=$volume;
foreach ($zone as $z) {
get_zone_config($socket, $z);
set_zone_source($socket, $z, $announce_source);
set_zone_onoff($socket, $z, "On");
set_zone_volume($socket, $z, $announce_volume);
}
//wait 1 sec for the speakers to be ready
sleep(1);
if (file_exists($intro)) {
echo $debug ? "mpg123 $intro<br>" : null;
exec("mpg123 -n 100 -q ".$intro, $output);
if ($debug)
foreach ($output as $line)
echo $line . "<br>";
}
echo $debug ? "mpg123 $file<br>" : null;
exec("mpg123 -q ". $file, $output);
if($debug)
foreach ($output as $line)
echo $line . "<br>";
foreach ($zone as $z) {
set_zone_config($socket, $z);
}
break;
case "volup":
case "voldown":
foreach ($zone as $z) {
set_zone_vol_UpDown($socket, $z, substr($action, 3));
}
break;
case "fadein":
foreach ($zone as $z) {
if ($source)
set_zone_source($socket, $z, $source);
zone_fadein($socket, $z, $volume);
}
break;
case "fadeout":
foreach ($zone as $z) {
get_zone_config($socket, $z);
zone_fadeout($socket, $z);
}
break;
case "test":
$debug=1;
foreach ($zone as $z) {
get_zone_config($socket, $z);
set_zone_config($socket, $z);
}
break;
}
socket_close($socket);
// end of main
// read zone config in an array to restore settings
function get_zone_config($socket, $zone)
{
global $debug, $config, $controller;
$str="GET ".
"C[$controller].Z[$zone].name,".
"C[$controller].Z[$zone].status,".
"C[$controller].Z[$zone].partyMode,".
"C[$controller].Z[$zone].volume,".
"C[$controller].Z[$zone].turnOnVolume,".
"C[$controller].Z[$zone].currentSource,".
"C[$controller].Z[$zone].doNotDisturb";
echo $debug ? __FUNCTION__.": $str<br>" : null;
socket_write($socket, $str."\r");
$line = socket_read($socket, 1024);
if ($line[0] == "S") {
$value = explode(",", substr($line ,2));
foreach ($value as $v) {
$details=explode("=", $v);
$attr=explode(".", $details[0]);
$config[$zone][$attr[2]] = trim(str_replace('"', "", $details[1]));
echo $debug ? __FUNCTION__.": Zone[$zone].[$attr[2]]=" . $config[$zone][$attr[2]] . "<br>" : null;
}
}
else {
echo $debug ? __FUNCTION__.": Result: $line.<br>" : null;
die (__FUNCTION__.": Error, reading from Russound");
}
return;
}
// Read a specific attribute of a zone
function read_zone_attr($socket, $zone, $attr)
{
global $debug, $config, $controller;
echo $debug ? __FUNCTION__.": GET C[$controller].Z[$zone].$attr<br>" : null;
socket_write($socket, "GET C[".$controller."].Z[".$zone."].".$attr."\r");
$line = socket_read($socket, 1024);
echo $debug ? __FUNCTION__.": Line: $line<br>" : null;
if ($line[0] == "S") {
$value = explode("=", $line);
$config[$zone][$attr] = trim(str_replace('"', "", $value[1]));
echo $debug ? print __FUNCTION__.": Z[$zone].[$attr]= ". $config[$zone][$attr]."<br>" : null;
}
else {
echo $debug ? __FUNCTION__.": Result: $line<br>" :null;
die (__FUNCTION__.": Error, reading from Russound");
}
return $config[$zone][$attr];
}
// Restore zone settings
function set_zone_config($socket, $zone)
{
global $debug, $config, $controller;
if ($config[$zone]["status"] == "ON") {
echo $debug ? __FUNCTION__.": Zone [$zone][volume]=".$config[$zone]["volume"]."<br>" : null;
set_zone_volume($socket, $zone, $config[$zone]["volume"]);
}
else
set_zone_volume($socket, $zone, 0);
set_zone_source($socket, $zone, $config[$zone]["currentSource"]);
set_zone_partymode($socket, $zone, $config[$zone]["partyMode"]);
set_zone_onoff($socket, $zone, $config[$zone]["status"]);
}
function set_zone_partymode($socket, $zone, $onoff)
{
global $debug, $controller;
echo $debug ? __FUNCTION__.": EVENT C[$controller].Z[$zone]!partyMode $onoff<br>" : null;
socket_write($socket, "EVENT C[$controller].Z[$zone]!partyMode $onoff\r");
$rc = socket_read ($socket,1024);
echo $debug ? __FUNCTION__.": RC: $rc<br>" : null;
return $rc;
}
function set_zone_volume($socket, $zone, $volume)
{
global $debug, $controller;
echo $debug ? __FUNCTION__.": EVENT C[$controller].Z[$zone]!KeyPress Volume $volume<br>" : null;
socket_write($socket, "EVENT C[".$controller."].Z[".$zone."]!KeyPress Volume ".$volume."\r");
$rc = socket_read ($socket,1024);
echo $debug ? __FUNCTION__.": RC: $rc<br>" : null;
return $rc;
}
function set_zone_source($socket, $zone, $source)
{
global $debug, $controller;
echo $debug ? __FUNCTION__.": EVENT C[$controller].Z[$zone]!KeyRelease SelectSource $source<br>" : null;
socket_write($socket, "EVENT C[".$controller."].Z[".$zone."]!KeyRelease SelectSource ".$source."\r");
$rc = socket_read ($socket,1024);
echo $debug ? __FUNCTION__.": RC: $rc<br>" : null;
return $rc;
}
// Power zone on and fade in volume
function zone_fadein($socket, $zone, $volume)
{
global $debug, $controller, $config;
if ($volume == 0) {
$volume=read_zone_attr($socket, $zone, "turnOnVolume");
}
set_zone_onoff($socket, $zone, "On");
set_zone_volume($socket, $zone, 0);
echo $debug ? __FUNCTION__.": Volume $volume<br>" : null;
for ($i = 1; $i <= $volume; $i++) {
set_zone_vol_UpDown($socket, $zone, "Up");
usleep(200000);
}
}
// Decrease zone volume slowly to zero
function zone_fadeout($socket, $zone)
{
global $debug, $controller, $config;
echo $debug ? __FUNCTION__.": Z[$zone]["volume"]=".$config[$z]["volume"]."<br>" : null;
for ($i = 1; $i <= $config[$zone]["volume"]; $i++) {
set_zone_vol_UpDown($socket, $zone, "Down");
usleep(200000);
}
}
function set_zone_vol_UpDown ($socket, $zone, $UpDown)
{
global $debug, $controller, $config;
echo $debug ? __FUNCTION__.": EVENT C[$controller].Z[$zone]!KeyPress Volume$UpDown<br>" : null;
socket_write($socket, "EVENT C[".$controller."].Z[".$zone."]!KeyPress Volume".$UpDown."\r");
$rc = socket_read ($socket,1024);
echo $debug ? __FUNCTION__.": RC: $rc<br>" : null;
}
function set_zone_onoff($socket, $zone, $onoff)
{
global $debug, $controller;
echo $debug ? __FUNCTION__.": EVENT C[$controller].Z[$zone]!Zone$onoff<br>" : null;
socket_write($socket, "EVENT C[".$controller."].Z[".$zone."]!Zone".$onoff."\r");
$rc = socket_read ($socket,1024);
echo $debug ? __FUNCTION__.": RC: $rc<br>" : null;
return $rc;
}
function text2mp3 ($text)
{
global $debug, $announce_dir, $announce_lang;
// Convert Words (text) to Speech (MP3)
// ------------------------------------
// Google Translate API cannot handle strings > 100 characters
$text = substr($text, 0, 100);
// Replace the non-alphanumeric characters
// The spaces in the sentence are replaced with the Plus symbol
$text = urlencode($text);
$debug ? print "Text: ".$text."<br>" : null;
// Name of the MP3 file generated using the MD5 hash
$md5 = md5($text);
// Save the MP3 file in this folder with the .mp3 extension
$file = $announce_dir . $md5 . ".mp3";
// If the MP3 file exists, do not create a new request
if (!file_exists($file)) {
$debug ? print "URL: http://translate.google.de/translate_tts?&q=".$text."&tl=" . $announce_lang . "&client=t<br>" : null;
$mp3 = file_get_contents("http://translate.google.de/translate_tts?&q=".$text."&tl=" . $announce_lang . "&client=t");
if (strlen($mp3) > 3) {
//mp3 stream received successfull, write mp3 and index
file_put_contents($file, $mp3);
file_put_contents($announce_dir . "index.log", $md5 . "\t" . $text . "\n", FILE_APPEND|LOCK_EX);
}
else
die ("Text to mp3 failed");
}
return $file;
}
?>
</html>
Kommentar