REST API events

145 views
Skip to first unread message

Roarster

unread,
Apr 12, 2012, 6:21:48 PM4/12/12
to karo...@googlegroups.com
Is it possible to receive some sort of callback or trigger when an event has finished? Such as finished speaking or finished moving ears. Otherwise it's near to impossible to know when to send the stop action and end the interactiveid.

Marcus Gerards

unread,
Apr 13, 2012, 1:33:47 AM4/13/12
to karo...@googlegroups.com
Am Freitag, 13. April 2012 00:21:48 UTC+2 schrieb Roarster:
Is it possible to receive some sort of callback or trigger when an event has finished? Such as finished speaking or finished moving ears. Otherwise it's near to impossible to know when to send the stop action and end the interactiveid.

Actually yes, you automatically get that. Took me a week of frustration to find out, but here it is (REST API):

1. The servers initiate the app (or you do it via signed-method). In any case, you get the interactiveID via $_GET.
2. You start the first event. Then you script terminates
3. The servers call your script again, this time with a POST, containing the XML-VoosMsg. Your script has to handle this case and check, if the POST contains a VoosMsg->correlationID. It also contains the interactiveID, which you need because your script won't remember it. 
4.  If, yes,you will have to check VoosMsg->event, for it being either "TERMINATED or "CANCELLED". Then your event has finished and you can fire up the next.
5. BEWARE: Your script will also be called upon button-pressed-events and - though I'm not sure, yet - each time the server accepts a coomand.

You can use various methods to store scheduled events between script calls. I use a SESSION with the interactiveID as the SESSION-ID, so I can pick up the right session on each call (I also store an array of events in the SESSION). You may use a database, a text file, whatever to achieve this.

If you have access to the shell of your webserver a 

tail -f /var/log/apache2/access.log (assuming an apache server)

can be helpful to learn about the callback behaviour.

Feel free to ask more questions - to get this working was most frustrating at times and I wouldn't want anyone to relive that.

Best wishes,

Marcus


Roarster

unread,
Apr 13, 2012, 5:33:07 AM4/13/12
to karo...@googlegroups.com
Thanks, that does help! From the looks of it will i need all all my commands to go through the server that the callback url points to? I'm making an android app and at the moment it sends all the commands straight to the karotz servers. Do you think it would be possible to:
1) send the command to my server(from the app)
2)the server then doesn't respond but sends the command to the api
3)when my server receives the finished code it then finally responds to the request the app made

i just don't know if that's possible in php(the only one i know)

Marcus Gerards

unread,
Apr 13, 2012, 6:19:49 AM4/13/12
to karo...@googlegroups.com


On Friday, April 13, 2012 11:33:07 AM UTC+2, Roarster wrote:
Thanks, that does help! From the looks of it will i need all all my commands to go through the server that the callback url points to?

Yes, but the callback-URL has to be located on your server!
 
I'm making an android app and at the moment it sends all the commands straight to the karotz servers. Do you think it would be possible to:
1) send the command to my server(from the app)
2)the server then doesn't respond but sends the command to the api
3)when my server receives the finished code it then finally responds to the request the app made

That's no problem.

Here is my callback.php - might save you some time.It relies on the excellent wizz.cc.karotz-class and handles button-presses and "event finished"-messages. If yu don't want to use the wizz.cc class, call the api directly via "file_get_content"-function or else:


