PHP Sonos (Klasse zum Ansteuern einzelner Player)

Was mir noch einfällt.

Beim Apache Webserver wird der Request Notify durchgeschleust.
Beim IIS ist dies entsprechend zu konfigurieren. Da ist per Default Get, Post und Head vorhanden.

Am schönsten müsste es sich integrieren, wenn du den ServerSocket nimmst. Dann kann das NOTIFY Event auf den ServerSocket verbinden und es direkt per RegisterVariable an das Sonos Skript weiterleiten :slight_smile:

paresy

Ja, das ist das Ziel! :smiley: (Ta Lun arbeitet nicht mit IPS)

Da kann ich ich nichts zu sagen aber würde mich mal interessieren. Ihr macht also pro Sonos einen Port auf um diesen dann zu identifizieren oder wie löst ihr das wenn es mehrere Geräte gibt?

Evtl. kann ich das ja ähnlich verarbeiten…

Nicht wirklich. Es geht nur darum, dass in IPS ein WebServer ziemlich eigenständig da steht und sich nicht vollautomatisch ins Konzept einbinden kann. (Kann schon, aber das ist kompliziert, da da man die (Notify-)Requests wieder ins eigentliche IP-Symcon System forwarden müsste)

Was es aber gibt, ist ein normaler TCP-Server, der sich so integrieren lässt, dass das Sonos PHP Skript direkt mit dem NOTIFY gestartet werden kann. (Wir können uns über einen TCP-Server ja einen WebServer nachbauen). Dadurch ist alles in einem Skript, welches hoffentlich am Ende automatisch Kategorien erstellt für die einzelnen Sonos Zonen, die wir dann im WebFront nur noch verlinken und glücklich sind :slight_smile:

paresy

Falls Jemand die Sonos Routinen aus dem br_ips Thread getestet hat… ich habe dort gerade einen Bug bei der Anzeige eines Group Unlinks behoben (Code ist im 1. Post; noch ohne Event Sub.).

Hallo zusammen,

erstmal danke für die vielen Hilfen, die man hier in dem Forum findet…
Und dann mein erster Post.

Ich hab mir ein Skript gebastelt, mit dem man die Weckzeit aus dem Sonos auslesen kann. (Achtung ich = php-Depp und IP-Symcon hab ich erst seit 3 Wochen…). Aber bei mir klappts!

Ich hab 2 Sonos-Player, deshalb sind die Variablen immer doppelt angegeben.
Weiterhin nutze ich nur einen Wecker pro Tag. Der String der aus der PHP-Klasse kommt, kann auch mehrer Wecker haben.

Folgende Vari´s müßen angelegt werden:

  • Weckzeit (String),
  • Wecker an?(Boolean),
  • Weckdauer (String),
  • Wecker Ende (String),
  • Zyklisches Ereignis bei einem Skript (das dann mit der Weckzeit etwas auslösen soll).

Hier das Skript:


//einbinden der Sonos Klasse
include("PHPSonos.inc.php");
//Player IP holen (Skript reciht, wenn es an einen Player gesendet wird, es werden alle Wecker ausgelesen)
$sonosip = GetValue(54945 ); //hier hole ich mir meine IP-Adresse eines Players
$sonos = new PHPSonos ($sonosip);

//RINCON einbinden
$RINCON_sonnendeck = GetValue(13380 );
$RINCON_stueberl = GetValue(17542 );

//Wecker Zeitvariablen definieren, im Webfront anzeigen
$id_WeckzeitSonnendeck = 45485 ;
$id_WeckzeitStueberl = 53428 ;

//Wecker an oder aus im Webfront anzeigen
$id_WeckerSonnendeckan = 23685 ;
$id_WeckerStueberlan = 54841 ;

//Weckdauer
$id_WeckdauerSonnendeck = 48686 ;
$id_WeckdauerStueberl = 17662 ;

//Wecker Ende
$id_WeckerEndeSonnendeck = 14209 ;
$id_WeckerEndeStueberl = 43707 ;

//Ereignis für Weckskript
$id_weckskript = 12141 ;

