PHP Sonos (Klasse zum Ansteuern einzelner Player)

Hallo miteinander,

ich seh Euch schon mit den Augen rollen … :confused:

wäre es möglich, für die Neulinge und ev. PHP Einsteiger mal kurz einen Einstieg in die Verwendung der PHPSonos Klasse zu geben.

Ich habe im IPS Baum eine neue Kategorie „Sonos“ angelegt und die Klasse als Script mit dem vorgegebenen Dateinamen gespeichert.

Jetzt will ich ohne Webfrontbenutzung einfach meinen Hauptplayer mit der IP 10.3.2.10 mit einem weiteren Player mit der IP 10.3.2.12 zu einer Gruppe verbinden, dann eine definierte Lautstärke einstellen und dann SmartRadio Augsburg abspielen.

Gebt mir bitte nur mal einen Tip, wie ich die Einzelteile in einem Script verbinde.

Herzlichen Dank dafür,
Stromer

Hi Stromer,

ich denke, am sinnvollsten ist es wenn du diesen Thread nebst den WIKI-Beiträgen von bengie durchhühnerst, Schritt für Schritt bengie’s Lösung (die ziemlich gut gelöst ist und auch -bis auf Kleinigkeiten - sehr gut funktioniert) implementierst. Diese Lösung ist eine Weiterentwicklung der Sonos-Klasse und beinhaltet deutlich mehr „User-Interface-Funktionen“ -> quasi näher an einer fertigen Lösung.
Dann sollte auch recht schnell klar werden wie das ganze fúnktioniert. Fragen werden in diesem Thread auch gern beantworet.

Hi Raketenschnecke,
die Dinger habe ich doch schon durchgearbeitet. Für mich stellt sich gerade die Frage, wo ich die RINCON herbekomme oder auch den String zum richtigen Radiosender finde…

Ansonsten, liege ich mit dem Script so einigermaßen richtig? Kann es erst heute Abend testen.

  1. Zonen verbinden
  2. Lautstärke einstellen
  3. I-Net Radiosender einstellen und abspielen

Gr, Stromer

Anbei mal meine zusammenkopierte Version.


<?
include("PHPSonos.inc.php"); 

// SonosMaster 10.3.2.51
// SonosSlave 10.3.2.52

 


// Get Script Parent 
$ParentID=(int)br_objParent ($IPS_SELF); 
// Talk to Coord 
$sonos = new PHPSonos("10.3.2.51"); //Sonos ZP IP Adresse Wohnzimmer


/* ****************************** ZONEATTR AND INFO EXAMPLE *********************************** 
$ZoneAttributes = $sonos->GetZoneAttributes(); 
print_r( $ZoneAttributes); 
$ZoneInfo = $sonos->GetZoneInfo(); 
print_r( $ZoneInfo); 
// ******************************* /ZONEATTR AND INFO EXAMPLE ************************************/ 


/* ****************************** AddMember EXAMPLE****************************/ 

$AddMember = $sonos->AddMember("RINCON_000E5825411201400"); 
echo "
DEBUG AddMember:
"; 
print_r( $AddMember); 

// Talk to slave 
$sonos = new PHPSonos("10.3.2.52"); //Slave Sonos ZP IP Address Sonos Schlafzimmer  
echo "
"; 
$ret = $sonos->SetAVTransportURI("x-rincon:" . "RINCON_000E5832FB5C01400"); 
echo "
DEBUG SetAVTransportURI to "."x-rincon:" . "RINCON_000E5832FB5C01400" ."
"; 
// Playing starts 

//IPS_Sleep(1000); 
//* ****************************** RemoveMember EXAMPLE**************************** 
// Talk to Coord 
// $sonos = new PHPSonos("10.3.2.51"); //Sonos ZP IPAdresse 
// $RemoveMember = $sonos->RemoveMember("RINCON_000E5825411201400"); 
// echo "
DEBUG RemoveMember:
"; 
// print_r( $RemoveMember); 

// Talk to slave 
// $sonos = new PHPSonos("10.3.2.52"); //Slave Sonos ZP IPAddress 
// needed for stop of playback on Slave 
// $sonos->SetAVTransportURI(""); 
// echo "
DEBUG SetAVTransportURI to NONE 
"; 
//Playing stops 
// ****************************** /AddMember and RemoveMember EXAMPLE****************************//