if (isset($_GET["karotz"])) {  // this is triggered if you call thisscript.php?karotz=1 from browser or phone
$APIKEY = "YOUR APIKEY";
$SECRET = "YOUR SECRET KEY";
$INSTALLID = "YOUR INSTALL ID";
$arr = array(
"installid" => $INSTALLID,
"apikey" => $APIKEY,
"once" => rand ( 9999999999999, 99999999999999 ),
"timestamp" => time());
$data = file_get_contents("http://api.karotz.com/api/karotz/start?" . sign($arr, $SECRET));
$voosMsg = simplexml_load_string($data);
$interactiveId = (string) $voosMsg->interactiveMode->interactiveId;
if (!(empty($interactiveId))) { // did we get an interactiveID?
session_id($interactiveId);
session_start();
$_SESSION['interactiveid'] = $interactiveId; // store interactiveID
} else {
logVoos("No interactiveID!");
exit(1);
}
}
elseif(isset($_GET["interactiveid"])) {   // this is triggered by the first call of the karotz-server (if you start the app via schedule or nanoz
session_id($_GET['interactiveid']);
session_start();
}
if (isset($_GET["karotz"]) || isset($_GET["interactiveid"])) { // First run
// Get the Feed 
getFeed();
//first callback start interactive mode
if (isset($_GET["interactiveid"])) $_SESSION['interactiveid'] = $_GET["interactiveid"]; // store interactiveID
include('../resource/karotz/wizz.cc_karotz_class.php');
$_karotz = new wizz_karotz($_SESSION['interactiveid'], false); # true for debug mode
$config = (object) ($_karotz->config()); // get the karotz-config
$title = 0;
$flag = false;
if (!isset($_GET['karotz'])) {
foreach ($config->params as $key=>$parameter) { // parse the value of title-option from config (only if called by kaotz.com)
if ($flag == true) $title = $parameter[0];
if ($parameter[0] == "title") $flag = true;
}
} else {
if (isset($_GET['title']) && ($_GET['title']==1)) $title = true; // if called by browser/client, check for title-config
}
// Set up the SESSION
$title_actions = array(
array("say"=>array("Dies sind die", "de", -1 , "calm")), 
array("say"=>array($_SESSION['title'], "de", -1, "calm"))
);
$actions = array(
array("led_light"=>array('0000FF')),
array("play"=>array($_SESSION['news_audio'])),
array("led_light"=>array('1100EE')),
array("say"=>array("Danke fürs Zuhören", "de", -1, "happy"))
);
if ($title == 1) $actions = array_merge($title_actions,$actions);  // user wants title? Add it to the queue
$actions = array_reverse($actions);
$_SESSION['actions'] = $actions; // store queue
$_SESSION['counter'] = count($actions)+1; // adjust counter for first action (see next line below)
$_karotz->led_light('FF00FF'); // start any action here - this is necessary to generate a correlationId for the next callback
session_write_close();
exit(0);
}
else {   // this will always be called after the first callback
$data = file_get_contents("php://input");
//posted event
try {
$voosMsg =simplexml_load_string($data);
$interactiveId = (string) $voosMsg->interactiveId;
session_id($interactiveId);
session_start();
include('../resource/karotz/wizz.cc_karotz_class.php');
if (isset($_SESSION['interactiveid'])) $_karotz = new wizz_karotz($_SESSION['interactiveid'], false); # true for debug mode
$code = (string) $voosMsg->event->code;
$corr = (string) $voosMsg->correlationId;
$type = (string) $voosMsg->buttonCallback->type;
if ((empty($corr) && empty($type)) || (empty($interactiveId))) exit(0); // drop callback if no correlationId given - this is VITAL!
if (!(empty($code))) {
if(($code == "TERMINATED") || ($code == "CANCELLED")) {
$_SESSION['counter'] = $_SESSION['counter']-1;    // advance to next event, if last one is finished
if ($_SESSION['counter'] != 0) {
$counter = 1;
foreach ($_SESSION['actions'] as $param) {
if ($counter == $_SESSION['counter']) {
$action = array_keys($param);
$parameter = array_values($param);
call_user_func_array(array($_karotz, $action[0]), $parameter[0]);
session_write_close();
exit(0);
} else {
$counter++;
}
}
} else {
cleanup($_karotz);
}
}
}
if (!(empty($type))) {
if ($type == "DOUBLE") { // doubleclick?
cleanup($_karotz); // quit 
} elseif ($type == "SIMPLE") {
// do nothing
}
}
}
catch (Exception $e) {
echo $h . 'Exception : ' .  $e->getMessage() . "\n";
}
}
function cleanup($_karotz) {
$_SESSION = array();
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params["path"],
$params["domain"], $params["secure"], $params["httponly"]
);
}
session_destroy();
$_karotz->quit();
exit(0);
}


I'm very interested in your Android-app, btw. If you need a tester.... :-)

Best wishes,

Marcus


Roarster

unread,
Apr 13, 2012, 6:50:30 AM4/13/12
to karo...@googlegroups.com
I think i've got it! The way in which my app differs to the mindscape one connection-wise is that mine only connects when it needs to send a command vs mindscape's always connected method. Soooo basically i can put a script on the callback url that simply closes any connections when it receives a terminated callback. I'll see if it works when i get the chance :) any of course you can test it! I need all the testers i can. It's currently already in the android market called "Swiss Army Carrot". That version only supports nabaztags but if you have one feel free to download ;) I'm planning on introducing karotz support in an update, when i get a stable version working with karotz support i'll post it for you here ;)