//XML-String aus Klasse aufbereiten
$Alarm = $sonos->GetAlarmTime();

//print_r ($Alarm);

//Berechnen des Weckerendes
$startzeit1 = substr($Alarm[0]['StartTime'],0,-3);
$dauer1 = substr($Alarm[0]['Duration'],0,-3);
$dauermin1 = (($dauer1[0].$dauer1[1])*60) + (($dauer1[3].$dauer1[4]));
$endewecker1 = date("H:i", strtotime($startzeit1) + $dauermin1*60);  //danke an muc


$haufigkeit1 = $Alarm[0]['Recurrence'];
	if ($haufigkeit1 == "DAILY"){$Datumstage1 = 127; $datumstyp = 0; $einmalig1datum=0; $Datumsintervall=0;}
	elseif ($haufigkeit1 == "ONCE"){$Datumstage1 = 0;$datumstyp = 1; $einmalig1datum=1; $Datumsintervall=0;}

	else
	{
	$welchetage1 = str_replace("ON_", "",$haufigkeit1);
	if (strpos ($welchetage1, "0") !== false){$sonntag1 = 64;}else{$sonntag1=0;}
	if (strpos ($welchetage1, "1") !== false){$montag1 = 1;}else{$montag1=0;}
	if (strpos ($welchetage1, "2") !== false){$dienstag1 = 2;}else{$dienstag1=0;}
	if (strpos ($welchetage1, "3") !== false){$mittwoch1 = 4;}else{$mittwoch1=0;}
	if (strpos ($welchetage1, "4") !== false){$donnerstag1 = 8;}else{$donnerstag1=0;}
	if (strpos ($welchetage1, "5") !== false){$freitag1 = 16;}else{$freitag1=0;}
	if (strpos ($welchetage1, "6") !== false){$samstag1 = 32;}else{$samstag1=0;}
	$Datumstage1 = $sonntag1+$montag1+$dienstag1+$mittwoch1+$donnerstag1+$freitag1+$samstag1;
	$datumstyp = 3;
	$einmalig1datum=0;
	$Datumsintervall=1;
	echo $Datumstage1;
	}

$weckeran1 = $Alarm[0]['Enabled'];
	if($weckeran1 == "1")	{	$weckeran1bool = "true";	}
	else	{	$weckeran1bool = "false";	}


$player1 = str_replace("RINCON_", "", $Alarm[0]['RoomUUID']);

//Daten schreiben
if ($player1 == $RINCON_sonnendeck)
{
SetValue($id_WeckzeitSonnendeck, $startzeit1);
SetValue($id_WeckerSonnendeckan, $weckeran1bool);
SetValue($id_WeckdauerSonnendeck, $dauermin1."min");
SetValue($id_WeckerEndeSonnendeck, $endewecker1);
}
elseif ($player1 == $RINCON_stueberl)
{
SetValue($id_WeckzeitStartzeit, $startzeit1);
SetValue($id_WeckerStueberlan, $weckeran1bool);
SetValue($id_WeckdauerStueberl, $dauermin1."min");
SetValue($id_WeckerEndeStueberl, $endewecker1);

}
else
{
echo "Kein Wecker vorhanden";
}

IPS_SetEventCyclic($id_weckskript, $datumstyp, $Datumsintervall, $Datumstage1, 0, 0, 0);
IPS_SetEventCyclicTimeBounds($id_weckskript,
mktime($startzeit1[0].$startzeit1[1], $startzeit1[3].$startzeit1[4], 0),
mktime($endewecker1[0].$endewecker1[1], $endewecker1[3].$endewecker1[4], 0));
IPS_SetEventCyclicDateBounds($id_weckskript,
mktime(0, 0, 0, date("m"), date("d"), date("Y")),
mktime(0, 0, 0, date("m"), date("d")+$einmalig1datum, date("Y")));
if ($weckeran1bool == "false")
{
IPS_SetEventActive($id_weckskript, false); //Ereignis deaktivieren
}
else
{
IPS_SetEventActive($id_weckskript, true); //Ereignis aktivieren
}



Weiterhin muß folgendes in die Sonos-Klasse (PHPSonos.inc.php) eingefügt werden:

