Piloter une enceinte Phantom Reactor

Bonjour,

J’ai découvert la semaine dernière que Devialet propose désormais une api permettant aux produits Phantom d’être contrôlés en utilisant des commandes réseaux. Cela permet donc de l’intégrer à un système domotique et donc à Jeedom.

Je me dis que ce que j’ai fais pour moi, même s’il n’y a rien de sorcier, pourrait être utile à d’autres. Aussi, je vous décrit rapidement ce que j’ai mis en place. Si certains sont intéressés par plus de détails, je pourrai toujours compléter par la suite.

En résumé, le système repose sur :

  • un virtuel disposant des commandes infos nous intéressant (état, volume, titre joué, …) et des commandes actions permettant d’interagir avec l’enceinte (play, pause, …),
  • un scénario en php récupérant les infos de l’enceinte et valorisant les commandes infos du virtuel,
  • un objet ‹ script › appelés par les commandes actions du virtuel et contenant le code php qui passe les commandes à l’enceinte.

Pour la config du virtuel, ça se passe comme sur la capture ci-dessous :

Ce qui donne sur le dashboard :
virt-dashboard

Le scénario est programmé pour s’exécuter toutes les minutes. Voici le code php :

<?php
	/* Virtuel de l'enceinte */
	$objVirt = '[Salon][Phantom Reactor]';

	/* Récupération des tags */
	$tags = $scenario->getTags();
	$infoDevice = $tags['#infoDevice#'];

	/* Génération de l'url de base */
	$IP = cmd::byString('#'.$objVirt.'[IP]#')->execCmd();
	$baseUrl = 'http://'.$IP.'/ipcontrol/v1';

	$powerState = cmd::byString('#'.$objVirt.'[powerState]#')->execCmd();
	if($powerState == 0){
		echo 'Enceinte non joignable';
		$scenario->setIsActive(0)->save();
	} else {
	  /* Infos statiques */
	  if ($infoDevice == 1){
		$endPoint = '/devices/current';

		$url = $baseUrl.$endPoint;
		$json = file_get_contents($url);
		$data = json_decode($json);

		$deviceName = $data->deviceName;
		$model = $data->model;
		$role = $data->role;
		cmd::byString('#'.$objVirt.'[deviceName]#')->event($deviceName);
		cmd::byString('#'.$objVirt.'[modele]#')->event($model);
		cmd::byString('#'.$objVirt.'[role]#')->event($role);
	  }

	  /* Infos dynamiques */
	  // Volume
	  $endPoint = '/systems/current/sources/current/soundControl/volume';

	  $url = $baseUrl.$endPoint;
	  $json = file_get_contents($url);
	  $data = json_decode($json);

	  $volume = $data->systemVolume;
	  cmd::byString('#'.$objVirt.'[volume]#')->event($volume);

	  // Lecture en cours
	  $endPoint = '/groups/current/sources/current';

	  $url = $baseUrl.$endPoint;
	  $json = file_get_contents($url);
	  $data = json_decode($json);

	  $playingState = $data->playingState;
	  $muteState = $data->muteState;
	  $sourceType = $data->source->type;
	  cmd::byString('#'.$objVirt.'[playingState]#')->event($playingState);
	  cmd::byString('#'.$objVirt.'[muteState]#')->event($muteState);
	  cmd::byString('#'.$objVirt.'[sourceType]#')->event($sourceType);

	  $artist = $data->metadata->artist;
	  $album = $data->metadata->album;
	  $title = $data->metadata->title;
	  cmd::byString('#'.$objVirt.'[artist]#')->event($artist);
	  cmd::byString('#'.$objVirt.'[album]#')->event($album);
	  cmd::byString('#'.$objVirt.'[title]#')->event($title);
}?>

Pour le script, chaque commande appelle le même script en passant la commande voulue en paramêtre.

Le code du script :