Marcus Gerards

unread,
Apr 13, 2012, 8:11:24 AM4/13/12
to karo...@googlegroups.com

On Friday, April 13, 2012 12:50:30 PM UTC+2, Roarster wrote:
I think i've got it! The way in which my app differs to the mindscape one connection-wise is that mine only connects when it needs to send a command vs mindscape's always connected method. Soooo basically i can put a script on the callback url that simply closes any connections when it receives a terminated callback. I'll see if it works when i get the chance :) any of course you can test it! I need all the testers i can. It's currently already in the android market called "Swiss Army Carrot". That version only supports nabaztags but if you have one feel free to download ;)

I've got two Nabz sitting here and torturing my employees, so I'll check it out :-) 
 
I'm planning on introducing karotz support in an update, when i get a stable version working with karotz support i'll post it for you here ;)

Looking forward to it! 

Shaigan

unread,
Apr 13, 2012, 10:03:23 AM4/13/12
to karo...@googlegroups.com
Some function calls are missing in the php script :

getFeed()
sign()
logVoos()

Please, what are those functions ?

Marcus Gerards

unread,
Apr 13, 2012, 12:56:09 PM4/13/12
to karo...@googlegroups.com
getFeed() loads the RSS-Feed of a German news radio, parses it and passes the title and the feed-URL to Karotz:

function getFeed() {
//Parse feed data
$feed = file_get_contents("http://www.dradio.de/rss/podcast/nachrichten/");
$xml = new SimpleXMLElement($feed);
$title = explode(",", (string) $xml->channel->item->title);   // grab the feed-title
$_SESSION['title'] = $title[0];
$regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
$input = $xml->channel->item->description;
if(preg_match_all("/$regexp/siU", $input, $matches)) {  // search for the feed-URL
$news_audio = $matches[2][0];
} else {
$url_error = TRUE;
}
$_SESSION['news_audio'] = $news_audio;
return 1;
}


sign() is needed for the call via SIGNED-method:

function sign($parameter, $secret){
$items = array();
foreach( $parameter as $key => $value){
array_push($items, urlencode($key)."=".urlencode($value));
}
asort($items);
$query = implode ( "&" , $items );
$iv = hash_hmac ( "sha1" , $query, $secret, true );
$signature = base64_encode($iv);
return $query."&signature=".urlencode($signature);
}


and finally logVoos(msg) just writes any passed msg to a textfile - useful for debugging 

function logVoos($msg) {
$h = fopen("log/received.txt", 'a') or exit ('cannot access log');
fwrite($h, "\n msg: " . $msg. "\n");
fclose($h);
return 1;
}
(assuming log/received.txt exists and is writeable by webserver/php)

Best wishes, 

Marcus

Shaigan

unread,
Apr 13, 2012, 1:21:52 PM4/13/12
to karo...@googlegroups.com
Thx you very much ;)

Shaigan

unread,
Apr 16, 2012, 11:47:42 AM4/16/12
to karo...@googlegroups.com
I'm sorry to be so noob, but I can't get i tto work without the wizz.cc class.
I'm trying to have only one script, with the objective to translate it into a lua script (to be included in a home automation box)

Could you please indicate by what I need to change the "$karotz->" classes calls ?

Thx a lot :)


Le vendredi 13 avril 2012 12:19:49 UTC+2, Marcus Gerards a écrit :

Genís Guàrdia Verdié

unread,
Apr 16, 2012, 1:03:34 PM4/16/12
to karo...@googlegroups.com
I have a question, is there any possibility that Karotz use cards RFID recorded by me?

2012/4/16 Shaigan <x.lassi...@gmail.com>

Marcus Gerards

unread,
Apr 18, 2012, 11:31:36 AM4/18/12
to karo...@googlegroups.com


On Monday, April 16, 2012 5:47:42 PM UTC+2, Shaigan wrote:
I'm sorry to be so noob, but I can't get i tto work without the wizz.cc class.
I'm trying to have only one script, with the objective to translate it into a lua script (to be included in a home automation box)

Could you please indicate by what I need to change the "$karotz->" classes calls ?


