#!/usr/bin/php -q <?php /* Simple Alarm call center script. This script can by used as after script for Asterisks AlarmReceiver cmd. This script read saved events from asterisk alarm receiver. If the event is important (Alarm event) script create asterisks call file which make a call and play sound message to selected numbers. You can also receive formated events to email. Notes: For better results in communication you can try increase output gain on your ATA (default setting was -3) FXS Port Output Gain: +1 You must set all other regional settings to match your alarm !!! (FXS Port Impedance, Ring Frequency, Ring Voltage, ...) Other info for Asterisks AlarmReceiver cmd can be found here: http://www.voip-info.org/wiki/index.php?page=Asterisk+cmd+AlarmReceiver ------------------------------------------------------------------------------------------------ Example: alarmreceiver.conf [general] timestampformat = %a %b %d, %Y @ %H:%M:%S %Z eventcmd = /usr/local/bin/after_alarm_event.php eventspooldir = /var/spool/asterisk/alarm_events logindividualevents = yes fdtimeout = 2000 sdtimeout = 200 loudness = 8192 ------------------------------------------------------------------------------------------------ Example: sip.conf (pstn to sip part) [31] type=friend context=phones host=dynamic secret=******* callerid="Ademco Alarm" <31> dtmfmode=inband disallow=all allow=ulaw ------------------------------------------------------------------------------------------------ Example: extension.conf [internal] ;alarm receiver exten => 560,1,Verbose(1|Extension 560 - Alarm Receiver) exten => 560,n,Ringing() exten => 560,n,Wait(2) exten => 560,n,AlarmReceiver() exten => 560,n,Hangup() [alarmreport] exten => start,1,Answer() exten => start,n,Wait(1) exten => start,n,Playback(ha/alarm) exten => start,n,Wait(1) exten => start,n,Playback(ha/alarm) exten => start,n,Wait(1) exten => start,n,Playback(ha/alarm) exten => start,n,Wait(1) exten => start,n,Playback(ha/alarm) exten => start,n,Wait(1) exten => start,n,Playback(ha/alarm) exten => start,n,Wait(1) exten => start,n,Playback(ha/alarm) exten => start,n,Wait(1) exten => start,n,Playback(ha/alarm) exten => start,n,Wait(1) exten => start,n,Playback(vm-goodbye) exten => start,n,Hangup() ------------------------------------------------------------------------------------------------ Written by Uros Indihar <uros.indihar@alphito.si> Alphito d.o.o. Changelog 0.1 Initial release 0.2 1.12.1008 Added mail support License GNU GPL2. Warranty: None. Use at your own risk ! */ class ademcoEventParser { var $eventMap=array( 110 => "Fire Alarm", 121 => "Duress", 122 => "Alarm, 24-hour Silent", 123 => "Alarm, 24-hour Audible", 131 => "Alarm, Perimeter", 132 => "Alarm, Interior", 134 => "Alarm, Entry/Exit", 135 => "Alarm, Day/Night", 143 => "Alarm, Expansion Module", 146 => "Silent Burglary", 150 => "Alarm, 24-Hour Auxiliary", 301 => "AC Power", 302 => "Low System Battery/Battery Test Fail", 305 => "System Reset", 333 => "Trouble or Tamper Expansion Module", 351 => "Telco Line Fault", 353 => "Long Range Radio Trouble", 373 => "Fire Loop Trouble", 374 => "Exit Error Alarm", 380 => "Global Trouble, Trouble Day/Night", 381 => "RF Supervision Trouble", 383 => "RF Sensor Tamper", 384 => "RF Sensor Low Battery", 401 => "Disarmed, Armed AWAY (MAX), Armed AWAY", 406 => "Cancel by User", 407 => "Remote Arm/Disarm (Downloading)", 408 => "Quick Arm AWAY/MAX", 441 => "Disarmed/Armed STAY/INSTANT , Quick Arm STAY/INSTANT", 570 => "Bypass", 602 => "Periodic Test", 606 => "AAV to follow", 607 => "System Test", 623 => "Event Log 80% Full", 629 => "1-1/3 Day No Event", ); var $eventsDir="/var/spool/asterisk/alarm_events/"; var $eventPrefix="event-"; var $lastEventSave="last_received_event"; var $actionChannels=array( //ademco_id => array(channel1,channel2,...); "NNNN(ADEMCO_ID 1)"=>array( "SIP/NNNNNN (Asterisk channel)", "SIP/NNNNNN (Asterisk channel)", ), "NNNN(ADEMCO_ID 2)"=>array( "SIP/NNNNNN (Asterisk channel)", ), ); var $callFileDir="/var/spool/asterisk/outgoing/"; var $actionChannelsMail=array( //ademco_id => array(Email1=>Name1,Email2=>Name2,...); "NNNN(ADEMCO_ID 1)"=>array( "example@example.com"=>"My Name", "example1@example.com"=>"My Name1", ), "NNNN(ADEMCO_ID 2)"=>array( "example@example.com"=>"My Name", ), ); var $emailFromName="Ademco Alarm Report"; var $emailFrom="cron@alphito.si"; var $callerId="Alarm Report <NNNNNNNNNNNN>"; function setEventsDir($dir) { $this->eventsDir=$dir; } function getEventFiles() { $eventFiles=array(); $eventPrefixLen=strlen($this->eventPrefix); $dh = opendir($this->eventsDir); while (($file = readdir($dh)) !== false) { if (substr($file,0,$eventPrefixLen) == $this->eventPrefix) { $eventFiles[$file]=filemtime($this->eventsDir.$file); } } asort($eventFiles); closedir($dh); $this->eventFiles=$eventFiles; } function loop() { foreach ($this->eventFiles as $file => $mtime) { $data=$this->parse($file); foreach ($data["events"] as $event) { //echo $event; $e=$this->parseEvent($event); if ($this->getSavedEvent() == $event) { //event is duplicated to last event $this->log($data["metadata"],$event,"Duplicated event",$e); } else { $this->saveEvent($event); $this->log($data["metadata"],$event,"New event",$e); $this->action($e,$data["metadata"],$event); } } //print_r($data); //remove file unlink($this->eventsDir.$file); } } function action($e,$metadata,$event) { if(intval($e["e"]) < 200) { //do action on alarm events $this->log($metadata,$event,"Starting action",$e); foreach ($this->actionChannels[$e["id"]] as $callChannel) { $this->createCallFile($callChannel); } } //send email report if (is_array($this->actionChannelsMail[$e["id"]])) { $msg ="Ademco alarm report.\n\n"; $msg.="Logged event at ".date("d.m.Y H:i:s",time()).".\n\n"; $msg."Event data:\n\n"; $msg.=implode(", ",$metadata)."\n"; $msg.=$event."\n"; $msg.=implode(", ",$e)."\n"; $msg.=$this->eventMap[$e["e"]]."\n\n"; $subject ="[ ALARM ] ".$this->eventMap[$e["e"]]; foreach ($this->actionChannelsMail[$e["id"]] as $email => $name) { $this->sendMail($subject,$name,$email,$this->emailFromName,$this->emailFrom,$msg); } } } function createCallFile($channel) { $callFile ="Channel: ".$channel."\n"; $callFile.="CallerID: ".$this->callerId."\n"; $callFile.="MaxRetries: 10\n"; $callFile.="RetryTime: 60\n"; $callFile.="WaitTime: 30\n"; $callFile.="Context: alarmreport\n"; $callFile.="Extension: start\n"; $callFile.="Priority: 1\n"; file_put_contents($this->callFileDir.uniqid("alarm").".call",$callFile); } function getSavedEvent () { $lastEvent=@file_get_contents($this->eventsDir.$this->lastEventSave); return $lastEvent; } function saveEvent($event) { file_put_contents($this->eventsDir.$this->lastEventSave,$event); } function parseEvent($event) { $e=array( "id" => substr($event,0,4), "q" => substr($event,4,3), "e" => substr($event,7,3), "z" => substr($event,10), ); //print_r($e); return($e); } function log($metadata,$event,$string,$e) { syslog(LOG_NOTICE,implode(", ",$metadata).", ".$event.", ".$string.", ".implode(", ",$e).", ".$this->eventMap[$e["e"]]); } function parse($file) { $fp=fopen($this->eventsDir.$file,"r"); $section=""; $data=array(); while (!feof($fp)) { $line = trim(fgets($fp,4096)); if (substr($line,0,1) == "[") { //new section started $section=substr($line,1,-1); $data[$section]=array(); } elseif (strlen($section) > 0) { //we are in section switch ($section) { case "metadata": if (strlen($line) > 0) { //dont include empty lines list($key,$val)=explode("=",$line); //echo $key."->".$val."\n"; $data[$section][trim($key)]=trim($val); } break; case "events": if (strlen($line) > 0) { $data[$section][]=trim($line); } break; } } //echo $line."\n"; } fclose($fp); return $data; } function sendMail($subject,$tostr,$toemail,$fromstr,$fromemail,$msg) { $from = '"'; $from.=$this->encode($fromstr); $from.= '"'; $from.="<".$fromemail.">"; $to = '"'; $to.=$this->encode($tostr); $to.= '"'; $to.="<".$toemail.">"; //$msubject=$this->encode($subject); $msubject=$subject; $headers = "MIME-Version: 1.0\n"; $headers .= "Content-type: text/plain; charset=utf-8\n"; $headers .= "From: ".$from."\n"; return mail($to, $msubject, $msg, $headers); } function encode($in_str, $charset="UTF-8") { $out_str = $in_str; if ($out_str && $charset) { $end = "?="; $start = "=?" . $charset . "?B?"; $spacer = $end . "\n " . $start; $length = 75 - strlen($start) - strlen($end); $length = floor($length/2) * 2; $out_str = base64_encode($out_str); $out_str = chunk_split($out_str, $length, $spacer); $spacer = preg_quote($spacer); $out_str = preg_replace("/" . $spacer . "$/", "", $out_str); $out_str = $start . $out_str . $end; } return $out_str; } } $aep=new ademcoEventParser(); $aep->getEventFiles(); $aep->loop(); ?>