#!/usr/bin/php -q 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 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 "; 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(); ?>