This is an update to Kate Hartman's great PHONES & OBJECTS page.


PHONES & OBJECTS: 

establishing a connection between Asterisk and Networked Objects



object triggers phone call


This script is an example of what you might use for a networked object that is going to trigger a phone call. It is called "testcall.php"  and it lives in your "/home/NETID/public_html/" directory. That is where your PHP script should live as well. Once you have placed your script in that directory, you will need to change the group from "users" to "asterisk" in order for it to work properly. You can do this by using the "chgrp" command, like this:

chgrp asterisk testcall.php


Here is testcall.php:


-----------------

<?

ini_set('display_errors',"1");

error_reporting(E_ALL);


//include gencallfile function

function gencallfile($numbertocall, $context = "2127960961", $extension = "s", $vars = "")

{

$time = time();

$temp_dir = "";

$callfile = "call_" . $time . ".call";

$startcallfile = $temp_dir . $callfile;

$end_dir = "/var/spool/asterisk/outgoing/";

$endcallfile = $end_dir . $callfile;

$cfile = fopen($startcallfile,"w");

fwrite($cfile,"Channel: SIP/itp_jnctn/" . $numbertocall . "\n");

fwrite($cfile,"MaxRetries: 1\nRetryTime: 60\nWaitTime: 30\n");

fwrite($cfile,"Context: " . $context . "\n");

fwrite($cfile,"Extension: " . $extension . "\n");

if ($vars != "")

{

fwrite($cfile,"SetVar: " . $vars . "\n");

}

fclose($cfile);

chmod($startcallfile,0777);

rename($startcallfile,$endcallfile);

}



?> 


<html>

<body>


<?

//if the parameter 'phonenumber' is set 

if (isset($_GET['phonenumber']))

{

//place a call to that number using from this context and extension

gencallfile($_GET['phonenumber'], "testcall_php","s","1");

echo "bam! you made a phone call.";


}

?>

</body>

</html>

------------------



This script is setup up so the only parameter you pass in is the phone number to which you'd like the call to be placed. The first test is to trigger a phone call from your browser. You can give it a try with this one:

http://asterisk.itp.tsoa.nyu.edu/~NETID/testcall.php?phonenumber=10000000 (replace zeros with the phone number that you want to call and replace NETID with your net-id)


Once you know your call is working from the browser, you can move on to the Arduino/XPort setup. An Xport is a serial-to-ethernet device. You can find information about it and how to set it up on Tom Igoe's Networked Objects site. The Arduino hooked up to the Xport is basically able to mimic what we did when we triggered the phone call from the browser- it connects to the server and calls the PHP script, complete with the parameter. That part is fairly straightforward. The larger question is - what should actually trigger the phone call? It could be anything from the push of a button to sensor values determining that an event has happened in the physical world. For this example we are going to use a simple button, but the possibilities are endless. 


Arduino code:


--------------------------------------------


//OBJECT TRIGGERS PHONE CALL

//Using Xport to Connect to Asterisk


// a digital input is on port 12

int button = 12;


// a status light is on port 13

int ledPin = 2;


// limits the maximum number of calls

int callLimit = 3; // maximum number of attempted http connects to call

int calls = 0;  // holds the current number of attempted http connects 

int lastButtonVal = 0;//this holds the last value of the button


void setup () {

  pinMode(button, INPUT);

  pinMode(ledPin, OUTPUT);


  // start up the serial connection

  Serial.begin(9600);


  // blink the status LED

  blinkLED(ledPin, 5, 250);

}


void loop () {


  int buttonVal = digitalRead(button);


  if (buttonVal == 1 && lastButtonVal == 0 && calls < callLimit) {//if the button is pressed and wasn't pressed before and less than 3 calls have been made then...

    deviceConnect();//connect to server

    httpRequest(); //make phone call

    calls++;//add one to the count of the number of phone calls made

  }

  lastButtonVal = buttonVal;//store old button value

  delay(1000);//wait a sec


}


// this function blinks the an LED light as many times as requested

void blinkLED(int targetPin, int numBlinks, int blinkRate) {

  for (int i=0; i<numBlinks; i++) {

    digitalWrite(targetPin, HIGH);   // sets the LED on

    delay(blinkRate);                     // waits for a blinkRate milliseconds

    digitalWrite(targetPin, LOW);    // sets the LED off

    delay(blinkRate);

  }

}