// Steuern der Lautstärke über eine Variable

$Volume = GetValueInteger(49317 /*[.Sound\.Control\iMP_Volume]*/ ); 
$sonos = new PHPSonos("10.3.2.51"); //Sonos ZP IPAdresse Wohnzimmer
$sonos->SetVolume($Volume); //0-100 in %  

Radiosender abspielen / Play radio 
$sonos->SetRadio("x-rincon-mp3radio://players.creacast.com/creacast/klassik/playlist.pls", "Klassik Radio"); 

>?

Hallo Stromer,
Du solltest Dir die br_sonos Sachen (setzen auf die PHPSonos Klasse auf) mal ansehen, da Sie auch automatisch den Status der Zonen mitschreiben und Du sehr einfach an die passenden Infos wie z.B. die Rincon kommst (stehen schon in einer Variable).

Wenn Du ohne br_sonos die Rincon haben willst, erhälst Du Sie wie unter Wiki: PHPSonos -> siehe FAQ beschrieben. :stuck_out_tongue:

Außerdem könntest Du über die Methode GetZoneInfo(); die MAC abfragen und daraus die RINCON ableiten.
Br_sonos macht das im Setup Z.B. so:

	$arrzoneplayers[$IP]['Rincon']="RINCON_".implode("",explode(":",$ZoneInfo['MACAddress']))."01400";

Die Radio URL bildest Du aus den Informationen von der Homepage eines Senders. Oder Du liest den String mit dem Intel Tool DeviceSpy aus dem Gerät aus (GetPositionInfo) bzw. nutzt die gleichnamige PHPSonos Methode.
Ein Netzwerksniffer ginge sonst natürlich auch. :slight_smile:

Ansonsten, liege ich mit dem Script so einigermaßen richtig? Kann es erst heute Abend testen.

  1. Zonen verbinden
  2. Lautstärke einstellen
  3. I-Net Radiosender einstellen und abspielen

Ja, ich denke Dein geposteter Code wird funktionieren, wenn die Rincons stimmen. :smiley:
Du musst noch diese Zeile entfernen (nicht notwendig, stammt aus br_ips / br_sonos)

$ParentID=(int)br_objParent ($IPS_SELF); 

Wobei ich bisher immer zuerst spielende Zonen hatte und dann die Addmember Methode ausgeführt habe - sollte aber kein Unterschied machen.

Viele Grüße und Viel Spaß, Benjamin

[Edit]: Die Infos aus diesem Beitrag sind jetzt auch ins Wiki eingebaut

Hi Bengie,
habe jetzt erst Deine Anfrage gesehen. Bin z.Zt. leider nur selten dazu gekommen an der Klasse weiter zu arbeiten.

Ich poste am Ende mal die Browse Funktion.

Ich habe vorher noch eine Frage. Wie kann ich die ZonePlayer ermitteln?
Z.Zt. habe ich eine Konfigurationsdatei, die sämtliche Geräte fest eingetragen hat. Bei mir sind aber nicht immer alle Geräte an und ich möchte nun ermitteln, welche Geräte an sind bzw. im Sonos-System bekannt.
Der Desktop Kontroller macht das ja auch sehr flott aber im wireshark kann ich nicht wirklich erkennen, wie er das macht.
Hast Du da eine Idee?

