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;
}
}
------------------------------------------------