Asterisk IVR

From XAP Automation
Jump to: navigation, search

Asteriskis a "digital PBX" that is used to integrate telephony equipment with traditional analog PSTN and more recent VoIP lines.

The Asterisk xAP Connector (axc) provides a gateway between Asterisk and xAP-enabled devices. axc v0.6 introduced support for xAP-enabled IVR menus so that Asterisk can be used to interact to control home functions (e.g., turn lights on/off) and/or obtain information that about the home environment (e.g., what is the kitchen temperature). This capability fully integrates with xAP Four (and soon Misterhouse).

Asterisk IVR menus must be implemented via "dial-plans" which describe the menu structure and the actions to be taken given a user's choice (e.g., "press 1").

The following Asterisk dial plan is implemented in Asterisk Extension Language (AEL). It is compatible with recent Asterisk releases and can be added to your existing extensions.ael (typically located in /etc/asterisk).

// global var declarations; if you already have a section
//   then specify TTS there.  TTS set to cepstral is known to work
//   *if* you have the Perl Asterisk library loaded and the cepstral.agi
//   added to your AGI dir
//   Possible values for TTS are cepstral, flite, festival, swift
// IMPORTANT: Do NOT embed spaces in the assignment
globals {
   TTS=cepstral;
};
// the xapcmd handles the cmd request by setting a special variable
// that axc looks for and then looks for axc's response
macro xapcmd(cmd, curexten) {
   set(xapresponse="");
   set(maxcount=5);
   if ("${curexten}" != "") {
      set(last_exten=${curexten});
   };
   NoOp(xapsend:${cmd});
START:
   Wait(1);
   if ("${xapresponse}" != "") {
      &speak(${xapresponse},"");
      set(xapresponse="");
      return;
   } else {
      set(maxcount=${maxount}-1);
      if ("${maxcount}" != "0") {
         goto START;
      } else {
         return;
      };
   };
};
// "wrapper" for TTS - depends on global var: TTS to select the engine
//    cepstral.agi is an AGI script that uses the cepstral theta/swift TTS engine
//    escapedigits can be optionally included to force termination
macro speak(text,escapedigits) {
   NoOp(TTS=${TTS});
   if ("${TTS}" = "cepstral") {
      agi(cepstral.agi,${text},${escapedigits});
   } else if ("${TTS}" = "festival") {
      Festival(${text},${escapedigits});
   } else if ("${TTS}" = "swift") {
      Swift(${text});
   } else if ("${TTS}" = "flite") {
      flite(${text});
   };
};
// house-attendant is a possible entry point for home automation
// If you specify your initial contexts within extensions.conf 
// then add something like the following to your default or
// corresponding context to associate the attendant w/ dialing 
// the operator:
//
// exten => 0,1,Goto(house-attendant, s, 1)
context house-attendant {
   s => {
      Wait(1);
      Answer();
      TIMEOUT(digit)=7;
      TIMEOUT(response)=10;
// set escape digits to be the chars that are allowed to be pressed to
// interrupt speaking
      set(escdig=12*);
      Wait(1);
greeting:
      &speak(welcome to the house attendant,${escdig});
menu:
      &speak(press 1 for current time,${escdig});
      &speak(press 2 for local weather,${escdig});	
// specify a timeout so that the user comes back to the menu if no selection  made
      WaitExten(5);
   };
// each numeric extension is the "handler" for the xap command
   1 => { 
      &xapcmd(what time is it,1); 
      goto s|menu; 
   };
   2 => { 
      &xapcmd(what is the weather like,2); 
      goto s|menu;
   };
   * => {
      if ("${last_exten}" != "") {
         goto ${last_exten}|1;
      } else {
         goto s|menu;
      };
   };
   o => goto s|menu;
   # => {
      Playback(goodbye);
      Hangup();
   };
   t => goto s|menu;
   i => {
      Playback(invalid);
      goto s|menu;
   };
};

For those users that don't want to use AEL as the dial-plan logic, the point of "entry" into axc to initiate a command is to invoke a NoOp command with an argument of "xapsend:<cmd>" (w/o the quotes) where <cmd> is the command to be sent (do not embed spaces between xapsend: and <cmd>). In addition, since axc will deposit the response into the asterisk channel variable named "xapresponse", it is essential that xapresponse be initialized to "" (<emptystring>) before the NoOp is called.

Since xAP is an asynchronous protocol, a strategy of waiting with a timeout will be required. During this wait w/ timeout (possibly looping as show above), query the channel variable "xapresponse".