PHP Sonos (Klasse zum Ansteuern einzelner Player)

Hallo,

im Artikel 221 dieses Threads (http://www.ip-symcon.de/forum/threads/7676-PHP-Sonos-(Klasse-zum-Ansteuern-einzelner-Player)?p=181303#post181303) habe ich das mal mittels GUPNP gemacht.

Der Code kann die Player discovern, und schreibt das Ergebnis in eine Textdatei (Zonennamen und IP-Adressen). Das könnte man einfach zyklisch machen, und die Textdatei anschließend neuladen lassen, je nach Anwendungsfall…
Aber Vorsicht: Der Zonenname ist nicht eindeutig, wenn es gepaarte Player (Stereopaar oder TV-Soundsystem) gibt, dann erhalten diese alle den gleichen Zonennamen, unterscheiden kann man die nur noch anhand ihrer UDN…

Grüße
Reiner

Hallo.

Danke erstmal.

Habe mir die „GUPNP“ angescheut. Ist nicht schlecht, aber wie bekomme ich diese lib in IP Symcon importiert?
Die lib ist ja in C geschrieben.

BYE
Tomi

Hallo, versuche nun seit ein paar Stunden einen passenden Beitrag zu finden. Aber irgendwie scheint das Forum zu groß geworden zu sein… und die Beiträge zu lang… :wink: Ist auch schon mein 4. Anlauf, verbrate so noch meinen ganzen Urlaub… :smiley:

Kann mir evtl jemand weiter helfen…

Ich möchte gerne meine Radiosender für Sonos über IPS wählen. Im Wiki habe ich folgendes Beispiel gefunden:

$sonos->SetRadio("x-rincon-mp3radio://players.creacast.com/creacast/klassik/playlist.pls");

Aber keine Erklärung zum Aufbau…

Wie muss ich das anpassen damit ich meine Sender dort einfügen kann?

Die Beschreibung im Wiki dazu habe ich zwar gelesen aber ist sie doch so allgemein gefasst das ich damit nichts anfangen kann. Vielleicht fehlen mir in dem Bereich entscheidende Kenntnisse…

Hab mal mit Wire Stark versucht zu belauschen was der Sonos macht, aber anscheinend sendet der Controller am PC nur den Befehl das der Sonos sich den „Link“ zum Sender holen soll… Arbeite aber auch äußerst selten mit Wire Stark und glaube das ich das nicht 100%ig interpretieren kann… Wenn ich den Trafik nun noch umleiten muss um die Rückantwort zu „hören“ bin ich glaube ich raus…

Wenn eine Erklärung zu langwierig ist wäre ich auch schon glücklich über einen passenden PHP Eintrag für mein Script :slight_smile:

Sender: „1.FM - Top 40“

Aber ich würde das auch gerne verstehen… :wink:

Du brauchst nur bis zum Beitrag #316 zurückgehen, da ist ein Beispiel!!

Hallo zusammen …

ich bin mir sicher für meine Frage gibt eine simple Lösung. Ich denke wahrscheinlich viel zu kompliziert!!!

Ich habe 5 Skripte in einer Kategorie angelegt. Der Inhalt sind 3 verschiedene Lautstärken und Mute bzw. Mute off einer Sonos Play1.

Nun möchte ich diese Scripte von einem anderen Rechner - ohne das Webinterface vom Server aufzurufen - starten. Kann mir jemand helfen, wie so ein Befehl aussehen sollte?

Ich bin da leider noch ein blutiger Anfänger und kämpfe mich von Problem zu Problem. Bis dato klappt durch viel Lesen auch schon mal eine ganze Menge, aber manche Dinge übersteigen da grad meinen Horizont!!

Besten Dank im vorraus!!!

Heiquito

Nachtrag: Das einzige was ich zu diesem Thema gefunden habe ist das hier

Wenn ich mir das Beispiel mal für meinen Fall übersetze, sollte das eigentlich so aussehen:

http://192.168.1.1:82/user/34715.ips.php

192.168.1.1 = Server (Beispiel IP Adresse)
user = ist der immer gleich?
34715.ips.php = Wert meines Scripts (Mute)

Script funktioniert über die Weboberläche. Als Befehl über den Browser kommt die Fehlermeldung „not Found“

Bin einen Schritt weiter …

Die Datei musste zusätzlich noch ins Unterverzeichnis von Webfront kopiert werden. Jetzt wird das Skript ausgeführt, öffnet aber dummerweise bzw. logischerweise die Seite im Browser, was ich gerne verhindern würde.

Irgendeine Idee?

Hallo Heiquito,

ich würde dir ja gerne helfen, jedoch habe ich noch nicht einmal im Ansatz
verstanden was Du überhaupt machen willst.

Anhand der zahlreichen Antworten die ich hier lese bin ich da wohl auch nicht alleine. :wink:

Könntest Du nochmal genauer beschreiben was Du überhaut machen willst?

Hallo zusammen!

Aus irgendwelchen Gründen wird die TransportInfo auf den Membern einer Gruppe beim Pausieren eines Streams nicht aktualisiert. TransportInfo liefert immer eine 1 zurück. Somit denkt das Skript, auf dem Member spielt noch was, obwohl der Coordinator die Wiedergabe längst gestoppt hat. Das ist ziemlich nervig. Passiert auch, wenn ich die Wiedergabe über die IPhone App pausiere. Hat jemand ne Idee, was man da machen kann.

Außerdem habe ich ein kleines Skript für meine Anbindung an einen Gira Homeserver geschrieben. Das Skript erlaubt es mit nur einer Taste auf den Bus-Schaltern entweder das Radio anzuschalten oder sich an einen bestehenden Stream im Haus anzuhängen. Bei erneutem Druck entfernt er den Client aus dem Stream oder stoppt die Wiedergabe des Radios.

Das ist ziemlich angenehm im Alltag, weil ich eh meistens einfach WDR2 einschalte. So muss ich das Handy nur noch zur Hand nehmen, wenn ich mal was anderes hören will. Und dann auch nur einmal am Anfang. In weiteren Räumen drücke ich dann wieder nur die Taste.

Zusätzlich habe ich eine Rückgabe an die LEDs der Schalter integriert. Wen die Integration im HomeServer interessiert, kann mich gerne kontaktieren.

Ich habe die Funktion „IntelliPlay“ genannt. Es gibt halt derzeit nur noch ein Problem mit diesem nicht mitbekommen, dass die Weidergabe eigentlich angehalten ist.

Ganz sauber ist das nicht programmiert. Aber ich hatte keine Lust mehr das aufzuräumen. Sorry dafür.


function IntelliPlay()
{
  global $sonos, $zones, $zone, $rincons, $sonosClients, $thisZone, $thisZoneName;
   
  //if something is running local, stop local playback (keep playing in the rest of the house)
  if (intval($sonos->GetTransportInfo()) == 1) 
    {
       
		$PositionInfo = $sonos->GetPositionInfo();
		//echo "URI" . $PositionInfo['URI'] . "<BR>";
		
		//Am I part of a Group? If yes, remove me
		//echo "PositionInfo: " . $PositionInfo['TrackURI'];
		//echo "STRSTR: " . substr(strstr($PositionInfo['TrackURI'],"x-rincon:"), 9);
		
		if (strstr($PositionInfo['TrackURI'],"x-rincon:")) {
		   //echo "Remove me";
		   $coordinatorRincon = substr(strstr($PositionInfo['TrackURI'],"x-rincon:"),9);
		   $coordinatorName = array_search($coordinatorRincon, $rincons);
		   //echo "CoordinatorName" . $coordinatorName;
		   
		   $coordinator = new PHPSonos($zones[$coordinatorName]);
		   
		   $coordinator->RemoveMember($rincons[$zone]);
		   $sonos->Stop();
		   $sonos->SetAVTransportURI("");
		   $wasMember = 1;
		} else {
		   //if not, simple stop
		   $stopIt = 1;
		}		
		
		//or am I a coordinator? Then 
		if ($wasMember !== 1) {
		   //echo "Check if I am coordinator";
		   
		   foreach($zones as $thisZoneName => $thisZone) {
		   $thisZone = new PHPSonos($thisZone);
		   
		   //eigenen Player beim Check ausschließen
		   if($thisZoneName !== $zone) {
		      $myPositionInfo = $thisZone->GetPositionInfo();
			  //echo "MyPositionInfo: " . $myPositionInfo['TrackURI'];
			  $checkRincon = "x-rincon:" . $rincons[$zone];
			  //echo "Rincon: " . $checkRincon;
			  
			  if ($myPositionInfo['TrackURI'] == $checkRincon) {
			    //echo "Tatsächlich! Ich bin ein Coordinator!!!";
				//echo "Remove: " . $rincons[$thisZoneName];
				//echo "Ich remove nun " . $thisZoneName . " vom Coordinator " . $zone;
				$thisZone->Stop();
				$mainPositionInfo = $sonos->GetPositionInfo();
				$thisZone->SetAVTransportURI($mainPositionInfo["TrackURI"]);
				$sonos->RemoveMember($rincons[$thisZoneName]);
				$thisZone->Play();
				$reportAOne = 1;
				$memberZone = $thisZoneName;
			  }
		   }
		   
		   }
		}

		$sonos->Stop();
		$sonos->SetAVTransportURI("");
		//report PlayStatus to LEDs
	    
		$stopIt = 1;
		
		if ($reportAOne) {
		ReportPlayStatus(1, $memberZone);
		} else {
		ReportPlayStatus(0, $zone);
		}
  
  //if nothing is running local, check the whole house
    } else {
     
     foreach($zones as $thisZoneName => $thisZone) {
	   
	   $thisZone = new PHPSonos($thisZone);
       //eigenen Client ausschließen
	   
	   if($thisZoneName !== $zone) {
	     
	     //Wenn hier was läuft, häng mich dran und gut
	     
		 if (intval($thisZone->GetTransportInfo()) == 1 && $somethingsPlaying !== 1) {
			
			//Vermutlich noch eine Unterscheidung nach Radio oder nicht Radio nötig?
		    echo "Es läuft was in: " . $thisZoneName;
			echo "Angehangen an: " . $thisZoneName . "und zwar:" . $rincons[$zone];
			$thisZone->AddMember($rincons[$zone]);
            $sonos->SetAVTransportURI("x-rincon:" . $rincons[$thisZoneName]);
			
			//report PlayStatus to local LED
			
			$somethingsPlaying = 1;
			ReportPlayStatus(1,$zone);
		 }
		 
       	}		
	   
	   }
	   
    }
	   
     
	 //echo "Spielt was: (" . $somethingsPlaying . ")";
	 
	 //Wenn nirgendwo was lief, dann spiel einfach WDR2
     if ($somethingsPlaying !== 1 and $stopIt !== 1) {
  	   $sonos->SetRadio("x-rincon-mp3radio://www.wdr.de/wdrlive/media/wdr2.m3u","WDR2");
       $sonos->Play();
	   
	   //Wenn es sich um das Schlafzimmer oder das Elternbad handelt, dann spiel den jeweils anderen mit!
	   //if ($zone == "Schlafzimmer) {
	   //}
	   
	   //if ($zone == "Bad") {
	   //}
	   
	   ReportPlayStatus(1,$zone);
	  }
	} 

Sorry. Code hier nochmal in hübsch!

function IntelliPlay()
{
  global $sonos, $zones, $zone, $rincons, $sonosClients, $thisZone, $thisZoneName;
   
  //if something is running local, stop local playback (keep playing in the rest of the house)
  if (intval($sonos->GetTransportInfo()) == 1) 
    {
       
		$PositionInfo = $sonos->GetPositionInfo();
		//echo "URI" . $PositionInfo['URI'] . "<BR>";
		
		//Am I part of a Group? If yes, remove me
		//echo "PositionInfo: " . $PositionInfo['TrackURI'];
		//echo "STRSTR: " . substr(strstr($PositionInfo['TrackURI'],"x-rincon:"), 9);
		
		if (strstr($PositionInfo['TrackURI'],"x-rincon:")) {
		   //echo "Remove me";
		   $coordinatorRincon = substr(strstr($PositionInfo['TrackURI'],"x-rincon:"),9);
		   $coordinatorName = array_search($coordinatorRincon, $rincons);
		   //echo "CoordinatorName" . $coordinatorName;
		   
		   $coordinator = new PHPSonos($zones[$coordinatorName]);
		   
		   $coordinator->RemoveMember($rincons[$zone]);
		   $sonos->Stop();
		   $sonos->SetAVTransportURI("");
		   $wasMember = 1;
		} else {
		   //if not, simple stop
		   $stopIt = 1;
		}		
		
		//or am I a coordinator? Then 
		if ($wasMember !== 1) {
		   //echo "Check if I am coordinator";
		   
		   foreach($zones as $thisZoneName => $thisZone) {
		   $thisZone = new PHPSonos($thisZone);
		   
		   //eigenen Player beim Check ausschließen
		   if($thisZoneName !== $zone) {
		      $myPositionInfo = $thisZone->GetPositionInfo();
			  //echo "MyPositionInfo: " . $myPositionInfo['TrackURI'];
			  $checkRincon = "x-rincon:" . $rincons[$zone];
			  //echo "Rincon: " . $checkRincon;
			  
			  if ($myPositionInfo['TrackURI'] == $checkRincon) {
			    //echo "Tatsächlich! Ich bin ein Coordinator!!!";
				//echo "Remove: " . $rincons[$thisZoneName];
				//echo "Ich remove nun " . $thisZoneName . " vom Coordinator " . $zone;
				$thisZone->Stop();
				$mainPositionInfo = $sonos->GetPositionInfo();
				$thisZone->SetAVTransportURI($mainPositionInfo["TrackURI"]);
				$sonos->RemoveMember($rincons[$thisZoneName]);
				$thisZone->Play();
				$reportAOne = 1;
				$memberZone = $thisZoneName;
			  }
		   }
		   
		   }
		}

		$sonos->Stop();
		$sonos->SetAVTransportURI("");
		//report PlayStatus to LEDs
	    
		$stopIt = 1;
		
		if ($reportAOne) {
		ReportPlayStatus(1, $memberZone);
		} else {
		ReportPlayStatus(0, $zone);
		}
  
  //if nothing is running local, check the whole house
    } else {
     
     foreach($zones as $thisZoneName => $thisZone) {
	   
	   $thisZone = new PHPSonos($thisZone);
       //eigenen Client ausschließen
	   
	   if($thisZoneName !== $zone) {
	     
	     //Wenn hier was läuft, häng mich dran und gut
	     
		 if (intval($thisZone->GetTransportInfo()) == 1 && $somethingsPlaying !== 1) {
			
			//Vermutlich noch eine Unterscheidung nach Radio oder nicht Radio nötig?
		    echo "Es läuft was in: " . $thisZoneName;
			echo "Angehangen an: " . $thisZoneName . "und zwar:" . $rincons[$zone];
			$thisZone->AddMember($rincons[$zone]);
            $sonos->SetAVTransportURI("x-rincon:" . $rincons[$thisZoneName]);
			
			//report PlayStatus to local LED
			
			$somethingsPlaying = 1;
			ReportPlayStatus(1,$zone);
		 }
		 
       	}		
	   
	   }
	   
    }
	   
     
	 //echo "Spielt was: (" . $somethingsPlaying . ")";
	 
	 //Wenn nirgendwo was lief, dann spiel einfach WDR2
     if ($somethingsPlaying !== 1 and $stopIt !== 1) {
  	   $sonos->SetRadio("x-rincon-mp3radio://www.wdr.de/wdrlive/media/wdr2.m3u","WDR2");
       $sonos->Play();
	   
	   //Wenn es sich um das Schlafzimmer oder das Elternbad handelt, dann spiel den jeweils anderen mit!
	   //if ($zone == "Schlafzimmer) {
	   //}
	   
	   //if ($zone == "Bad") {
	   //}
	   
	   ReportPlayStatus(1,$zone);
	  }
	} 

Hallo havenonick,

bzgl. des Abspielzustands gibt es leider keine andere Lösung. Für Sonos spielt ein Gruppenmember immer etwas ab, u.U. ist das halt ziemlich still :slight_smile:

Das einzige, was du machen kannst, ist halt den Abspielzustand vom Gruppenmaster abzufragen/zu verwenden (so wie es der Sonos-Controller ja auch tut), anstatt direkt den Player zu fragen.

Grüße
Reiner

Alles klar. Dann bau ich mir das als Workaround. Sollten nur ein paar Zeilen sein. Gut zu wissen. Dann such ich wenigstens nicht verzweifelt weiter.

Hallo zusammen,

ich nutze diese Ansteuerung hier für viele Sonos Geräte in meinem Haus schon recht lange.
Jetzt hatte ich in den letzten Tagen ein Update auf IPS 3.1 gemacht.
Nach kurzer Zeit habe ich festgestellt, das hohe Latenzen (5-30 sec.) beim ein- und ausschalten der Sonos Geräte auftreten (mute die Geräte lediglich).
Ich nutze hierfür einen Taster im Toggle-Betrieb (vorher frage ich erst, ob das Gerät ein- oder ausgeschaltet ist und mache dann die jeweilige Aktion).

Irgendwie habe ich mir dann keinen Rat mehr gefunden und bin zurück auf IPS 3.0.
Und siehe da, alle Probleme sind wieder weg.

Habt ihr aktuell ähnliche Probleme beobachtet?
Was könnte das sein? Bzw. was hat es mit IPS 3.1 zu tun?

Hat denn niemand von Euch dieses Problem?
Habe die letzten Tag nochmal ein Update auf 3.1 gemacht und das Problem war wieder da.
Bin jetzt wieder zurück auf 3.0.

Ich weiß nicht, wo ich weiter nach dem Problem suchen soll, dann Hardware ist absolut identisch geblieben. Es ist lediglich das Update der IP-Symcon Software die dazu führt.

Die Steuerung von Sonos über Android, Windows usw. über die Sonos Programme/Apps funktioniert auch problemlos.

Hallöchen

Ehrlich gesagt ja, Sonos ist bei mir im IPS drin und läuft mit. ABER ich steuere und verwende es so gut wie nie mit Sonos. Ich werde es mal am Weekend (bin sonst nicht vor Ort) prüfen falls sonst keiner das so einsetzt. Einfach mal Mutebefehl bei laufendem Sonos wählen und melde mich dann. Was du mit ein / ausschalten Sonos meinst weiss ich nicht ausser eben mute ein und aus.

Gruss

Servus,
also ich hab auch alles unter 3.1 und nein, ein solches Delay ist mir bis dato noch nicht aufgefallen.

Gruss

Hier der Code den ich ausführe und mit dem es bei Version 3.1 hohe Latenzen gibt.
Ich nutze Homematic und schalte die Musik mit Aktoren (Tastern) ein und aus (Mute).
Meine anderen Aktoren, Sensoren laufen mit den Skripten und Version 3.1 ohne Probleme.
Verzögerungen kommen immer nur, wenn ich was mit Sonos mache.

<?

include("PHPSonos.inc.php");

$sonos = new PHPSonos("192.168.178.130"); //Sonos ZP IPAdresse

$status = $sonos->GetTransportInfo(); // gibt den aktuellen Status
// des Sonos-Players als Integer zurück, 1: PLAYING, 2: PAUSED, 3: STOPPED
SetValueInteger(20506 /*[Kategorien\Musik\Sonos Küche\Sonos Küche Status]*/ , $status);

if ( $status == 3 or $status == 2 )
{
 
  $sonos->Play();
  $sonos->SetVolume(10); //0-100 in %
}
else
{
  $sonos->Pause();
}

$status = $sonos->GetTransportInfo(); // gibt den aktuellen Status
SetValueInteger(20506 /*[Kategorien\Musik\Sonos Küche\Sonos Küche Status]*/ , $status);


?>

Hallo.

Habe schon alles versucht aber irgendwie bekomme ich es nicht hin.

Mache ein Subscribe am Sonos Client
$sonos = new PHPSonos($ip); //Sonos ZP IPAdresse
$callback = „http://192.168.2.220:80/eventIPSSub.php“;
$sonos->SubscribeMRAVTransport($callback);

In Wireshark sehe ich die Antwort vom Sonos Client:
NOTIFY /eventIPSSub.php HTTP/1.1
HOST: 192.168.2.220:80
CONNECTION: close
CONTENT-TYPE: text/xml
CONTENT-LENGTH: 5662
NT: upnp:event

Nur leider sehe ich nichts in meinem PHP Script „eventIPSSub.php“.
Muss ich am Server noch etwas Konfigurieren?
Habe irgendwas gelesen das IP Symcon die „NOTIFY“ Msg nicht weiterleitet, stimmt das?
Was mus ich machen?

Danke.

BYE
Thomas

Hi,

habe dieselbe Situation …

BG Johannes

Schön, dass es noch andere gibt die auch mein Problem haben.

Ich habe am Wochenende wieder von 3.0 auf 3.1 mit dem aktuellen Build #3420.
Wollte es einfach mal wieder probieren, ob die Delays weg sind.
Aber es ist, als würde man mit dem Update einen Schalter umlegen, denn auf einmal ist das Problem da.

Die Bedienung über die Sonos App auf Androiid funktioniert parallel ohne Verzögerungen.

Man könnte meinen es hat irgendetwas mit der TCP/IP Kommunikation aus IP-Symcon ins Netzwerk zu tun.

Moin, moin,

ich würde gerne den aktuellen Mute-Status eines Sonos-Players abfragen. Im Wiki wird auf eine Funktion GetMute verwiesen, wenn ich diese versuche zu nutzen bekomme ich aber eine Fehlermeldung („Call to undefined method“).
Gibt es diese Funktion nicht mehr?
Wenn ja, wie bekomme ich den aktuellen Mute-Status heraus?

Merci+Gruß, Hocky