Die neue (angepasste Funktion) ist auf der nächsten Seite.

so ich hoffe mein erster Auftritt hier blamiert mich nicht. Freu mich über Feedback und viele weitere Posts :wink:

Beste Grüße
iamking

Hallo und Willkommen,
schon eine gute Idee, das habe ich auch noch als Idee drauf. Ich würde es aber besser finden, wenn ein PHP Array als return übergeben wird wo die Daten schon sauber verarbeitet wurden.

Bei mir wird sowas ausgegeben:

<Alarms><Alarm ID=„4“ StartTime=„06:45:00“ Duration=„00:45:00“ Recurrence=„ON_1“ Enabled=„1“ RoomUUID=„RINCON_000E582244F401400“ ProgramURI=„x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u“ ProgramMetaData="<DIDL-Lite xmlns:dc=„http://purl.org/dc/elements/1.1/“ xmlns:upnp=„urn:schemas-upnp-org:metadata-1-0/upnp/“ xmlns:r=„urn:schemas-rinconnetworks-com:metadata-1-0/“ xmlns=„urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/“><item id=„S://TAMINAS/Musik/Playlists/aufwecken.m3u“ parentID=„A:PLAYLISTS“ restricted=„true“><dc:title>aufwecken.m3u</dc:title><upnp:class>object.container.playlistContainer</upnp:class><desc id=„cdudn“ nameSpace=„urn:schemas-rinconnetworks-com:metadata-1-0/“>RINCON_AssociatedZPUDN</desc></item></DIDL-Lite>" PlayMode=„SHUFFLE_NOREPEAT“ Volume=„55“ IncludeLinkedZones=„0“/><Alarm ID=„35“ StartTime=„06:00:00“ Duration=„01:00:00“ Recurrence=„ON_12345“ Enabled=„1“ RoomUUID=„RINCON_000E5823E01C01400“ ProgramURI=„x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u“ ProgramMetaData="<DIDL-Lite xmlns:dc=„http://purl.org/dc/elements/1.1/“ xmlns:upnp=„urn:schemas-upnp-org:metadata-1-0/upnp/“ xmlns:r=„urn:schemas-rinconnetworks-com:metadata-1-0/“ xmlns=„urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/“><item id=„S://TAMINAS/Musik/Playlists/aufwecken.m3u“ parentID=„A:PLAYLISTS“ restricted=„true“><dc:title>aufwecken.m3u</dc:title><upnp:class>object.container.playlistContainer</upnp:class><desc id=„cdudn“ nameSpace=„urn:schemas-rinconnetworks-com:metadata-1-0/“>RINCON_AssociatedZPUDN</desc></item></DIDL-Lite>" PlayMode=„SHUFFLE_NOREPEAT“ Volume=„69“ IncludeLinkedZones=„0“/><Alarm ID=„42“ StartTime=„10:00:00“ Duration=„02:00:00“ Recurrence=„ON_06“ Enabled=„1“ RoomUUID=„RINCON_000E5823E01C01400“ ProgramURI=„x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u“ ProgramMetaData="<DIDL-Lite xmlns:dc=„http://purl.org/dc/elements/1.1/“ xmlns:upnp=„urn:schemas-upnp-org:metadata-1-0/upnp/“ xmlns:r=„urn:schemas-rinconnetworks-com:metadata-1-0/“ xmlns=„urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/“><item id=„S://TAMINAS/Musik/Playlists/aufwecken.m3u“ parentID=„A:PLAYLISTS“ restricted=„true“><dc:title>aufwecken.m3u</dc:title><upnp:class>object.container.playlistContainer</upnp:class><desc id=„cdudn“ nameSpace=„urn:schemas-rinconnetworks-com:metadata-1-0/“>RINCON_AssociatedZPUDN</desc></item></DIDL-Lite>" PlayMode=„SHUFFLE_NOREPEAT“ Volume=„67“ IncludeLinkedZones=„0“/><Alarm ID=„409“ StartTime=„05:30:00“ Duration=„02:00:00“ Recurrence=„ONCE“ Enabled=„0“ RoomUUID=„RINCON_000E5823E01C01400“ ProgramURI=„x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u“ ProgramMetaData="<DIDL-Lite xmlns:dc=„http://purl.org/dc/elements/1.1/“ xmlns:upnp=„urn:schemas-upnp-org:metadata-1-0/upnp/“ xmlns:r=„urn:schemas-rinconnetworks-com:metadata-1-0/“ xmlns=„urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/“><item id=„S://TAMINAS/Musik/Playlists/aufwecken.m3u“ parentID=„A:PLAYLISTS“ restricted=„true“><dc:title>aufwecken.m3u</dc:title><upnp:class>object.container.playlistContainer</upnp:class><desc id=„cdudn“ nameSpace=„urn:schemas-rinconnetworks-com:metadata-1-0/“>RINCON_AssociatedZPUDN</desc></item></DIDL-Lite>" PlayMode=„SHUFFLE_NOREPEAT“ Volume=„71“ IncludeLinkedZones=„0“/><Alarm ID=„747“ StartTime=„08:55:00“ Duration=„01:00:00“ Recurrence=„ONCE“ Enabled=„0“ RoomUUID=„RINCON_000E582244F401400“ ProgramURI=„x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u“ ProgramMetaData="<DIDL-Lite xmlns:dc=„http://purl.org/dc/elements/1.1/“ xmlns:upnp=„urn:schemas-upnp-org:metadata-1-0/upnp/“ xmlns:r=„urn:schemas-rinconnetworks-com:metadata-1-0/“ xmlns=„urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/“><item id=„S://TAMINAS/Musik/Playlists/aufwecken.m3u“ parentID=„A:PLAYLISTS“ restricted=„true“><dc:title>aufwecken.m3u</dc:title><upnp:class>object.container.playlistContainer</upnp:class><desc id=„cdudn“ nameSpace=„urn:schemas-rinconnetworks-com:metadata-1-0/“>RINCON_AssociatedZPUDN</desc></item></DIDL-Lite>" PlayMode=„SHUFFLE_NOREPEAT“ Volume=„43“ IncludeLinkedZones=„0“/></Alarms>RINCON_000E582244F401400:1065