Hier nun die Browse funktion, wie ich sie verwende:

    //Browse Informationen
     public function Browse($value,$meta="BrowseDirectChildren")
    {

       switch($meta){
       case 'BrowseDirectChildren':
       case 'c':
       case 'child':
      	$meta="BrowseDirectChildren";
       break; 	
       case 'BrowseMetadata':
       case 'm':
       case 'meta':
	       	$meta = "BrowseMetadata";
       break;
       default:
       return false;       	
      } 
        $header='POST /MediaServer/ContentDirectory/Control HTTP/1.1
SOAPACTION: "urn:schemas-upnp-org:service:ContentDirectory:1#Browse"
CONTENT-TYPE: text/xml; charset="utf-8"
HOST: '.$this->address.':1400';
$xml='<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>'.htmlspecialchars($value).'</ObjectID><BrowseFlag>'.$meta.'</BrowseFlag><Filter></Filter><StartingIndex>0</StartingIndex><RequestedCount>1000</RequestedCount><SortCriteria></SortCriteria></u:Browse>
</s:Body>
</s:Envelope>';
$content=$header . '
Content-Length: '. strlen($xml) .'

'. $xml;

    $returnContent = $this->sendPacket($content);
    $xmlParser = xml_parser_create();
        $returnContent = substr($returnContent, stripos($returnContent, '<'));
        $returnContent = substr($returnContent, 0, strrpos($returnContent, '>') + 4);
        $returnContent = str_replace(array("<", ">", """, "&", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);

        $xml = new SimpleXMLElement($returnContent);
        $liste = array();
        for($i=0,$size=count($xml);$i<$size;$i++)
        {
            //Wenn Container vorhanden, dann ist es ein Browse Element
            //Wenn Item vorhanden, dann ist es ein Song.
            if(isset($xml->container[$i])){
            		$aktrow = $xml->container[$i];
		            $attr = $xml->container[$i]->attributes();
		            $liste[$i]['typ'] = "container";
             }else if(isset($xml->item[$i])){
            	//Item vorhanden also nur noch Musik
            		$aktrow = $xml->item[$i];
		            $attr = $xml->item[$i]->attributes();
		            $liste[$i]['typ'] = "item";
            }else{
            	//Fehler aufgetreten
            	return;
            }	
            		$id = $attr['id'];
		            $parentid = $attr['parentID'];
		            $albumart = $aktrow->xpath("upnp:albumArtURI");
		            $titel = $aktrow->xpath("dc:title");
		            $interpret = $aktrow->xpath("dc:creator");
		            $album = $aktrow->xpath("upnp:album");
	            	if(isset($aktrow->res)){
	  	          	$res = (string)$aktrow->res;
	  	          	$liste[$i]['res'] = urlencode($res);
		          		
		          	}else{
	    	      		$liste[$i]['res'] = "leer";
	      	    	}
	      	    		$resattr = $aktrow->res->attributes();
									if(isset($resattr['duration'])){
		          			$liste[$i]['duration']=(string)$resattr['duration'];
		          		}else{
		          			$liste[$i]['duration']="leer";
		          		}
	        	    if(isset($albumart[0])){
	                $liste[$i]['albumArtURI']="http://" . $this->address . ":1400".(string)$albumart[0];
	          	  }else{
	                $liste[$i]['albumArtURI'] ="leer";
	            	}
	            	$liste[$i]['title']=(string)$titel[0];
	            	if(isset($interpret[0])){
             		   $liste[$i]['artist']=(string)$interpret[0];
            		}else{
		               $liste[$i]['artist']="leer";
    		        }
		            if(isset($id) && !empty($id)){
		                $liste[$i]['id']=urlencode((string)$id);
		            }else{
		                $liste[$i]['id']="leer";
		            }
		            if(isset($parentid) && !empty($parentid)){
		                $liste[$i]['parentid']=urlencode((string)$parentid);
		            }else{
		                $liste[$i]['parentid']="leer";
		            }
           			if(isset($album[0])){
                	$liste[$i]['album']=(string)$album[0];
            		}else{
                	$liste[$i]['album']="leer";
            		}
            
        }
return $liste;
    }

Welcome Back! :smiley:

Der Controller nutzt das SSDP Protokoll. Dabei senden die Sonos ZP eine Nachricht an einen Controlpoint (Controller) bzw. man kann durch senden einer Nachricht die Geräte (ZP) zur Antwort ermuntern.

Die Wikipedia Artikel bieten einen guten Überblick fürs erste:
Universal Plug and Play
Simple Service Discovery Protocol

Ich brauche das bisher nicht, daher habe ich mir noch keine Gedanken zur Umsetzung mit PHP gemacht. Im Wireshark habe ich die Requests aber schon gesehen.

Ich hoffe das hilft Dir weiter und ich schreibe nichts, was Du schon kennst.

Hier nun die Browse funktion, wie ich sie verwende:

Danke, schaue ich mir mal an! :slight_smile:

Grüße, Benjamin

Hallo zusammen,

damit nach den vielen Monaten auch mal eine nicht als „Test“ markierte Klasse zugänglich ist, veröffentliche ich die nun seit einiger Zeit genutze Klasse mit unseren Änderungen (welche so bis auf die Kommentare auch im br_sonos.zip sein sollte).

Bei der Entwicklung gab es teilweise ein Vor- und Zurück und ich habe versucht zumindest einen Teil davon über die Historie im Vergleich zur letzten Version abzubilden.

Historie:


- 110328 - br corrected titel to title and other things...
- 110328 - br added optional parameter id to SaveQueue
- 110406 - br edited Seek to accept UPNP Unit parameter as option (sec. arg is Target then)
- 110406 - br edited GetPositionInfo to also reflect UPNP return value names
- 110406 - br fixed non valid soap request in seek()
- 110406 - br added return of CurrentURI and CurrentUriMetaData to GetMediaInfo (Current File or QUEUE)
				This info is needed to restart a queue, pl or radiostation
- 110407 - br consolidated SetRadio, SetQueue and SetAVTransportURI
				two last now also support MetaData as optional, 2nd parameter; SetRadio supports the name of a radiostation as an optional second parameter
- 110529 - br GetMediaInfo now returns Radio station in the array, key is title
- 110529 - ta lun added browse functions
- 110529 - br fixed problem with missing parentid in browse()
- 110529 - iamking added GetAlarmTime()
- 110529 - ta lun fixed misc bugs and GetAlarmTime() now returns an array

- 110530 - br edited Browse() to reflect upnp possibilities
- 110601 - br renamed GetAlarmtime to ListAlarms to reflect upnp Names
- 110601 - iamking improved ListAlarms - added ProgramURI, ProgramMetaData, PlayMode, Volume, IncludeLinkedZones
- 110614 - br added parameters to Browse / http://110530www.ip-symcon.de/forum/f53/php-sonos-klasse-ansteuern-einzelner-player-7676/index10.html#post120977
- 110627 - talun edited GetSonosPlaylists: urlencode file
- 110711 - br fixed Problems in SetAVTransportUri
TODO/BUG - 110819 - br/talun TODO edit Browse to return duration

Für mich pers. ist mein nächstes Todo: die Änderungen in der Browse Funktion von Ta Lun zu sichten, testen und einzubauen. Außerdem werde ich wohl mal Routinen zum Auslesen der Daten der ZP Eingänge bauen (da man diese ja leicht ansprechen kann, möchte ich ja auch wissen wie mein Input benannt ist).

Ansonsten sind Subcribes und die Suche nach ZP im Netz (mit PHP) natürlich sehr spannend.

[EDIT: Wiki ist jetzt aktualisiert. bitte Info, wenn Ihr eine Idee habt wie man an die Bilder der Radiosender kommt bzw. wo bisher das Problem ist.]

Grüße, Benjamin

PHPSonos.zip (9.84 KB)

Hallo Benjamin,
habe jetzt mal wegen der Bilder eine Anfrage im deutschen SONOS-Forum gestellt. Mal sehen, vielleicht kommt ja da was rüber.

Grüße, Jürgen

Hallo,
habe im SONOS-Forum jetzt den Hinweis bekommen, dass die Quelle der Radiostationen von Radiotime.com kommt und dass es dort auch eine [b]API[/b] gibt. Kann persönlich leider nicht viel damit anfangen; vielleicht hilft es euch aber weiter.

Grüße, Jürgen

Super, Danke Jürgen! :smiley:

Ich habe mir die Infos durchgesehen und möchte die bisherigen Ergebnisse nicht zurückhalten: :slight_smile:

Wenn man per Sonos Controller abspielt:
nutzt dieser defakto zuerst:

http://legato.radiotime.com/Tune.ashx?id=s116053&partnerId=Sonos&serial=00-0E-58-25-41-12:4

dann ein Redirect zu:

x-rincon-mp3radio://stream.antenne.com/hra-nds/mp3-64/tunein/

o.g. kann man auf dem eigenen Sonos unter

http://192.168.0.115:1400/status/radiolog

nachvollziehen.

API: API Reference « Inside RadioTime
OPML API: Describe « Inside RadioTime

Das Logo kommt dann von hier:

http://opml.radiotime.com/Describe.ashx?c=nowplaying&id=s32500&partnerId=<id>&serial=<serial>

bzw. (geht auch Ohne Sonos MAC Adresse, welche normalerweise als Serial übergeben wird)

http://opml.radiotime.com/Describe.ashx?c=nowplaying&id=s116053

In der Antwort findet man das Logo so vor:

<logo>http://radiotime-logos.s3.amazonaws.com/s116053.png</logo>

Nachträglich/ per PHPSonos, kann man die Stationid rausfinden per GetMediaInfo als CurrentURI und diese dann zum bilden des o.g. OPML Aufrufs verwenden.

Wenn man per PHPSonos die Stream URL setzt:
Wird erstmal kein Logo (auch nicht beim Original Controller angezeigt), sondern nur die per Metadata an den Set TransportUri übergebenen Infos (da setzen wir derzeit nur „Title“).

Also müsste man in diesem Fall wohl die Logo Url beim SetAVTransportUri mitgeben:

<upnp:albumArtURI>http://</upnp:albumArtURI>

… um Sie dann später per GetPositionInfo zu erhalten…

Ein schöner Ansatzpunkt - ich muss noch genauer testen, aber tausend Dank für die interessanten Infos!! :cool:

Die Infos kannst Du auch im Sonos Forum gerne verlinken.

Viele Grüße, Benjamin

EDIT: siehe auch http://www.ip-symcon.de/forum/f53/php-sonos-klasse-ansteuern-einzelner-player-7676/index15.html#post130430

Hi, ich erhalte einen Fehler vom Sonos ZP…

Ich habe Dein Browse testweise so in die Klasse gebaut (also um die zusätzlichen Parameter erweitert):


    //Browse Informationen
   public function Browse($value,$meta="BrowseDirectChildren",$filter="",$sindex="0",$rcount="1000",$sc="")

    { 

       switch($meta){ 
       case 'BrowseDirectChildren': 
       case 'c': 
       case 'child': 
          $meta="BrowseDirectChildren"; 
       break;      
       case 'BrowseMetadata': 
       case 'm': 
       case 'meta': 
               $meta = "BrowseMetadata"; 
       break; 
       default: 
       return false;            
      }  
        $header='POST /MediaServer/ContentDirectory/Control HTTP/1.1 
SOAPACTION: "urn:schemas-upnp-org:service:ContentDirectory:1#Browse" 
CONTENT-TYPE: text/xml; charset="utf-8" 
HOST: '.$this->address.':1400'; 
$xml='<?xml version="1.0" encoding="utf-8"?> 
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
<s:Body>.
<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>'.htmlspecialchars($value).'</ObjectID><BrowseFlag>'.$meta.'</BrowseFlag><Filter>'.$filter.'</Filter><StartingIndex>'.$sindex.'</StartingIndex><RequestedCount>'.$rcount.'</RequestedCount><SortCriteria>'.$sc.'</SortCriteria></u:Browse>
</s:Body>
</s:Envelope>'; 
$content=$header . ' 
Content-Length: '. strlen($xml) .' 

'. $xml; 

    $returnContent = $this->sendPacket($content); 
    $xmlParser = xml_parser_create(); 
        $returnContent = substr($returnContent, stripos($returnContent, '<')); 
        $returnContent = substr($returnContent, 0, strrpos($returnContent, '>') + 4); 
        $returnContent = str_replace(array("<", ">", """, "&", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent); 

        $xml = new SimpleXMLElement($returnContent); 
        $liste = array(); 
        for($i=0,$size=count($xml);$i<$size;$i++) 
        { 
            //Wenn Container vorhanden, dann ist es ein Browse Element 
            //Wenn Item vorhanden, dann ist es ein Song. 
            if(isset($xml->container[$i])){ 
                    $aktrow = $xml->container[$i]; 
                    $attr = $xml->container[$i]->attributes(); 
                    $liste[$i]['typ'] = "container"; 
             }else if(isset($xml->item[$i])){ 
                //Item vorhanden also nur noch Musik 
                    $aktrow = $xml->item[$i]; 
                    $attr = $xml->item[$i]->attributes(); 
                    $liste[$i]['typ'] = "item"; 
            }else{ 
                //Fehler aufgetreten 
                return; 
            }     
                    $id = $attr['id']; 
                    $parentid = $attr['parentID']; 
                    $albumart = $aktrow->xpath("upnp:albumArtURI"); 
                    $titel = $aktrow->xpath("dc:title"); 
                    $interpret = $aktrow->xpath("dc:creator"); 
                    $album = $aktrow->xpath("upnp:album"); 
                    if(isset($aktrow->res)){ 
                        $res = (string)$aktrow->res; 
                        $liste[$i]['res'] = urlencode($res); 
                           
                      }else{ 
                          $liste[$i]['res'] = "leer"; 
                      } 
                          $resattr = $aktrow->res->attributes(); 
                                    if(isset($resattr['duration'])){ 
                              $liste[$i]['duration']=(string)$resattr['duration']; 
                          }else{ 
                              $liste[$i]['duration']="leer"; 
                          } 
                    if(isset($albumart[0])){ 
                    $liste[$i]['albumArtURI']="http://" . $this->address . ":1400".(string)$albumart[0]; 
                    }else{ 
                    $liste[$i]['albumArtURI'] ="leer"; 
                    } 
                    $liste[$i]['title']=(string)$titel[0]; 
                    if(isset($interpret[0])){ 
                        $liste[$i]['artist']=(string)$interpret[0]; 
                    }else{ 
                       $liste[$i]['artist']="leer"; 
                    } 
                    if(isset($id) && !empty($id)){ 
                        $liste[$i]['id']=urlencode((string)$id); 
                    }else{ 
                        $liste[$i]['id']="leer"; 
                    } 
                    if(isset($parentid) && !empty($parentid)){ 
                        $liste[$i]['parentid']=urlencode((string)$parentid); 
                    }else{ 
                        $liste[$i]['parentid']="leer"; 
                    } 
                       if(isset($album[0])){ 
                    $liste[$i]['album']=(string)$album[0]; 
                    }else{ 
                    $liste[$i]['album']="leer"; 
                    } 
             
        } 
return $liste; 
    } 

Test erfolgt so:

$sonoslists=$sonos->GetSONOSPlaylists();
print_r($sonoslists);
foreach($sonoslists as $sonoslist)
{
	if ($sonoslist['title']=='Test') $id=$sonoslist['id'];
}
echo "
===============================================================
";
$browseliste = $sonos->Browse("SQ:53","c");
            print_r($browseliste);
echo "
===============================================================
";

Ausgabe ist:


Array
(
    [0] => Array
        (
            [id] => SQ:3
            [title] => Enya cd 1
            [typ] => Sonos
            [file] => file%3A%2F%2F%2Fjffs%2Fsettings%2Fsavedqueues.rsq%233
        )

    [1] => Array
        (
            [id] => SQ:2
            [title] => Enya cd 2
            [typ] => Sonos
            [file] => file%3A%2F%2F%2Fjffs%2Fsettings%2Fsavedqueues.rsq%232
        )

    [2] => Array
        (
            [id] => SQ:4
            [title] => Enya cd 3
            [typ] => Sonos
            [file] => file%3A%2F%2F%2Fjffs%2Fsettings%2Fsavedqueues.rsq%234
        )

    [3] => Array
        (
            [id] => SQ:5
            [title] => Harry Potter
            [typ] => Sonos
            [file] => file%3A%2F%2F%2Fjffs%2Fsettings%2Fsavedqueues.rsq%235
        )

    [4] => Array
        (
            [id] => SQ:7
            [title] => Rock and Roll
            [typ] => Sonos
            [file] => file%3A%2F%2F%2Fjffs%2Fsettings%2Fsavedqueues.rsq%237
        )

    [5] => Array
        (
            [id] => SQ:53
            [title] => Test
            [typ] => Sonos
            [file] => file%3A%2F%2F%2Fjffs%2Fsettings%2Fsavedqueues.rsq%2353
        )

)

===============================================================

Fatal error:  Uncaught exception 'Exception' with message 'Error sending command: HTTP/1.1 400 Bad Request
Content-type: text/html
Connection: close

Error 400Error 400Bad Request' in C:\IP-Symcon\scripts\PHPSonos.inc.php:1446
Stack trace:
#0 C:\IP-Symcon\scripts\PHPSonos.inc.php(1315): PHPSonos->sendPacket('POST /MediaServ...')
#1 C:\IP-Symcon\scripts\288br_sonos_test.php(168): PHPSonos->Browse('SQ:53', 'c')
#2 {main}
  thrown in C:\IP-Symcon\scripts\PHPSonos.inc.php on line 1446

Die SQ:53 sollte es ja nach der o.g. Ausgabe geben? Hab ich das Falsch übergeben oder habe ich beim einbauen der zusätzlichen Parameter einen Fehler gemacht?

Hast Du eine Idee?

Grüße, Benjamin

ich versteh nur Bahnhof :wink: Verfolge das Thema aber mit brennendem Interesse, was mich am interessiert ist eine Anzeige- und Auswahlfunktion der Musik-Quellen. Ich sehe: Ihr kommt voran:)

