diff --git a/README.md b/README.md
index a79d7d1..0b75b35 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,6 @@ Plugin for Jeedom Open Source domotic solution.
Remotely control Google Cast devices directly from Jeedom.
-
![Logo Jeedom](docs/assets/images/logo.png "Logo Jeedom")
![Logo plugin](docs/images/logoplugin.png "Logo plugin")
diff --git a/core/class/googlecast.class.php b/core/class/googlecast.class.php
index e7479c7..3fccc01 100644
--- a/core/class/googlecast.class.php
+++ b/core/class/googlecast.class.php
@@ -17,8 +17,8 @@
*/
/* * ***************************Includes********************************* */
-//error_reporting(E_ALL);
-//ini_set('display_errors', 'On');
+error_reporting(E_ALL);
+ini_set('display_errors', 'On');
require_once dirname(__FILE__) . "/googlecast_utils.inc.php";
@@ -713,6 +713,10 @@ public function getChromecastIP() {
return $this->getConfiguration('ip', '');
}
+ public function getUUID() {
+ return $this->getConfiguration('uuid', '');
+ }
+
public function getChromecastURI() {
return $this->getConfiguration('uri', '');
}
@@ -935,6 +939,7 @@ public function refreshStatusByUUID($uuid) {
}
public function helperSendSimpleCmd($command_name, $value=null, $_callback=null, $_source='googlecast', $_app='media', $_appid='CC1AD845') {
+ $command_name = googlecast_utils::getFullCmdTranslation($command_name);
$fulldata = array(
'apikey' => jeedom::getApiKey('googlecast'),
'cmd' => 'action',
@@ -954,13 +959,16 @@ public function helperSendSimpleCmd($command_name, $value=null, $_callback=null,
return self::socket_connection( json_encode($fulldata) );
}
+ // send commands as php array of by sequence (seperated by $$)
public function helperSendCustomCmd($_commands, $_callback=null, $_source='googlecast', $_app='media', $_appid='CC1AD845') {
$datalist = array();
$commandlist = $_commands;
if ( !is_array($_commands) ) {
- $commandlist = array($_commands);
+ $commandlist = explode('$$', $_commands);
}
foreach ($commandlist as $commandstring) {
+ $commandstring = googlecast_utils::getFullCmdTranslation($commandstring);
+
$data = array();
$splitcmd = explode('|', $commandstring);
$splitcount = count($splitcmd);
@@ -988,6 +996,7 @@ public function helperSendCustomCmd($_commands, $_callback=null, $_source='googl
}
array_push($datalist, $data);
}
+ log::add('googlecast','debug','helperSendCustomCmd : ' . print_r($datalist, true));
$fulldata = array(
'apikey' => jeedom::getApiKey('googlecast'),
@@ -1014,7 +1023,7 @@ public function helperSendConfigInfoCmd($_commands, $_destLogicalId, $setType=fa
}
public function getInfoHttpSimple($cmdLogicalId, $destLogicalId=null) {
- $cmdLogicalIdTranslate = googlecast_utils::getCmdTranslation($cmdLogicalId);
+ $cmdLogicalIdTranslate = googlecast_utils::getFullCmdTranslation($cmdLogicalId);
if (is_null($destLogicalId)) {
$destLogicalId = ($cmdLogicalIdTranslate!=$cmdLogicalId ? $cmdLogicalId : null);
}
@@ -1229,7 +1238,7 @@ private function recursePath($array, $pathList, $errorRet) {
}
public function setInfoHttpSimple($cmdLogicalId, $destLogicalId=null) {
- $cmdLogicalId = googlecast_utils::getCmdTranslation($cmdLogicalId);
+ $cmdLogicalId = googlecast_utils::getFullCmdTranslation($cmdLogicalId);
return $this->setInfoHttp($cmdLogicalId, false, $destLogicalId);
}
@@ -1293,6 +1302,26 @@ public function setInfoHttp($cmdLogicalId, $showError=false, $destLogicalId=null
}
}
+ public function getInfoValue($logicalID) {
+ $cmd = $this->getCmd('info', $logicalID);
+ if (!is_object($cmd) ) {
+ return null;
+ }
+ $ret = $cmd->execCmd();
+ if ( is_null($ret) ) {
+ return '';
+ }
+ return $ret;
+ }
+
+ public function isOnline() {
+ $ret = $this->getInfoValue('online');
+ if ($ret==1 or $ret===true ) {
+ return true;
+ }
+ return false;
+ }
+
}
class googlecastcmd extends cmd {
@@ -1303,84 +1332,99 @@ class googlecastcmd extends cmd {
/* * *********************Methode d'instance************************* */
public function execute($_options = null) {
- $listCmd = googlecast_utils::getCmdTranslation($this->getLogicalId());
- $eqLogic = $this->getEqLogic();
+ $originalLogicalId = $this->getLogicalId();
- # special case of custom command
- if ($listCmd == "customcmd") {
- $listCmd = trim($_options['message']);
- }
- # special case of 'action' command with subtype 'list' starting with 'cmdlist_'
- if ( strpos($listCmd, 'cmdlist_')===0 ) {
- $listCmd = str_replace('^', '|', trim($_options['select'])); // replace ^ by |
- if ($listCmd=='') { // case of default value ('none' selected)
- $listCmd='quit_app';
- }
- }
+ $originalLogicalId = googlecast_utils::getFullCmdTranslation($originalLogicalId);
- // if this is a command 'info' to retrieve google cast device configuration using http
- if ($this->getType() != 'action') {
- // command must contains string 'cmd=getconfig'
- if (stristr($listCmd, 'cmd=getconfig')!=false) {
- $eqLogic->getInfoHttpSimple($listCmd, $this->getLogicalId());
- log::add('googlecast','debug',"Envoi d'une commande GoogleCast API http depuis Jeedom");
- }
- else {
- return;
- }
- }
+ if ( $this->getType() == 'action' ) {
+ # special case of custom command
+ if ($originalLogicalId == "customcmd") {
+ $originalLogicalId = trim($_options['message']);
+ }
- // 'refresh' type command
- if ($listCmd == "refreshconfig" || $listCmd == "refresh") {
- // both refresh commands require refreshing conifguration command refresh
- foreach ($eqLogic->getCmd('info') as $cmd) {
- $logicalId = googlecast_utils::getCmdTranslation($cmd->getLogicalId());
- if (stristr($logicalId, 'cmd=getconfig')!=false) {
- $eqLogic->getInfoHttpSimple($logicalId, $cmd->getLogicalId());
+ # special case of 'action' command with subtype 'list' starting with 'cmdlist_'
+ elseif ( strpos($originalLogicalId, 'cmdlist_')===0 ) {
+ $originalLogicalId = str_replace('^', '|', trim($_options['select'])); // replace ^ by |
+ if ($originalLogicalId=='') { // case of default value ('none' selected)
+ $originalLogicalId='quit_app';
}
- }
+ }
- if ($listCmd == "refreshconfig") {
- return; // do not need to go further in that case
+ if ($originalLogicalId=='') {
+ return;
}
}
- // if this is a command 'action' to modify google cast device configuration using http
- if (stristr($listCmd, 'cmd=setconfig')!=false) {
- log::add('googlecast','debug',"Envoi d'une commande GoogleCast API http depuis Jeedom (set)");
- $eqLogic->setInfoHttpSimple($listCmd, null);
- return;
+ $listCmd = $originalLogicalId;
+
+ $eqLogic = $this->getEqLogic();
+
+ switch ($this->getSubType()) { // manage placeholder replacement
+ case 'slider':
+ $listCmd = str_replace('#slider#', $_options['slider'], $listCmd);
+ break;
+ case 'color':
+ $listCmd = str_replace('#','',str_replace('#color#', $_options['color'], $listCmd));
+ break;
+ case 'select':
+ $listCmd = str_replace('#listValue#', $_options['select'], $listCmd);
+ break;
+ case 'message':
+ $listCmd = str_replace('#message#', $_options['message'], $listCmd);
+ if ( isset($_options['title']) ) {
+ $listCmd = str_replace('#title#', $_options['title'], $listCmd);
+ }
+ if ( isset($_options['volume']) ) {
+ $listCmd = str_replace('#volume#', $_options['volume'], $listCmd);
+ }
+ break;
}
$datalist=array();
$cmdgroups = explode('$$', $listCmd); // split multiple commands (sequences)
+
foreach ($cmdgroups as $listCmd) {
+ $originalListCmd = $listCmd;
+ $listCmd = googlecast_utils::getFullCmdTranslation($originalListCmd);
$data = array();
+
+ // if this is a command 'info' to retrieve google cast device configuration using http
+ if ($this->getType() != 'action') {
+ // command must contains string 'cmd=getconfig'
+ if (stristr($listCmd, 'cmd=getconfig')!=false) {
+ $eqLogic->getInfoHttpSimple($listCmd, $originalListCmd);
+ log::add('googlecast','debug',"Envoi d'une commande GoogleCast API http depuis Jeedom");
+ }
+ else {
+ continue;
+ }
+ }
+
+ // 'refresh' type command
+ if ($listCmd == "refreshconfig" || $listCmd == "refresh") {
+ // both refresh commands require refreshing conifguration command refresh
+ foreach ($eqLogic->getCmd('info') as $cmd) {
+ $logicalId = googlecast_utils::getFullCmdTranslation($cmd->getLogicalId());
+ if (stristr($logicalId, 'cmd=getconfig')!=false) {
+ $eqLogic->getInfoHttpSimple($logicalId, $cmd->getLogicalId());
+ }
+ }
+
+ if ($listCmd == "refreshconfig") {
+ continue; // do not need to go further in that case
+ }
+ }
+ // if this is a command 'action' to modify google cast device configuration using http
+ if (stristr($listCmd, 'cmd=setconfig')!=false) {
+ log::add('googlecast','debug',"Envoi d'une commande GoogleCast API http depuis Jeedom (set)");
+ $eqLogic->setInfoHttpSimple($listCmd, null);
+ continue;
+ }
+
$values = explode('|', $listCmd); // split commands
foreach ($values as $value) {
$value = explode('=', $value);
if (count($value) == 2) { // X=Y
- switch ($this->getSubType()) { // manage placeholder replacement
- case 'slider':
- $data[trim($value[0])] = trim(str_replace('#slider#', $_options['slider'], $value[1]));
- break;
- case 'color':
- $data[trim($value[0])] = str_replace('#','',trim(str_replace('#color#', $_options['color'], $value[1])));
- break;
- case 'select':
- $data[trim($value[0])] = trim(str_replace('#listValue#', $_options['select'], $value[1]));
- break;
- case 'message':
- $data[trim($value[0])] = trim(str_replace('#message#', $_options['message'], $value[1]));
- if ( isset($_options['title']) ) {
- $data[trim($value[0])] = trim(str_replace('#title#', $_options['title'], $data[trim($value[0])]));
- }
- if ( isset($_options['volume']) ) {
- $data[trim($value[0])] = trim(str_replace('#volume#', $_options['volume'], $data[trim($value[0])]));
- }
- break;
- default:
- $data[trim($value[0])] = trim($value[1]);
- }
+ $data[trim($value[0])] = trim($value[1]);
}
elseif (count($value) == 1) { // // X only, then assume this is a command
$data['cmd'] = trim($value[0]);
@@ -1388,17 +1432,19 @@ public function execute($_options = null) {
case 'slider':
$data['value'] = $_options['slider'];
break;
+ /*
case 'select':
$data['value'] = trim($_options['select']);
break;
case 'message':
$data['value'] = trim($_options['message']);
break;
+ */
}
}
}
if (count($data) == 0) { // something is wrong because no value
- return;
+ continue;
}
array_push($datalist, $data); // push in the sequence array (even if only one command)
}
diff --git a/core/class/googlecast_utils.inc.php b/core/class/googlecast_utils.inc.php
index 9721982..4faf94d 100644
--- a/core/class/googlecast_utils.inc.php
+++ b/core/class/googlecast_utils.inc.php
@@ -4,7 +4,7 @@
class googlecast_utils {
- public static function getCmdTranslation($logicalId) {
+ public static function getFullCmdTranslation($logicalId) {
$ret = $logicalId;
if ( $logicalId == 'speak' ) {
@@ -21,7 +21,6 @@ public static function getCmdTranslation($logicalId) {
$radioname = strtolower(str_replace("radio_", "", $logicalId));
$radioArray = json_decode(file_get_contents(dirname(__FILE__) . "/../webradios/radiolist.json"), true);
if ( isset($radioArray[$radioname]) ) {
-
$radio = $radioArray[$radioname];
$ret = "app=media|value='".$radio['location']."','audio/mpeg',title:'".$radio['title']."',thumb:'".$radio['image']."'";
}
@@ -131,6 +130,11 @@ public static function getCmdTranslation($logicalId) {
return $ret;
}
+
+ public static function getCmdTranslation($cmd) {
+ return $cmd;
+ }
+
public static function getJsonPathResult($json, $path) {
$store = new JsonStore($json);
return $store->get($path);
diff --git a/core/webradios/radiolist.json b/core/webradios/radiolist.json
index 209e966..df4c117 100644
--- a/core/webradios/radiolist.json
+++ b/core/webradios/radiolist.json
@@ -91,8 +91,8 @@
},
"pulsradio_trance": {
"location": "http://icecast.pulsradio.com:80/pulstranceHD.mp3",
- "title": "PulsRadio Trance",
- "image": "http://www.pulsradio.com/trance/logo.png"
+ "title": "PulsRadio Trance",
+ "image": "http://www.pulsradio.com/trance/logo.png"
},
"pulsradio_lounge": {
"location": "http://icecast.pulsradio.com/relaxHD.mp3",
diff --git a/docs/fr_FR/index.md b/docs/fr_FR/index.md
index b238117..5823d98 100644
--- a/docs/fr_FR/index.md
+++ b/docs/fr_FR/index.md
@@ -268,9 +268,11 @@ Elles doivent être séparés par *|*
- sleep (optional, int/float) : add a break after end of command in seconds (eg: 2, 2.5)
- uuid (optional) : redirect to other google cast uuid in new thread (parallel processing). Useful when using sequences on several device.
- nothread (optional) : if uuid provided, disable use of thread for parallel processing. (eg: nothread=1)
+- brodcast (optional) : 'all' to broadcast to all connected devices or seperated by ',' (ex: 'uuid1,uuid2')
ex web : app=web|cmd=load_url|vol=90|value='http://pictoplasma.sound-creatures.com',True,10
ex TTS : cmd=tts|vol=100|value=Mon text a dire
+ex broadcast : cmd=quit_app|broadcast=all
```
> **Notes**
@@ -574,7 +576,7 @@ if ( !is_object($googlecast) or $googlecast->getIsEnable()==false ) {
// variable _test contains 'None' if google cast does not exist or is disable
}
else {
- // Run a command
+ // Run a command as single command or sequence (seperated by $$) or by sending a php array of commands
$ret = $googlecast->helperSendCustomCmd('cmd=tts|value=Test Scénario PHP|vol=100');
$scenario->setData("_test", $ret);
// Command launched
@@ -605,6 +607,34 @@ else {
}
```
+Exemple d'attente de fin de commande TTS ou NOTIF :
+
+```php
+$uuid = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX';
+$maxwait = 30; // 30 sec of max waiting
+$retrydelay = 500*1000; // will retry every 500 ms
+
+$googlecast = googlecast::byLogicalId($uuid, 'googlecast');
+if ( !is_object($googlecast) or $googlecast->getIsEnable()==false or $googlecast->isOnline()==false ) {
+ return;
+}
+else {
+ $command_string = 'cmd=tts|value=Test Scénario PHP pour gérer le délai !|vol=100';
+ $googlecast->helperSendCustomCmd($command_string);
+ sleep(2); // make sure command has started
+ $status = $googlecast->getInfoValue('status_text');
+ $starttime = time();
+ while ($status=='Casting: TTS' or $status=='Casting: NOTIF' ) {
+ usleep($retrydelay); // or sleep(1); // 1 sec
+ $status = $googlecast->getInfoValue('status_text');
+ if ( (time()-$starttime)>$maxwait ) {
+ break;
+ }
+ }
+ return;
+}
+```
+
### Utilisation avec interactions et IFTTT
#### Interactions
diff --git a/resources/googlecast.py b/resources/googlecast.py
index be8b517..e471f89 100644
--- a/resources/googlecast.py
+++ b/resources/googlecast.py
@@ -573,6 +573,26 @@ def action_handler(message):
for command in commandlist :
uuid = srcuuid
+
+ if 'broadcast' in command :
+ broadcastList = command['broadcast']
+ if broadcastList == 'all' :
+ uuidlist = list(globals.GCAST_DEVICES.keys())
+ else :
+ uuidlist = broadcastList.split(',')
+ for newUuid in uuidlist :
+ newcmd = command.copy()
+ del newcmd['broadcast']
+ newMessage = {
+ 'cmd' : 'action',
+ 'delegated' : True,
+ 'device' : {'uuid' : newUuid, 'source' : message['device']['source'] },
+ 'command' : newcmd
+ }
+ logging.debug("ACTION------DELEGATED command to other uuid : " + newUuid)
+ thread.start_new_thread( action_handler, (newMessage,))
+ continue
+
if 'uuid' in command :
if 'nothread' in command and command['uuid'] in globals.GCAST_DEVICES:
uuid = command['uuid']
@@ -944,20 +964,8 @@ def action_handler(message):
forceapplaunch = False
if 'forceapplaunch' in command :
forceapplaunch = True
- prevcommand = jcast.getPreviousPlayerCmd(forceapplaunch)
- if prevcommand is not None :
- newMessage = {
- 'cmd' : 'action',
- 'delegated' : True,
- 'resume' : True,
- 'device' : {'uuid' : uuid, 'source' : message['device']['source'] },
- 'command' : prevcommand
- }
- logging.debug("NOTIF------DELEGATED RESUME AFTER NOTIF for uuid : " + uuid)
- time.sleep(0.3)
- jcast.resetPreviousPlayerCmd()
- thread.start_new_thread( action_handler, (newMessage,))
- else :
+ resumeOk = manage_resume(uuid, message['device']['source'], forceapplaunch, 'NOTIF')
+ if resumeOk==False :
logging.debug("NOTIF------Resume is not possible!")
else :
logging.debug("NOTIF------Error while getting local media !")
@@ -1037,20 +1045,9 @@ def action_handler(message):
forceapplaunch = False
if 'forceapplaunch' in command :
forceapplaunch = True
- prevcommand = jcast.getPreviousPlayerCmd(forceapplaunch)
- if prevcommand is not None :
- newMessage = {
- 'cmd' : 'action',
- 'delegated' : True,
- 'resume' : True,
- 'device' : {'uuid' : uuid, 'source' : message['device']['source'] },
- 'command' : prevcommand
- }
- logging.debug("TTS------DELEGATED RESUME AFTER TTS for uuid : " + uuid)
- time.sleep(0.3)
- jcast.resetPreviousPlayerCmd()
- thread.start_new_thread( action_handler, (newMessage,))
- else :
+
+ resumeOk = manage_resume(uuid, message['device']['source'], forceapplaunch, 'TTS')
+ if resumeOk==False :
logging.debug("TTS------Resume is not possible!")
else :
logging.debug("TTS------File generation failed !")
@@ -1100,6 +1097,16 @@ def action_handler(message):
logging.debug("ACTION------Stop action")
player.pause()
fallbackMode=False
+ elif cmd == 'resume':
+ forceapplaunch = False
+ if 'forceapplaunch' in command :
+ forceapplaunch = True
+ resumeOk = manage_resume(uuid, message['device']['source'], forceapplaunch, 'ACTION')
+ if resumeOk==False :
+ logging.debug("ACTION------Resume is not possible!")
+ else :
+ logging.debug("ACTION------Resume OK")
+ fallbackMode=False
elif cmd == 'sleep':
logging.debug("ACTION------Sleep")
time.sleep(float(value))
@@ -1140,6 +1147,24 @@ def manage_callback(uuid, callback_type):
# todo things for callback before returning value
return True
+def manage_resume(uuid, source='googlecast', forceapplaunch=False, origin='TTS'):
+ jcast = globals.GCAST_DEVICES[uuid]
+ prevcommand = jcast.getPreviousPlayerCmd(forceapplaunch)
+ if prevcommand is not None :
+ newMessage = {
+ 'cmd' : 'action',
+ 'delegated' : True,
+ 'resume' : True,
+ 'device' : {'uuid' : uuid, 'source' : source },
+ 'command' : prevcommand
+ }
+ logging.debug("RESUME------DELEGATED RESUME AFTER "+origin+" for uuid : " + uuid)
+ time.sleep(0.3)
+ jcast.resetPreviousPlayerCmd()
+ thread.start_new_thread( action_handler, (newMessage,))
+ return True
+ return False
+
def get_tts_data(text, language, engine, speed, forcetts, calcduration, silence=300):
srclanguage = language
if not globals.tts_gapi_haskey and (engine=='gttsapi' or engine=='gttsapidev') :