Wenn du die aktuelle Klasse hast findest Du Beispiele wo Du die Verarbeitung und Rücksendung eines PHP Array´s sehen kannst.
Wenn Du das selber machen willst wäre das super. Ich glaube das wäre einheitlicher, wenn wir das so angehen würden.

Hi Ta Lun,

ja du hast recht. So hatte ich auch angefangen.
Ich hab bei der „GetZoneAttributes“ und „GetMediaInfo“ ein bisschen gespickt.

Es werden ja 2 Werte Ausgegeben. Einmal die „CurrentAlarmList“ (ist das was du oben geschrieben hast) und einmal die „CurrentAlarmListVersion“.

Leider ist das Array „CurrentAlarmList“ immer leer, wenn ich nach den Beispielen oben arbeite, deshalb das komplizierte Skript von mir. Ich hab dann aufgegeben eine Ausgabe in einem Array umzusetzen.

Beispiel mit „GetZoneAttributes“ wie ich vorgegangen bin:


$TimeAttributes = Array();

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

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



bereits hier kommt ein leeres Array für „CurrentAlarmList“ zurück, die „CurrentAlarmListVersion“ ist aber gefüllt. Hier bin ich dann nicht mehr weitergekommen.

Wenn ich das richtig verstehe, sollte aber die gesamte AlarmList die du oben geschrieben hast in dem $key angezeigt werden, oder?

Falls ja, dann kann man hier weiter arbeiten und die Zerlegung des Strings entsprechend in der Klasse machen.

Also ich habe jetzt mal ein wenig die Function von Dir angepasst.
1.) Habe ich das senden auf einmal reduziert. Du hast das senden zweimal gemacht. Dann habe ich die Sonderzeichen so umgewandelt, das diese nicht mehr HTML Enteties sind sondern wieder echte Zeichen und gehe dann mit simple XML an die Rückgabe und teile dann das XML Objekt mit der for Schleife so auf, das ich jeden Wecker als Array in einem Array speichern kann.