:smiley:

Wir sind doch kein Fließband hier… :stuck_out_tongue: :o :rolleyes: ich hab das mal eingebaut :smiley:

Dies in die PHPSonos einfügen:

	public function GetAudioInput() // added br
	{

$header='POST /AudioIn/Control HTTP/1.1
SOAPACTION: "urn:schemas-upnp-org:service:AudioIn:1#GetAudioInputAttributes"
CONTENT-TYPE: text/xml; charset="utf-8"
HOST: '.$this->address.':1400';
$xml='<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:GetAudioInputAttributes xmlns:u="urn:schemas-upnp-org:service:AudioIn:1"/>
</s:Body>
</s:Envelope>';
$content=$header . '
Content-Length: '. strlen($xml) .'

'. $xml;

$returnContent = $this->XMLsendPacket($content);


		$xmlParser = xml_parser_create("UTF-8");
		xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
		xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
		xml_parser_free($xmlParser);



		$AudioInReturn = Array();

		$key="CurrentName"; // Lookfor
		if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$AudioInReturn[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
      } else { $AudioInReturn[$key] = ""; }

		$key="CurrentIcon"; // Lookfor
		if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$AudioInReturn[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
      } else { $AudioInReturn[$key] = ""; }


		return $AudioInReturn; //Assoziatives Array
 	}