<?php
	/* Adresse IP de l'enceinte */
	$IP = '192.168.1.10';
	//$IP = cmd::byString('#[Salon][Phantom Reactor][IP]#')->execCmd();

	$baseUrl = 'http://'.$IP.'/ipcontrol/v1';
	$command = $argv[1];


	switch ($command) {
	  case 'volumeUp':
		$endPoint = '/systems/current/sources/current/soundControl/volumeUp';
		$data = array(
		);
		break;
	  case 'volumeDown':
		$endPoint = '/systems/current/sources/current/soundControl/volumeDown';
		$data = array(
		);
		break;
	  case 'mute':
		$endPoint = '/groups/current/sources/current/playback/mute';
		$data = array(
		);
		break;
	  case 'unmute':
		$endPoint = '/groups/current/sources/current/playback/unmute';
		$data = array(
		);
		break;
	  case 'play':
		$endPoint = '/groups/current/sources/current/playback/play';
		$data = array(
		);
		break;
	  case 'pause':
		$endPoint = '/groups/current/sources/current/playback/pause';
		$data = array(
		);
		break;
	  case 'next':
		$endPoint = '/groups/current/sources/current/playback/next';
		$data = array(
		);
		break;
	  case 'previous':
		$endPoint = '/groups/current/sources/current/playback/previous';
		$data = array(
		);
		break;
	  case 'nightModeOn':
		$endPoint = '/systems/current/settings/audio/nightMode';
		$data = array(
			'nightMode'        => 'on'
		);
		break;
	  case 'nightModeOff':
		$endPoint = '/systems/current/settings/audio/nightMode';
		$data = array(
			'nightMode'        => 'off'
		);
		break;
	  default:
		$endPoint = 'nok';
		echo 'Commande inconnue';
	} 

	if ($endPoint != 'nok'){
		$url = $baseUrl.$endPoint;
		/* Creation des options de contexte */
		$options = array(
			'http' => array(
				'method'  => 'POST',
				'header'  => "Content-Type: application/json",
				'ignore_errors' => true,
				'timeout' =>  1,
				'content' => json_encode($data),
			),
		);

		/* Creation du contexte HTTP */
		$context  = stream_context_create($options);

		/* Execution de la requete */
		file_get_contents($url, false, $context);
	}
?>

Mon intégration repose également sur un objet du plugin ‹ Network › qui me permet de savoir si l’enceinte est allumée ou pas. Je peux ainsi désactiver le scénario si l’enceinte est éteinte et le réactiver lorsque j’allume l’enceinte.

Pour plus d’infos, la doc de l’api peut être trouvée à cette adresse : https://help.devialet.com/hc/fr/articles/4415207423378-Documentation-pour-piloter-Phantom-via-IP

6 « J'aime »

Je rajoute le code pour un widget affichant la pochette de l’album en cours de lecture.

<div class="cmd cmd-widget" data-type="info" data-subtype="string" data-cmd_id="#id#" data-cmd_uid="#uid#">
	<div class="content-sm ">
		<img class="IMGalbumCover#uid#" src="" />
	</div>
	<style>
		img.IMGalbumCover#uid# {
			max-width: 120px;
			height: auto;
			border-radius: 8px;
			filter: grayscale(0%);
		}        
	</style>   
	<script>
		jeedom.cmd.update['#id#'] = function(_options){
          	if (_options.display_value == '0') {
            	$('.cmd[data-cmd_id=#id#] .IMGalbumCover#uid#').empty().attr('src', 'data/customTemplates/dashboard/paused-cover.jpg');
            }else{
				$('.cmd[data-cmd_id=#id#] .IMGalbumCover#uid#').empty().attr('src', _options.display_value);
            }			
		}
		jeedom.cmd.update['#id#']({display_value: '#state#'})
	</script>
</div>
1 « J'aime »

Hello
Bah il est bien cool ton post
Je m’en suis pas mal inspiré pour intégrer ma Phantom I
A l’occasion, j’ecrirais un post en citant le tien …
Pour la mise à jour, tu peux pour chaque commande declenchée, lancer la MAJ de ton virtuel, en declanchant ton scenario apres l’execution de chaque commande du script (config avancee de la commande, config, Action après exécution de la commande, Scenario et hop ); Mais ca ne permet de mettre à jour que sur action sur le virtuel …