Just follow the REST-API on the karotz-LAB here - what you're searching for is about the only thing they documented well (but not without errors). The wizz.cc-class is just a wrapper to make things easier (to read).

Here is an example, replaces $_karotz->led_light('color');


I don't know how that's done with LUA, but you just have to request the URL, as described in the docs.

Best wishes,

Marcus

 

Shaigan

unread,
Apr 18, 2012, 11:48:55 AM4/18/12
to karo...@googlegroups.com
Thx for your help

blddk

unread,
May 15, 2012, 3:37:32 PM5/15/12
to karo...@googlegroups.com
I am trying to use this, but it keeps returning CANCELLED, instead of TERMINATED.

The problem is that CANCELLED is returned right away, as soon as TTS is started, and my server then closes the app again.

Any idea why this can be happening? I have tried ttl, ears, led, and config... only thing I can get to return TERMINATED after it is done, is the config command, and it only works once, next time I have to manually close the app, and it then got around a 30% chance of returning TERMINATED again.

Marcus Gerards

unread,
May 16, 2012, 4:16:05 AM5/16/12
to karo...@googlegroups.com


Am Dienstag, 15. Mai 2012 21:37:32 UTC+2 schrieb blddk:
I am trying to use this, but it keeps returning CANCELLED, instead of TERMINATED.

The problem is that CANCELLED is returned right away, as soon as TTS is started, and my server then closes the app again.


That has always been the case. However, until last thursday you just had to check if the message contained a correlationId, too. If not, you'd just drop the "empty" CANCELLED or TERMINATED messages and the script would run fine. This won't work anymore. I've mailed lab and support about this, but did not get any response. The servers only send a correlationID now if a multimedia file has been played all through. 

If you only use the multimedia function, you can check for the play and stop-events, though:

$multimedia = (string) $voosMsg->multimediaCallback->action;
if(($multimedia == "STOP"))  // issue next playback-command

But this won't help with "say", "Led" or "ears".

I must say I'm very disappointed with violet. After hours of figuring out how to run commands one after another, developing apps started to be fun. Then Violet suddenly breaks the API or changes it without documenting it. All the work was in vain! 

No support so far, you just get anonymous "we're investigating" messages which contain not even the sender's name. 

Best wishes,

Marcus




blddk

unread,
May 16, 2012, 10:05:43 AM5/16/12
to karo...@googlegroups.com
I am having problems with that multimedia stuff too... Because it does not play the last ½-1 second of the files. Even if I skip to close the app when receiving the STOP response.

Do I have to do more than just call "http://api.karotz.com/api/karotz/multimedia?action=play&url=" . urlencode($soundURL) . "&interactiveid=$interactiveid" ?

blddk

unread,
May 16, 2012, 10:23:15 AM5/16/12
to karo...@googlegroups.com
http://www.youtube.com/watch?v=dNfKrWEi8b8 

Just uploaded a video of it too.

Marcus Gerards

unread,
May 16, 2012, 1:29:17 PM5/16/12
to karo...@googlegroups.com

Maybe it's the following bug (from wiki.karotz.com):

"The end of the last piece of the mp3 playlist is truncated if the repeat mode is off. This is not the case when there is a repeat.

To play, play three short blasts in succession without repeat, then repeat with."


You could also post your source here.


Best wishes,


Marcus

blddk

unread,
May 16, 2012, 4:03:09 PM5/16/12
to karo...@googlegroups.com
This is starting to be a real mess...

Broken api, broken functions doing unexpected things, poor English documentation, and non responsive support...

Will try to see if I can get php to merge the files with a second of silence in the end.


This fix tells me to play the file 3 times without delay, then enable repeat???

Marcus Gerards

unread,
May 16, 2012, 5:07:08 PM5/16/12
to karo...@googlegroups.com


Am Mittwoch, 16. Mai 2012 22:03:09 UTC+2 schrieb blddk:
This is starting to be a real mess...

Broken api, broken functions doing unexpected things, poor English documentation, and non responsive support...

Will try to see if I can get php to merge the files with a second of silence in the end.


This fix tells me to play the file 3 times without delay, then enable repeat???

I think it means to play a short "sample of silence" three times. Maybe it doesn't refer to streaming playback at all, but usb-playback instead. I translated it from the french wiki using google translate - maybe the french guys here can help. ;-)

About the API - does anyone know who might respond at Violet? Are there known developers?

Reply all
Reply to author
Forward
0 new messages