Input einer Ip abfragen:

$Inputs=$sonos->GetAudioInput();
print_r($Inputs);

Output (Beispiel):

Array
(
    [CurrentName] => Heimkino
    [CurrentIcon] => HomeTheater
)

Das Abspielen ist im Wiki beschrieben: PHPSonos -> Beispiel 5.11 -> Abspielen eines Signals am Audioeingang / Playing signal the sonos analog input

Meintest Du sowas?
Grüße, Benjamin

Edit: …ist dann ggf. auch im nächsten Zip drin.

immer locker bleiben: was lange währt wird gut;)

Klappt den der o.g. Code bei Dir auch? Bei mir schon, aber ohne Deine RM dazu stehe ich irgendwie auch im Dunkeln.

hi bengie,

klar bekommste von mir ne Rückmeldung. Den Code oben hab ich noch nicht eingebaut (Momentan ist bei mir Frozen Zone):wink:

Hallo Benjamin,
habe Deinen Code „GetAudioInput“ mal bei mir in die PHPSonos eingefügt und dann abgefragt. Bei mir kommt dann jedoch ein Timeout: „Fatal error: Maximum execution time of 30 seconds exceeded in [Sonos\SONOSLibs\PHPSonos.inc.php] on line 1411“ Das ist bei mir die Zeile „$buffer = fgets($fp,128);“