void deviceConnect() {

  // server's IP address: 

  Serial.print("C128.122.151.44/80\n");

}



void httpRequest() {

  // Make HTTP GET request - trigger PHP script - replace zeros with phone #

  Serial.print("GET /~NETID/testcall.php?phonenumber=10000000000 HTTP/1.1\n"); 

  // server's name:

  Serial.print("HOST:asterisk.itp.tsoa.nyu.edu\n\n");

}


----------------------------------





phone controls object


In this example, Asterisk establishes a socket connection with Arduino via the Xport. This allows you to use the keys of the phone to control the output of the Arduino. 


The PHP script lives in your Asterisk AGI directory.


------------------------------------------


#!/usr/local/bin/php

<?PHP

require('/var/lib/asterisk/agi-bin/phpagi.php');

$agi = new AGI();

//open a socket to the Xport's IP address on port 10001, change this IP to the IP of your Xport

$fp = fsockopen("tcp://128.122.151.222", 10001, $errno, $errstr);

if (!$fp) {

   echo "ERROR: $errno - $errstr<br />\n";

   exit();

}

$continue = true;

while($continue)

{

$return = $agi->wait_for_digit(10000);


if ($return['result'] > 0) //if you press a button on the phone

{

$ascii = chr($return['result']); //convert that # to ASCII

fwrite($fp, $ascii); //send that through the socket to the Xport

$agi->say_number($ascii); //say the number aloud

}

else

{

$continue = false;

  fclose($fp); //if not, close to the socket


}

}

   fclose($fp);

/* End AGI Scripting */


?>

---------------------------------------------



The Xport will be on the other end, passively awaiting the socket connection. The Arduino code is as follows:



------------------------------------------------

//PHONE CONTROLS OBJECT

//Asterisk Connects to Arduino via Xport


/*

Connections:

Lantronix TX --> Arduino RX

Lantronix RX --> Arduino TX

Lantronix Reset --> Arduino pin 7

*/


#define disconnected 0

#define connected 1


// Defines for I/O pins:

#define connectedLED 2 // indicates when there's a TCP connection

#define gotdataLED 3 // Indicates that data has come in


#define oneLED 5

#define twoLED 6


#define deviceResetPin 7 // resets Lantronix Device


// variables:

char inByte=' '; // incoming byte from serial RX

int status = 0; // Lantronix device's connection status


void setup()

{

  // set all status LED pins and Lantronix device reset pin:

  pinMode(connectedLED, OUTPUT);

  pinMode(gotdataLED, OUTPUT);

  pinMode(deviceResetPin, OUTPUT);

  pinMode(oneLED,OUTPUT);

  pinMode(twoLED,OUTPUT);


  // start serial port, 9600 8-N-1:

  Serial.begin(9600);

  //reset Lantronix device:

  resetDevice();

}


void loop()

{

  stateCheck();

}


/*

  Take the Lantronix device's reset pin low to reset it

*/

void resetDevice()

{

  digitalWrite(deviceResetPin, LOW);

  delay(50);

  digitalWrite(deviceResetPin, HIGH);


  // pause to let Lantronix device boot up:

  delay(2000);

}


void stateCheck()

{

  switch (status)

  {

    case disconnected:

      digitalWrite(connectedLED,LOW);

      // read the serial port:

      if (Serial.available())

      {

        inByte = Serial.read();

        Serial.print(inByte);

        if (inByte == 'C')

        { // 'C' in ascii

          status = connected;

        }

      }

      digitalWrite(connectedLED,HIGH);

      break;

    case connected:

      if (Serial.available())

      {

        inByte = Serial.read();

        Serial.print((char)inByte);

        if (inByte == '1')

        {

          digitalWrite(oneLED,HIGH);

          digitalWrite(twoLED,LOW);

        }

        else if (inByte == '2')

        {

          digitalWrite(twoLED,HIGH);

          digitalWrite(oneLED,LOW);

        }

        else if (inByte > 65)

        {

           digitalWrite(oneLED,HIGH);

           digitalWrite(twoLED,HIGH);

        }

        else

        {

           digitalWrite(oneLED,LOW);

           digitalWrite(twoLED,LOW);

        }

      }

      break;

  }

}

------------------------------------------------