PHP Sonos (Klasse zum Ansteuern einzelner Player)

Hi!

Geändert hat sich da nicht direkt was…da geht es um die „chunks“ (Antwort kommt in „Stücken“). Da kann kugelberg dir mehr Infos zu geben, da bin ich nicht so gut drin :slight_smile:

Grüße,
Chris

Hallo,

bevor ich bei mir im Sonos PHP Modul (von einer Zugriffsklasse die auf PHPSonos basiert hat) auf den PHP Soap Client (https://raw.githubusercontent.com/tkugelberg/SymconSonos/master/Sonos/sonosAccess.php) umgestellt habe, hatte ich da schon etwas für chunks in die sendPacket Funktion eingebaut:


/**
 * XMLsendPacket
 *
 * - <b>NOTE:</b> This function does send of a soap query and DOES NOT filter a xml answer
 * - <b>Returns:</b> Answer as XML
 *
 * @return Array
 */
    private function XMLsendPacket( $content )
    {
        $fp = fsockopen($this->address, 1400 /* Port */, $errno, $errstr, 10);
        if (!$fp)
            throw new Exception("Error opening socket: ".$errstr." (".$errno.")");
		    
        fputs ($fp, $content);
        $ret = "";
        $buffer = "";
        while (!feof($fp)) {
            $ret.= fgets($fp,128);
        }

        fclose($fp);

        if(strpos($ret, "200 OK") === false)
            throw new Exception("Error sending command: ".$ret);

        $array = preg_split("/
/", $ret);

        $result = "";
        if(strpos($ret, "TRANSFER-ENCODING: chunked") === false){
            $result = $array[count($array) - 1];
        }else{
            $chunksStarted = false;
            $content       = false;
            foreach($array as $key => $value){
                if($value == ""){
                    $chunksStarted = true;
                    continue;
                }
                if($chunksStarted === false)
                    continue;
                if($content === false){
                    if( $value === 0)
                        break;
                    $content = true;
                    continue;
                }
                $result = $result.$value;
                $content = false;
            }
        } 
		
        return $result;
    }

/**
 * sendPacket - communicate with the device
 *
 * - <b>NOTE:</b> This function does send of a soap query and may filter xml answers
 * - <b>Returns:</b> Answer
 *
 * @return Array
 */

    private function sendPacket( $content )
    {
        $fp = fsockopen($this->address, 1400 /* Port */, $errno, $errstr, 10);
        if (!$fp)
            throw new Exception("Error opening socket: ".$errstr." (".$errno.")");

        fputs ($fp, $content);
        $ret = "";
        while (!feof($fp)) {
            $ret.= fgetss($fp,128);
        }
        fclose($fp);

        if(strpos($ret, "200 OK") === false)
            throw new Exception("Error sending command: ".$ret);
		
        $array = preg_split("/
/", $ret);

        $result = "";
        if(strpos($ret, "TRANSFER-ENCODING: chunked") === false){
            $result = $array[count($array) - 1];
        }else{
            $chunksStarted = false;
            $content       = false;
            foreach($array as $key => $value){
                if($value == ""){
                    $chunksStarted = true;
                    continue;
                }
                if($chunksStarted === false)
                    continue;
                if($content === false){
                    if( $value === 0)
                        break;
                    $content = true;
                    continue;
                }
                $result = $result.$value;
                $content = false;
            }
        } 
		
        return $result;
    }

Die Antwort kommt immer dann in Chunks zurück, wenn sie eine gewisse Größe überschreitet.

Ich würde euch aber ans Herz legen, mal einen Blick auf die PHP Soap Client Variante zu werfen. Das ist sehr viel einfacher. Zumindest meiner Meinung nach.

Gruß,
Thorsten

Hallo,

ich habe die Herausforderungen in PHPSonos.inc.php gefunden, die XML-Antwort steht an einer anderen Stelle im Antwortarray. Anstatt $array[count($array) - 1] habe ich erst einmal fix return $array[8] verwendet. Ich weiss, das könnte in Zukunft andere Herausforderungen beschwören…


	private function sendPacketV6($content)
	{
		$fp = fsockopen($this->address, 1400 /* Port */, $errno, $errstr, 10);
		if (!$fp)
		    throw new Exception("Error opening socket: ".$errstr." (".$errno.")");
		fputs ($fp, $content);
		$ret = "";
		while (!feof($fp)) {
			$ret.= fgetss($fp,128); // filter xml answer
		}
		fclose($fp);
		if(strpos($ret, "200 OK") === false)
       	            throw new Exception("Error sending command: ".$ret);
		$array = preg_split("/
/", $ret);
		//return $array[count($array) - 1];
		return $array[8];
	}

Viele Grüße

Admin: Diesen ehemals doppelten Eintrag bitte löschen. Vielen Dank.

Hallo,

das halte ich nicht für richtig.
Das entspricht nicht dem Standart für HTTP/SOAP Antworten. Hast Du mal in den Header Daten geschaut, ob es nicht doch evtl. eine Antwort in chunks ist?

Diese Information müsste weiter oben im $array[2] oder 3 oder so stehen. Das HTTP Header Feld „TRANSFER-ENCODING“ wird mit dem Wert „chunked“ zurückgeliefert.

Wenn dem so ist, ist das XML auf mehere Felder im array verteilt…

Mit „$result = $array[count($array) - 1];“ gibt man ja eigentlich die Letzte Zeile der Resonse zurück.
Und bei chunks ist das immer eine Leerzeile. (Chunked transfer encoding - Wikipedia, the free encyclopedia)

Weiterhin ist das splitten bei "
" unsauber, es müsste "
" sein. Aber das scheint ja schon leit längerem zu funktionieren. So steht es zumindest in der HTTP spezifikation…

Gruß,
Thorsten

Hallo Leute,

gelegentlich lese ich Euren Thread und bin aktuell über das chunked Problem gestolpert. Ich hatte mich eine Zeit lang eingehend mit DLNA beschäftigt und einen allgemeinen Control Point geschaffen (gelegentlich entwickle ich auch noch weiter).
Ausgehend vom allgemeinen DLNA sind die Reaktionen etwas unterschiedlich beim Content Browsing je nachdem, welche HTTP-Version im Header gesetzt wird. HTTP 1.1 produziert z.B. eine chunked Response bei manchen Geräten, die man mit HTTP 1.0 abstellt.

Rein spekulativ: vielleicht ist es ja bei Euren SONOS je nach Alter der Firmware genauso ?

UPNP/DLNA for IPS: new version - Seite 10

Gruß

André

Hallo Leute

ich beschäftige mich seit kurzem mit dem Thema aber ich komme nicht drauf wie das lösen soll.
ich hoffe einer von euch kann mir helfen. die befehle mach ich mit php und über url abruf bzw. sende ich mit dem Gira Homeserver die befehle (muster: http://yourserver/sonos/index.php?zone=kitchen&action=TogglePlayPause)
Leider bekomme ich es nicht für den wechsel von Radio zur Playlist hin.

LG

Hi Schlaxi!

Willkommen im IPS Forum :slight_smile:

Damit man dir helfen kann, solltest du etwas mehr Infos veröffentlichen. Auf Ratespiele haben die wenigsten Lust :wink:

Deshalb bitte möglichst genau beschreiben was du machen willst und falls vorhanden schon ein Skript von dir, damit man dir sagen kann was daran falsch ist oder wie man es anders lösen könnte usw…

Grüße,
Chris

Hallo Chris,
ich möchte mir einen Befehl schreiben das ich von Radio Sender auf die Playlist komme um diese abzuspielen.
Leider komme ich nicht drauf und mein script funzt nicht wirklich.
ich hoffe du kannst mir helfen.

LG Schlaxi

protected function _Playlist1()
	{
		  {      
    case 'SpielPlaylist1':
      $PlaylistName = "Playlist1"; 
      foreach ($sonos->GetSONOSPlaylists() as $sonoslist){ 
         if ($sonoslist['title']==$PlaylistName){ 
            $PlaylistFILE= $sonoslist['file'];
            break; 
         } 
      $sonos->ClearQueue();
      $sonos->AddtoQueue("$PlaylistFILE"); 
      $sonos->SetQueue("x-rincon-queue:RINCON_"."00-00-00-00-00-00"."01400#0"); 
		$this->_PHPSonos->Play();
	}

Moin!

Also du willst ein IPS-Skript ausführen und das soll dafür sorgen, dass die Playlist XY auf der Sonos abgespielt wird?!

Was gibt dein Skript denn aus? Kommt ein Fehler? In dem Teil würde ich mal behaupten, dass das Skript nie in den Case „SpielPlaylist1“ kommt, außer du hast den entsprechenden Teil ausgelassen…

Ich vermute mal, dass du den Code irgendwo rauskopiert hast?

Wenn du das Skript in IPS startest, was bekommst du als Ausgabe und was passiert?

<?
// Hier den include vom PHPSonos einbauen

$PlaylistName = "Playlist1";  
foreach ($sonos->GetSONOSPlaylists() as $sonoslist)
{  
    if ($sonoslist['title']==$PlaylistName)
    {  
        $PlaylistFILE= $sonoslist['file']; 
        echo "PlaylistFILE:".$PlaylistFILE;  // Zur Kontrolle, ob das Skript überhaupt hier rein kommt
        break;  
    }  
}
$sonos->ClearQueue(); 
$sonos->AddtoQueue("$PlaylistFILE");  
$sonos->SetQueue("x-rincon-queue:RINCON_"."00-00-00-00-00-00"."01400#0");  
$this->_PHPSonos->Play(); 
?>

…die RINCON des Sonos Player muss natürlich eingetragen sein, ohne RINCON funktioniert nichts. Ich denke das hast du nur „unkenntlich“ gemacht!?

Grüße,
Chris

Er hat aber einen Gira Homeserver… nicht IPS :wink:

Michael

Weil ich mir nicht sicher war was er hat/will, hab ich gesagt er soll AUSFÜHRLICH beschreiben wie wo was er will…hat er nicht, also bin ich von IPS ausgegangen, weil wir hier ja im IPS Forum sind und nicht im GIRA Forum :rolleyes:

-Chris-

Hat er doch im ersten Post geschrieben… überlesen ?
Noch lange kein Grund gleich zu schreien…
Michael

Hallo
Sorry
Ja ich hab einen Gira Homeserver und wenn du als rincon die mac adresse meinst die hab ich unkenntlich gemacht.
ja ich habs wo raus kopiert und habe schon mehrere möglichkeiten probiert, leider erfolglos.

wenn du ihr mir trotzdem helfen möchtet wäre ich euch sehr Dankbar.

Brauche den Befehl für einen Radioweckerfunktion über knx/Homeserver/Tastsensor auf Sonos.

lg Schlaxi

Rincon UNGLEICH Mac-Adresse … das nur mal am Rande :wink:
Die Rincon kannst du auf verschiedene Wege ermitteln. Am einfachsten ist es wohl, wenn du bei einem Computer im Heimnetzwerk auf „Netzwerk“ klickst und dir die Eigenschaften des Sonos Player anzeigen lässt.

Aber mal davon abgesehen, ist das hier im Thread alles eher unpassend. Du solltest eher irgendwo anders hier im Forum, oder im Gira Forum, einen Thread eröffnen. Ich würde mal behaupten, dass es bei Gira auch einige Leute gibt die Sonos im Einsatz haben usw…

PHP-Code zum Steuern von Sonos kannst du dir aber an vielen Stellen im Forum oder auf GitHub raussuchen…hier ein paar Beispiele und dann bitte woanders weiter :slight_smile:
> SonosBY (Sonos // Gruppen erstellen, Gruppen auflösen, Text to Speech, …)
> SymconSonos/module.php at master · tkugelberg/SymconSonos · GitHub

Oder direkt für Gira:
SONOS mit GIRA Homeserver steuern – neue Version - Thomas Trautner

Oder Allgemein:
DjMomo/sonos - PHP - GitHub
Sonos - A PHP library for interacting with Sonos speakers

Und dem User „JHH“ kann ich mich nur zu 100% anschließen (Antwort Nr. 3) :slight_smile:
Sonos PHP | Sonos Community
…wir sind schon nett, nur eine fertige Lösung für jemanden bauen der nicht mal IPS im Einsatz hat…öhm…nö…wieso auch :wink: :smiley:

Soooo…denke du hast genug Input. Jetzt musst du es nur noch einbauen :slight_smile:

Grüße,
Chris

Hallo Chris

Ja das ist mir schon klar das dir/euch nicht freut mir eine fertige lösung zu basteln…
hier im Forum wird halt am meisten geschrieben
hab meinen fehler schon gefunden, hab die macadresse falsch geschrieben.

jetzt fehlt mir nur noch der befehl für eine bestimmte playlist.

	protected function _actionMusik()
	         {
		$this->_PHPSonos->SetQueue("x-rincon-queue:RINCON_MacAdresse01400#0");
		$this->_PHPSonos->Play();
	        }

Tjaaaa…die Community hier ist schon toll und sehr aktiv :slight_smile: Da musst du wohl mal auf IPS umbauen :wink:

Aber schau mal in meinem SonosBY Skript, da siehst du gut die einzelnen notwendigen Schritte, zum Playlist-ID auslesen und Playlist laden usw…

Grüße,
Chris

Hallo zusammen,

brauch mal wieder eure Hilfe.

hab hier ein Phänomen …

der Code

<?

include('TTS_Function_AnsageAufSonosMitSound_12711.ips.php'); // function ansage auf sonos mit Sound

$Player_IP = $sonosKeller;
$ansagetext = 'Das Gartenwasser ist noch offen';
$ton = 'gemeckerKurz';

if (Sys_Ping($sonosKeller, 1000)==1)
{
    TTS_Play_Sonos($Player_IP,$ansagetext,$ton);
}

?>

funktioniert mit $ton

der Code

<?

include('TTS_Function_AnsageAufSonosMitSound_12711.ips.php'); // function ansage auf sonos mit Sound

$Player_IP = $sonosKeller;
$ansagetext = 'Rauchalarm im Schlafzimmer Wolf';
$ton = 'alarm01';

if (Sys_Ping($sonosKeller, 1000)==1)
{
    TTS_Play_Sonos($Player_IP,$ansagetext,$ton);
}

?>

verschluckt irgend wie $ton, d.h. es wird nur $ansagetext ausgegeben.

in der TTS_Function_AnsageAufSonosMitSound_12711.ips.php

ist folgendes hinterlegt:

$wav = array
(
   "alarm01"        => "x-file-cifs://server01/media/Sounds/alarm_01.mp3",
   "gemecker"        => "x-file-cifs://server01/media/Sounds/gemecker.mp3",
   "gemeckerKurz"    => "x-file-cifs://server01/media/Sounds/goat.mp3",
   "sheep"            => "x-file-cifs://server01/media/Sounds/sheep.mp3",
   "donkey"            => "x-file-cifs://server01/media/Sounds/donkey.mp3",
   "kuckuck"        => "x-file-cifs://server01/media/Sounds/Kuckuck/cuckoo".$hour.".wav",
   "rooster"        => "x-file-cifs://server01/media/Sounds/Hahn/rooster".$hour.".wav"
);

Die .wav kann abgepielt werden, sind also nicht leer.

Hat jemand eine Idee woran das liegen könnte?

Hallo zusammen,

hatte für die Suche zur Lösung ein neues Thema eröffnet.

Das Problem lag wohl an der .mp3.

Die Lösung war:

Die .mp3 in eine .wav und zurück in eine .mp3 zu konvertieren.

Siehe https://www.symcon.de/forum/threads/33270-mp3-mp3
Sorry für die späte Meldung…

Guten Abend zusammen,

wollte gerade die Lautstärke KNX -> Sonos installieren und scheinbar klappt das Script unter 4.1 so nicht mehr.
Da ich aber kein php Profi bin kann ich den Fehler in der Zeile case … nicht beheben


<?
include("PHPSonos.inc.php"); 
//Hier die Variable einfügen mit der aktuellen Lautstärke!!!! 
$Volume = GetValueInteger(46867 /*SONOS LAUTSTÄRKE AKTUELL*/); 
//Player IP-Adresse eintragen!!!! 
$sonos = new PHPSonos("192.168.0.162"); //Sonos ZP IPAdresse 
switch ($IPS_SENDER) 
{ 
case "Variable": 
    if($IPS_EVENT == "12345") // <--Ereignis erstellen mit Variable deines PLUS-Tasters 
    und Ausführen bei Variable Aktualisierung und die ID hier eintragen 
    { 
        $Volume_Plus = ($Volume+5); 
        $sonos->SetVolume($Volume_Plus); 
    } 
    if($IPS_EVENT == "54321") // <--Ereignis erstellen mit Variable deines MINUS-Tasters 
    und Ausführen bei Variable Aktualisierung und die ID hier eintragen 
    { 
        $Volume_Minus = ($Volume-5); 
        $sonos->SetVolume($Volume_Minus); 
    } 
    break; 
}
?>

Danke Thomas