Grüße, Jürgen

Sodele ich habe nun mal Deine Filter für die Funktion Browse eingebaut und ich bekomme keine Probleme.

Bei mir sieht eine Ausgabe wie folgt aus für eine Playlist:

[0] => Array
(
[typ] => item
[res] => x-file-cifs%3A%2F%2FTAMINAS%2FMusik%2FTa%2520Lun%2FSonos%2FEra%2FEra%2F01%2520Era.mp3
[duration] => leer
[albumArtURI] => http://192.168.0.206:1400/getaa?u=x-file-cifs://TAMINAS/Musik/Ta%20Lun/Sonos/Era/Era/01%20Era.mp3&v=294
[title] => Era
[artist] => Era
[id] => S%3A%2F%2FTAMINAS%2FMusik%2FTa%2520Lun%2FSonos%2FEra%2FEra%2F01%2520Era.mp3
[parentid] => SQ%3A1
[album] => Era
)

[1] =&gt; Array
    (
        [typ] =&gt; item
        [res] =&gt; x-file-cifs%3A%2F%2FTAMINAS%2FMusik%2FTa%2520Lun%2FSonos%2FEra%2FEra%2F02%2520Ameno%2520Remix.mp3
        [duration] =&gt; leer
        [albumArtURI] =&gt; http://192.168.0.206:1400/getaa?u=x-file-cifs://TAMINAS/Musik/Ta%20Lun/Sonos/Era/Era/02%20Ameno%20Remix.mp3&v=294
        [title] =&gt; Ameno Remix
        [artist] =&gt; Era
        [id] =&gt; S%3A%2F%2FTAMINAS%2FMusik%2FTa%2520Lun%2FSonos%2FEra%2FEra%2F02%2520Ameno%2520Remix.mp3
        [parentid] =&gt; SQ%3A1
        [album] =&gt; Era
    )