Die Function sieht wie folgt aus:

 public function GetAlarmTime() 
	{

$header='POST /AlarmClock/Control HTTP/1.1
SOAPACTION: "urn:schemas-upnp-org:service:AlarmClock:1#ListAlarms"
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:AlarmClock xmlns:u="urn:schemas-upnp-org:service:AlarmClock:1"/>
</s:Body>
</s:Envelope>';
$content=$header . '
Content-Length: '. strlen($xml) .'

'. $xml;

				$returnContent = $this->XMLsendPacket($content);
				$returnContent = substr($returnContent, stripos($returnContent, '<'));
        $returnContent = substr($returnContent, 0, strrpos($returnContent, '>') + 4);
        $returnContent = str_replace(array("<", ">", """, "&", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
        $xmlr = new SimpleXMLElement($returnContent);
        $liste = array();
        for($i=0,$size=count($xmlr);$i<$size;$i++)
        {
            $attr = $xmlr->Alarm[$i]->attributes();
            $liste[$i]['ID'] = (string)$attr['ID'];
            $liste[$i]['StartTime'] = (string)$attr['StartTime'];
            $liste[$i]['Duration'] = (string)$attr['Duration'];
            $liste[$i]['Recurrence'] = (string)$attr['Recurrence'];
            $liste[$i]['Enabled'] = (string)$attr['Enabled'];
            $liste[$i]['RoomUUID'] = (string)$attr['RoomUUID'];
            $liste[$i]['ProgramURI'] = (string)$attr['ProgramURI'];
            $liste[$i]['PlayMode'] = (string)$attr['PlayMode'];
            $liste[$i]['Volume'] = (string)$attr['Volume'];
            
        }
        return $liste;
 	}

Das Ergebiss sieht nun wie folgt bei mir aus:

Array
(
[0] => Array
(
[ID] => 4
[StartTime] => 06:45:00
[Duration] => 00:45:00
[Recurrence] => ON_1
[Enabled] => 1
[RoomUUID] => RINCON_000E582244F401400
[ProgramURI] => x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u
[PlayMode] => SHUFFLE_NOREPEAT
[Volume] => 55
)

[1] =&gt; Array
    (
        [ID] =&gt; 35
        [StartTime] =&gt; 06:00:00
        [Duration] =&gt; 01:00:00
        [Recurrence] =&gt; ON_12345
        [Enabled] =&gt; 1
        [RoomUUID] =&gt; RINCON_000E5823E01C01400
        [ProgramURI] =&gt; x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u
        [PlayMode] =&gt; SHUFFLE_NOREPEAT
        [Volume] =&gt; 69
    )

[2] =&gt; Array
    (
        [ID] =&gt; 42
        [StartTime] =&gt; 10:00:00
        [Duration] =&gt; 02:00:00
        [Recurrence] =&gt; ON_06
        [Enabled] =&gt; 1
        [RoomUUID] =&gt; RINCON_000E5823E01C01400
        [ProgramURI] =&gt; x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u
        [PlayMode] =&gt; SHUFFLE_NOREPEAT
        [Volume] =&gt; 67
    )

[3] =&gt; Array
    (
        [ID] =&gt; 409
        [StartTime] =&gt; 05:30:00
        [Duration] =&gt; 02:00:00
        [Recurrence] =&gt; ONCE
        [Enabled] =&gt; 0
        [RoomUUID] =&gt; RINCON_000E5823E01C01400
        [ProgramURI] =&gt; x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u
        [PlayMode] =&gt; SHUFFLE_NOREPEAT
        [Volume] =&gt; 71
    )

[4] =&gt; Array
    (
        [ID] =&gt; 747
        [StartTime] =&gt; 08:55:00
        [Duration] =&gt; 01:00:00
        [Recurrence] =&gt; ONCE
        [Enabled] =&gt; 0
        [RoomUUID] =&gt; RINCON_000E582244F401400
        [ProgramURI] =&gt; x-file-cifs://TAMINAS/Musik/Playlists/aufwecken.m3u
        [PlayMode] =&gt; SHUFFLE_NOREPEAT
        [Volume] =&gt; 43
    )

Ich hoffe es ist klar was ich gemacht habe ansonsten Fragen. Du hast schon viel Vorarbeit geleistet. Ich habe nur noch copy&paste benötigt :wink:

Hi Ta Lun,

wow,
danke dir. Ich werd mir das mal ansehen, aber gib mir ein bis zwei Tage es zu verstehen. Die Fragen kommen dann (wahrscheinlich).

Gruß
iamking

Logo, kein Problem.

Ich habe in der Klasse weitere Änderungen an MediaInfo vorgenommen um die Informationen für Radiosender abzufragen. Außerdem habe ich die Änderungen von Ta lun zum Browse (leicht) verändert eingebaut und seinen letzten Vorschlag zur GetAlarmTime vorerst mal eingebaut (1:1) …

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

Beispiel zum browse():


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

/* ****************************** Browse EXAMPLE***********************/

$browseliste = $sonos->Browse("SQ:5","c"); // Diese spezifische Pl gibt es bei mir
            print_r($browseliste);

/* ****************************** /Browse EXAMPLE***********************/?>

Beispiel GetAlarmTime


/* ****************************** GetAlarmTime EXAMPLE***********************/
print_r($sonos->GetAlarmTime());

/* ****************************** GetAlarmTime EXAMPLE***********************/

Beispiel Output:



Array
(
    [0] => Array
        (
            [ID] => 36
            [StartTime] => 06:08:00
            [Duration] => 02:00:00
            [Recurrence] => ON_12345
            [Enabled] => 1
            [RoomUUID] => RINCON_000E58250B9C01400
            [ProgramURI] => x-sonosapi-stream:s8954?sid=254&flags=32
            [PlayMode] => NORMAL
            [Volume] => 15
        )

    [1] => Array
        (
            [ID] => 41
            [StartTime] => 07:59:00
            [Duration] => 02:00:00
            [Recurrence] => ONCE
            [Enabled] => 0
            [RoomUUID] => RINCON_000E58250B9C01400
            [ProgramURI] => x-sonosapi-stream:s8954?sid=254&flags=32
            [PlayMode] => SHUFFLE_NOREPEAT
            [Volume] => 24
        )

)

Grüße, Benjamin

PHPSonos.inc.zip (9.49 KB)

Mir fehlt Bei Dir die Function:

		function Subscribe($callback){
$content='SUBSCRIBE /MediaRenderer/AVTransport/Event HTTP/1.1
HOST: '.$this->address.':1400
CALLBACK: <'.$callback.'>
NT: upnp:event
TIMEOUT: Second-300
Content-Length: 0

';
$this->sendPacket($content);
} 

EDIT:
Ich habe nun mit Browse ein wenig getestet und bin nicht glücklich mit den Änderungen. Ich verarbeite dies mit Javascript. Und sämtliche Einträge, die Umlaute haben funktionieren nicht und haben null bei mir.
Ich weiß nicht wie ich das sauber verarbeiten kann. Die Lösung vorher hat bei mir funktioniert.
Hast Du eine Idee wie wir das hinbekommen? Ich will mich eigentlich nicht von diesem Projekt lösen und eine eigene Version nutzen.

Die Funktion findest Du unter dem Namen SubcribeMRAVTransport. Leider hat Sie im Zip noch keinen $callback Parameter, aber das ändere ich im nächsten ZIP.


/* urn:upnp-org:serviceId:AVTransport */
	function SubscribeMRAVTransport($callback){
$content='SUBSCRIBE /MediaRenderer/AVTransport/Event HTTP/1.1
HOST: '.$this->address.':1400
CALLBACK: <'.$callback.'>
NT: upnp:event
TIMEOUT: Second-300
Content-Length: 0

';
$this->sendPacket($content);
}

EDIT:
Ich habe nun mit Browse ein wenig getestet und bin nicht glücklich mit den Änderungen. Ich verarbeite dies mit Javascript. Und sämtliche Einträge, die Umlaute haben funktionieren nicht und haben null bei mir.
Ich weiß nicht wie ich das sauber verarbeiten kann. Die Lösung vorher hat bei mir funktioniert.
Hast Du eine Idee wie wir das hinbekommen? Ich will mich eigentlich nicht von diesem Projekt lösen und eine eigene Version nutzen.

Bei mir funktionierte die Browse vorher nicht mit Umlauten… jetzt schon. Ich schaue mir nochmal Deine Original Browse Funktion an und vergleiche die beiden.

[EDIT]Vielleicht hatte ich du zu schnell geändert und mich am print_r orientiert - im Browser ist es mit Deinem Browse richtig.

Dann klappt bei Dir so wieder alles?? (Zip unten)

PHPSonos.inc.zip (9.49 KB)

Teste ich und gebe eine Rückmeldung. Warum hast Du die Function Subscribe umbenannt?

Man kann ja nicht nur Mediarenderer->AvTransport Events subscriben sondern auch noch weitere Infos von anderen Services erhalten, deswegen fand ich Subscribe zu allgemein.

Ok ich habe das mit dem Subscribe so übernommen.

Bei Browse bitte noch folgende Änderungen:
Bei Dir:

$liste[$i]['albumArtURI'] ="none";

Habe ich wieder geändert in:

$liste[$i]['albumArtURI'] ="leer";

Bei Dir:

$liste[$i]['res'] = ($res); // was urlencoded

Habe ich geändert in:

$liste[$i]['res'] = (string)urlencode($res); // was urlencoded

Bei dem Bild basieren alle meine Scripte auf den return „leer“ und so ist dies einheitlicher in der Function.
Wenn Du urlencode dort nicht machst kann man im Browser den Wert nicht nutzen, da eine Raute (#) angehängt ist und dies im Brwoser einer Sprungmarke entspricht. Die anderen Dinge scheinen zu funktionieren und somit erstmal keine Einfwände :wink:

Bitte ändere das doch noch bei Dir um, damit wir wieder einheitlich sind.
Du bist so mein Repository Server :smiley:

hm…also ich glaube Du mußt Dir die Function Browse nochmal in ruhe ansehen. Ich bekomme die ParentID nicht mehr geliefert, dann wird wie oben beschrieben mal none, mal leer und mal nur „“ bei keinem Ergebnis zurück geliefert.
Ich habe jetzt meine alte Version wieder eingesetzt:

    //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";
	      	    	}
	        	    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;
    }

Gruß
Ta Lun

Ja, ich habe jetzt bei mir mal beide als Browse und Browse2 drin. Die fehlende ParentID kann ich nachvollziehen bei mir. Ich habe mal den Output bei Playlisten verglichen und würde nun Deine Funktion - wie von Dir gepostet- in die Klasse übernehmen. Allerdings würde ich dabei gerne die Rückgabe von „leer“ bei AlbumArtUri durchweg auf „“ anpassen, so arbeiten die meisten anderen Funktionen der Klasse derzeit auch. :eek:

Mein Problem ist, ich setze einige Funktionen wie auch das Browse aktuell nicht mit IPS jeden Tag ein und kann daher schwer bewerten wie es richtig ist. Ich muss mir also Testfälle basteln und skripten für so ein Browse um überhaupt bewerten zu können, macht die Funktion bei mir das gewünschte… und über Testfälle deckt man ja bekanntermaßen nur einen Teil der Realität ab. :smiley:

Des weiteren würde ich die Paremeter der Funktion anpassen (auch wenn das bisher erstmal wenig Funktion hat), da die Soap Methode Browse laut Device Spy einges mehr ermöglicht (ist ja auch an Deinem SOAP Code zu sehen).
Vorschlag wäre:

Browse($value,$meta="BrowseDirectChildren",$filter="",$sindex="",$rcount="",$sc="")

Eigentlich sollte sich dadurch ja wenig ändern und man kann die Funktion dann wie vorher, mit 1 oder 2, aber auch auch den weiteren Parametern aufrufen.

Was hälst Du davon??

[EDIT]
Ach, die GetAlarmTime würde ich in ListAlarms umbenennen - das enstricht dann dem SOAP Namen und die Funktion gibt ja auch genau das zurück.
Grüße, Benjamin