[2] =&gt; Array
    (
        [typ] =&gt; item
        [res] =&gt; x-file-cifs%3A%2F%2FTAMINAS%2FMusik%2FTa%2520Lun%2FSonos%2FEra%2FEra%2F03%2520Cathar%2520Rhythm.mp3
        [duration] =&gt; leer
        [albumArtURI] =&gt; http://192.168.0.206:1400/getaa?u=x-file-cifs://TAMINAS/Musik/Ta%20Lun/Sonos/Era/Era/03%20Cathar%20Rhythm.mp3&v=294
        [title] =&gt; Cathar Rhythm
        [artist] =&gt; Era
        [id] =&gt; S%3A%2F%2FTAMINAS%2FMusik%2FTa%2520Lun%2FSonos%2FEra%2FEra%2F03%2520Cathar%2520Rhythm.mp3
        [parentid] =&gt; SQ%3A1
        [album] =&gt; Era
    )

Ich habe das gleiche gemacht wie Du habe mir mit GetSonosPlaylists die Playlist ausgegeben und habe mal meine höchste ID genommen und diese aufgerufen. Mal mit den Parameter „c“ mal ohne und jedes mal funktioniert es.
Ich hänge mal meine Klasse mit dran. Bitte teste das einmal damit.
Ich glaube ich hatte das wieder Rückgängig gemacht aber ich hatte beim Event rumgespiele auch mit den funktionen
XMLsendPacket
und
sendPacket

gespielt, da diese sonst zu Timeouts führten (in den ersten test jedenfalls)

Hoffe Du findest was und wir können wieder auf einer Klasse aufsetzen.

Gruß
Ta Lun
PHPSonos.inc.zip (8.36 KB)

EDIT:
Ausgabe von GetAudioInput():
Array
(
[CurrentName] => Line-In
[CurrentIcon] =>
)

Getestet mit:
Play:5
ZP120 und ZP90

Hum, ich habe es jetzt mit Deiner Browse Funktion probiert und es klappt! :smiley:

Das merkwürdige ist das mir der Totalcommander Dateivergleich bei der Browse Funktion und den sendpacket Funktionen keinen Unterschied zwischen unseren Funktionen anzeigt.:confused:
Naja, ich habe jetzt Deine Browse Funktion in die Klasse kopiert.

Aber „Duration“ ist bei mir immer „leer“ (wie ja in Deiner Ausgabe auch). Bekommst Du da in irgendeiner Konstellation eine Länge zurück???

Edit: zu GetAudioInputAttributes (ich habe die Funktion bei mir nochmal umbenannt, so dass sie dem UPNP Namen entspricht):
Die Ausgabe „Line-In“ und kein zugeordnetes Bild erhälst Du immer wenn für diesen ZP kein Eingang definiert/konfiguriert wurde.

Jup wenn Du Dir die Metadaten eines Songs geben läßt bekommst Du diese Infos mit. Ich nutzte das um die Songs einer Playlist zu verarbeiten.

EDIT:
Zeitg ein TotalCommander die ASCII oder die Binär Vergleiche an?
Beim Senden reicht ein Zeilenumbruch und es geht nicht mehr.