Updated to KH 3.3 and overhaul

This commit is contained in:
Deon George 2013-10-17 15:15:13 +11:00
parent 217fa94867
commit 57389e462f
26 changed files with 695 additions and 459 deletions

View File

@ -17,5 +17,5 @@ RewriteRule ^(?:application|modules|includes/kohana)\b.* index.php/$0 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all other URLs to kh.php/URL
# Rewrite all other URLs to index.php/URL
RewriteRule .* index.php/$0 [PT]

View File

@ -3,48 +3,56 @@
// -- Environment setup --------------------------------------------------------
// Load the core Kohana class
require SYSPATH.'classes/kohana/core'.EXT;
require SYSPATH.'classes/Kohana/Core'.EXT;
if (is_file(APPPATH.'classes/kohana'.EXT))
if (is_file(APPPATH.'classes/Kohana'.EXT))
{
// Application extends the core
require APPPATH.'classes/kohana'.EXT;
require APPPATH.'classes/Kohana'.EXT;
}
else
{
// Load empty core extension
require SYSPATH.'classes/kohana'.EXT;
require SYSPATH.'classes/Kohana'.EXT;
}
/**
* Set the default time zone.
*
* @see http://kohanaframework.org/guide/using.configuration
* @see http://php.net/timezones
* @link http://kohanaframework.org/guide/using.configuration
* @link http://www.php.net/manual/timezones
*/
date_default_timezone_set('Australia/Melbourne');
/**
* Set the default locale.
*
* @see http://kohanaframework.org/guide/using.configuration
* @see http://php.net/setlocale
* @link http://kohanaframework.org/guide/using.configuration
* @link http://www.php.net/manual/function.setlocale
*/
setlocale(LC_ALL, 'en_US.utf-8');
/**
* Enable the Kohana auto-loader.
*
* @see http://kohanaframework.org/guide/using.autoloading
* @see http://php.net/spl_autoload_register
* @link http://kohanaframework.org/guide/using.autoloading
* @link http://www.php.net/manual/function.spl-autoload-register
*/
spl_autoload_register(array('Kohana', 'auto_load'));
/**
* Optionally, you can enable a compatibility auto-loader for use with
* older modules that have not been updated for PSR-0.
*
* It is recommended to not enable this unless absolutely necessary.
*/
//spl_autoload_register(array('Kohana', 'auto_load_lowercase'));
/**
* Enable the Kohana auto-loader for unserialization.
*
* @see http://php.net/spl_autoload_call
* @see http://php.net/manual/var.configuration.php#unserialize-callback-func
* @link http://www.php.net/manual/function.spl-autoload-call
* @link http://www.php.net/manual/var.configuration#unserialize-callback-func
*/
ini_set('unserialize_callback_func', 'spl_autoload_call');
@ -75,15 +83,16 @@ if (isset($_SERVER['KOHANA_ENV']))
* - string index_file name of your index file, usually "index.php" index.php
* - string charset internal character set used for input and output utf-8
* - string cache_dir set the internal cache directory APPPATH/cache
* - integer cache_life lifetime, in seconds, of items cached 60
* - boolean errors enable or disable error handling TRUE
* - boolean profile enable or disable internal profiling TRUE
* - boolean caching enable or disable internal caching FALSE
* - boolean expose set the X-Powered-By header FALSE
*/
Kohana::init(array(
'base_url' => '',
'index_file' => '',
'caching' => TRUE,
'cache_dir' => '/dev/shm/halmon',
'index_file' => '',
));
/**
@ -105,10 +114,11 @@ Kohana::modules(array(
// 'codebench' => SMDPATH.'codebench', // Benchmarking tool
'database' => SMDPATH.'database', // Database access
// 'image' => SMDPATH.'image', // Image manipulation
'khemail' => SMDPATH.'khemail', // Email module for Kohana 3 PHP Framework
'minion' => SMDPATH.'minion', // CLI Tasks
'orm' => SMDPATH.'orm', // Object Relationship Mapping
// 'unittest' => SMDPATH.'unittest', // Unit testing
'userguide' => SMDPATH.'userguide', // User guide and API documentation
'email' => SMDPATH.'email', // Email Module
));
/**
@ -116,24 +126,34 @@ Kohana::modules(array(
*/
Route::set('sections', '<directory>/<controller>(/<action>(/<id>(/<sid>)))',
array(
'directory' => '('.implode('|',Kohana::config('config.method_directory')).')'
'directory' => '('.implode('|',array_values(URL::$method_directory)).')'
))
->defaults(array(
'action' => 'index',
));
// Static file serving (CSS, JS, images)
Route::set('default/media', 'media(/<file>)', array('file' => '.+'))
->defaults(array(
'controller' => 'welcome',
'action' => 'media',
'file' => NULL,
'controller' => 'media',
'action' => 'get',
));
/**
* Set the routes. Each route must have a minimum of a name, a URI and a set of
* defaults for the URI.
*/
Route::set('default', '(<controller>(/<action>(/<id>)))', array('id' => '[a-zA-Z0-9_.-]+'))
Route::set('default', '(<controller>(/<action>(/<id>)))', array('id'=>'[a-zA-Z0-9_.-]+'))
->defaults(array(
'controller' => 'welcome',
'action' => 'index',
));
/**
* If APC is enabled, and we need to clear the cache
*/
if (file_exists(APPPATH.'cache/CLEAR_APC_CACHE') AND function_exists('apc_clear_cache') AND (PHP_SAPI !== 'cli')) {
if (! apc_clear_cache() OR ! unlink(APPPATH.'cache/CLEAR_APC_CACHE'))
throw new Kohana_Exception('Unable to clear the APC cache.');
}
?>

View File

@ -0,0 +1,154 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Handles incoming events
*
* @package HAlMon
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Event {
private $_caller = NULL;
private $_callername = NULL;
private $_events = array('protocol'=>array(),'orm'=>array());
private $_timestamp = NULL;
public function __construct($file) {
if (! file_exists($file))
throw new Kohana_Exception('File doesnt exist (:file)',array(':file'=>$file));
$this->process(file_get_contents($file));
}
public function __toString() {
return (string)sprintf('%s %s',join('|',$this->_events['protocol']),date('d-m-Y H:i:s',$this->_timestamp));
}
/**
* Check that our Event is valid
*/
public function check() {
return $this->_caller AND $this->_timestamp AND $this->_events['protocol'];
}
private function process($content) {
$meta = $event = FALSE;
$et = NULL;
$good = TRUE;
$events = array();
foreach (explode("\n",$content) as $line) {
// Ignore out blank lines
if (! trim($line))
continue;
if (preg_match('/^\[metadata\]/',$line)) {
$meta = TRUE;
$event = FALSE;
continue;
} elseif (preg_match('/^\[events\]/',$line)) {
$meta = FALSE;
$event = TRUE;
continue;
}
if ($meta) {
list ($k,$v) = explode('=',$line,2);
switch ($k) {
case 'PROTOCOL':
switch ($v) {
case 'ADEMCO_CONTACT_ID':
$protocol = 'Protocol_ContactID';
break;
default:
throw new Kohana_Exception('Unknown protocol :protocol',array(':protocol'=>$v));
}
break;
case 'CALLINGFROM':
$this->_caller = $v;
break;
case 'CALLERNAME':
$this->_callername = $v;
break;
case 'TIMESTAMP':
$this->_timestamp = $v;
break;
default:
printf('Extra data in event file - meta section (%s)',$line);
}
} elseif ($event) {
$x = new $protocol($line);
if ($x->event())
array_push($this->_events['protocol'],$x);
}
}
}
public function save() {
$result = FALSE;
foreach ($this->_events['protocol'] as $id => $po) {
$eo = ORM::factory('Event');
$eo->values(array(
'alarmevent'=>$po,
'datetime'=>$this->_timestamp,
'account_id'=>ORM::factory('Account',array('alarmphone'=>$this->_caller,'siteid'=>$po->accnum())),
'protocol'=>$po->protocol(),
));
// @todo With this logic and multiple events, if 1 event doesnt save, we'll loose it.
if ($eo->save() AND ! $result)
$result = TRUE;
$this->_events['orm'][$id] = $eo;
}
return $result;
}
public function trigger() {
// Work through each of the account triggers
foreach ($this->_events['orm'] as $id => $orm) {
$contacts = array();
foreach ($orm->account_id->trigger->find_all() as $to) {
if (! in_array($to->contact->id,$contacts) AND (is_null($to->alarm) OR $to->alarm == $this->_events['protocol'][$id]->etype())) {
// Get details of the event.
$po = $orm->account_id->model->plugin($this->_events['protocol'][$id],$orm->account_id);
if ($to->email) {
$e = Email::connect();
$sm = Swift_Message::newInstance();
$sm->setSubject('Notice from your alarm');
$sm->setBody(sprintf('Event ID: %s, Message: %s',$orm->id,(string)$po));
$sm->setTo($to->contact->email);
$sm->setFrom('noreply@leenooks.net');
$e->send($sm);
}
if ($to->sms) {
}
// We dont need to process any more triggers to the same account.
array_push($contacts,$to->contact->id);
}
}
}
}
}
?>

View File

@ -1,9 +1,9 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Our Account Model
*
* @package HAM
* @subpackage Accounts
* @package HAlMon
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
@ -14,7 +14,10 @@ class Model_Account extends ORM {
'model'=>array('foreign_key'=>'id'),
);
protected $_has_many = array(
'contact'=>array('far_key'=>'id'),
'trigger'=>array('far_key'=>'id'),
'paneluser'=>array('model'=>'PanelUser','far_key'=>'id'),
'panelzone'=>array('model'=>'PanelZone','far_key'=>'id'),
);
}
?>

View File

@ -2,8 +2,7 @@
/**
*
* @package HAM
* @subpackage Contacts
* @package HAlMon
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George

View File

@ -1,9 +1,9 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This Model manages our events as they are received
*
* @package HAM
* @subpackage Events
* @package HAlMon
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George

View File

@ -0,0 +1,26 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Panel Models
*
* @package HAlMon
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Model extends ORM {
protected $_has_many = array(
'alarm'=>array('far_key'=>'id'),
);
public function plugin(Protocol $eo,Model $ao) {
$x = 'Panel_'.$this->model;
if (class_exists($x))
return new $x($eo,$ao);
else
throw new Kohana_Exception('Unknown Panel :panel',array(':panel'=>$this->model));
}
}
?>

View File

@ -1,14 +1,14 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Alarm Panel Users
*
* @package HAM
* @subpackage Alarms
* @package HAlMon
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Alarm extends ORM {
class Model_PanelUser extends ORM {
}
?>

View File

@ -1,17 +1,14 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Alarm Panel Zones
*
* @package HAM
* @subpackage Models
* @package HAlMon
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Model extends ORM {
protected $_has_many = array(
'alarm'=>array('far_key'=>'id'),
);
class Model_PanelZone extends ORM {
}
?>

View File

@ -1,9 +1,9 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Customer Trigger notifications
*
* @package HAM
* @subpackage Trigger
* @package HAlMon
* @category Models
* @author Deon George
* @copyright (c) 2010 Deon George
@ -13,9 +13,5 @@ class Model_Trigger extends ORM {
protected $_has_one = array(
'contact'=>array('foreign_key'=>'id'),
);
public function trigger($code) {
return $this->where('alarm','=',$code)->or_where('alarm','=',null)->find();
}
}
?>

View File

@ -3,8 +3,8 @@
/**
* This class overrides Kohana's ORM
*
* @package lnApp/Modifications
* @category Classes
* @package HAlMon
* @category Modifications
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
@ -17,25 +17,6 @@ class ORM extends Kohana_ORM {
// Our filters used to display values in a friendly format
protected $_display_filters = array();
// Override check() so that it doesnt throw an exception.
// @todo Need to figure out how to show the items that fail validation
final public function check(Validation $extra_validation = NULL) {
// Determine if any external validation failed
$extra_errors = ($extra_validation AND ! $extra_validation->check());
// Always build a new validation object
$this->_validation();
$array = $this->_validation;
if (($this->_valid = $array->check()) === FALSE OR $extra_errors)
{
return FALSE;
}
return $this;
}
/**
* Format fields for display purposes
*

View File

@ -3,19 +3,21 @@
/**
* This class provides the base for Alarm Panel models
*
* @package HAM
* @package HAlMon
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
abstract class Panel {
protected $events = array();
protected $_ao = NULL;
protected $_eo = NULL;
public function __construct(array $events) {
$this->events = $events;
public function __construct(Protocol $eo,Model $ao) {
$this->_ao = $ao;
$this->_eo = $eo;
}
abstract public function trigger();
abstract public function __toString();
}
?>

View File

@ -0,0 +1,177 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class looks after Ness D8/Clipsal panel events
*
* @package HAlMon
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Panel_NessD8 extends Panel {
public function __toString() {
try {
return ($this->_eo->type() !== '18') ? 'Unkown Alarm: '.$this->_eo->event() : $this->event();
} catch (exception $e) {
return $e->getMessage();
}
}
private function area() {
$x = $this->_ao->panelzone->where('zoneid','=',$this->_eo->area())->find();
return $x->loaded() ? $x->description : 'Area '.$this->_eo->area();
}
public function event() {
switch ($this->_eo->etype()) {
// Medical
case 100:
return (($this->_eo->equal() == 1) AND ($this->_eo->area() == '01') AND ($this->_eo->info() == '033')) ? 'Medical Alarm' : 'Unknown Alarm '.$this->_eo->etype();
// Fire
case 110:
return (($this->_eo->equal() == 1) AND ($this->_eo->area() == '01') AND ($this->_eo->info() == '034')) ? 'Fire Alarm' : 'Unknown Alarm '.$this->_eo->etype();
// Panic
case 120:
switch ($this->_eo->info()) {
case '031': return ($this->_eo->area() == '01') ? 'Keyswitch Panic' : 'Unknown Panic Alarm '.$this->_eo->area();
case '032': return ($this->_eo->area() == '01') ? 'Keypad Panic' : 'Unknown Panic Alarm '.$this->_eo->area();
default: return ($this->_eo->area() == '01') ? 'Radio Key Panic: '.$this->_eo->info() : 'Unknown Panic Alarm '.$this->_eo->area();
}
// Duress Alarm
case 121:
return (($this->_eo->equal() == 1) AND ($this->_eo->area() == '01') AND ($this->_eo->info() == '030')) ? 'Duress Alaram' : 'Unknown Alarm '.$this->_eo->etype();
// Alarm
case 130:
switch ($this->_eo->equal()) {
case 1: $action = 'Alarm'; break;
case 3: $action = 'Reset'; break;
default: $action = 'Unknown';
}
return sprintf('Alarm %s (Area: %s) (Zone: %s)',$action,$this->area(),$this->zone());
// Mains Fail
case 301:
return (($this->_eo->equal() == 1) AND ($this->_eo->area() == '01') AND ($this->_eo->info() == '050')) ? 'Mains Fail' : 'Unknown Alarm '.$this->_eo->etype();
// Exit Installer Mode
case 306:
return (($this->_eo->equal() == 1) AND ($this->_eo->area() == '01') AND ($this->_eo->info() == '035')) ? 'Exit Install Mode' : 'Unknown Alarm '.$this->_eo->etype();
// Tamper
case 307:
switch ($this->_eo->equal()) {
case 1: $action = 'Alarm'; break;
case 3: $action = 'Reset'; break;
default: $action = 'Unknown';
}
switch ($this->_eo->info()) {
case '040': return ($this->_eo->area() == '01') ? sprintf('External Tamper %s',$action) : 'Unknown Tamper Alarm '.$this->_eo->area();
case '041': return ($this->_eo->area() == '01') ? sprintf('Internal Tamper %s',$action) : 'Unknown Tamper Alarm '.$this->_eo->area();
case '042': return ($this->_eo->area() == '01') ? sprintf('keypad Tamper %s',$action) : 'Unknown Tamper Alarm '.$this->_eo->area();
default: return 'Unknown Tamper Alarm '.$this->_eo->info();
}
// Panel Battery Fail
case 309:
return (($this->_eo->equal() == 1) AND ($this->_eo->area() == '01') AND ($this->_eo->info() == '051')) ? 'Panel Battery Fail' : 'Unknown Alarm '.$this->_eo->etype();
// Auto Exclude
case 380:
switch ($this->_eo->equal()) {
case 1: $action = 'Start'; break;
case 3: $action = 'Stop'; break;
default: $action = 'Unknown';
}
return sprintf('Auto Exclude %s (Area: %s) (Zone: %s)',$action,$this->area(),$this->zone());
// Radio Sensor Supervision
case 381:
switch ($this->_eo->equal()) {
case 1: $action = 'Start'; break;
case 3: $action = 'Stop'; break;
default: $action = 'Unknown';
}
return sprintf('Radio Sensor Supervision %s (Zone: %s)',$action,$this->_eo->info());
// Radio Sensor Tamper
case 383:
switch ($this->_eo->equal()) {
case 1: $action = 'Start'; break;
case 3: $action = 'Stop'; break;
default: $action = 'Unknown';
}
return sprintf('Radio Sensor Tamper %s (Zone: %s)',$action,$this->_eo->info());
// Radio Sensor Low Battery
case 384:
switch ($this->_eo->equal()) {
case 1: $action = 'Start'; break;
case 3: $action = 'Stop'; break;
default: $action = 'Unknown';
}
return sprintf('Radio Sensor Low Battery %s (Zone: %s)',$action,$this->_eo->info());
// Arm/Disarm Call
case 402:
switch ($this->_eo->equal()) {
case 1: $action = 'Disarmed'; break;
case 3: $action = 'Armed'; break;
default: $action = 'Unknown';
}
return sprintf('Panel %s (Area: %s) (By: %s)',$action,$this->area(),$this->user());
// Force Arm/Disarm Call
case 406:
switch ($this->_eo->equal()) {
case 1: $action = 'Disarmed'; break;
case 3: $action = 'Armed'; break;
default: $action = 'Unknown';
}
return sprintf('Force Panel %s (Area: %s) (By: %s)',$action,$this->area(),$this->user());
// Manual Exclude
case 573:
switch ($this->_eo->equal()) {
case 1: $action = 'Start'; break;
case 3: $action = 'Stop'; break;
default: $action = 'Unknown';
}
return sprintf('Manual Exclude %s (Area: %s) (Zone: %s)',$action,$this->area(),$this->zone());
// Test Call
case 602:
return (($this->_eo->equal() == 1) AND ($this->_eo->area() == '01') AND ($this->_eo->info() == '063')) ? 'Test Call' : 'Unknown Alarm '.$this->_eo->etype();
default:
return 'Unkown Event Code: '.$this->_eo->etype();
}
}
public function user() {
if ($this->_eo->info()==58)
Return 'Short Cut';
$x = $this->_ao->paneluser->where('userid','=',$this->_eo->info())->find();
return $x->loaded() ? $x->username : 'User '.$this->_eo->info();
}
public function zone() {
$x = $this->_ao->panelzone->where('zoneid','=',$this->_eo->info())->find();
return $x->loaded() ? $x->username : 'Zone '.$this->_eo->info();
}
}
?>

View File

@ -0,0 +1,35 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
const PROTOCOL_CONTACTID=1;
/**
* This class is handling Events
*
* @package HAlMon
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
abstract class Protocol {
// Raw event ID
protected $_id = NULL;
protected $_protocol = NULL;
public function __construct($event) {
$this->_id = $this->check($event) ? $event : NULL;
}
public function __toString() {
return (string)$this->event();
}
public function event() {
return $this->_id;
}
public function protocol() {
return $this->_protocol;
}
}
?>

View File

@ -0,0 +1,78 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is handling Ademco Contact ID Events
*
* @package HAlMon
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Protocol_ContactID extends Protocol {
protected $_protocol = PROTOCOL_CONTACTID;
private $_checksum_map = array(
'0'=>10,
'1'=>1,
'2'=>2,
'3'=>3,
'4'=>4,
'5'=>5,
'6'=>6,
'7'=>7,
'8'=>8,
'9'=>9,
'*'=>11,
'#'=>12,
'A'=>13,
'B'=>14,
'C'=>15,
);
public function accnum() {
return substr($this->_id,0,4);
}
public function area() {
return substr($this->_id,10,2);
}
// Check that this event is valid
public function check($id) {
if (strlen($id) != 16)
return FALSE;
// Our checksum should be mod15
$c = $t = 0;
while ($c<strlen($id))
$t += $this->_checksum_map[substr($id,$c++,1)];
return ($t%15 === 0) ? TRUE : FALSE;
}
public function checksum() {
return substr($this->_id,15,1);
}
public function equal() {
return substr($this->_id,6,1);
}
public function etype() {
return substr($this->_id,7,3);
}
public function info() {
return substr($this->_id,12,3);
}
/**
* Message Type
* @note This is typically always 18
*/
public function type() {
return substr($this->_id,4,2);
}
}
?>

View File

@ -0,0 +1,44 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* HomeALarmMONitor Receive an Event
*
* @package HAlMon
* @category Tasks
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Task_Event_Load extends Minion_Task {
protected $_options = array(
'file'=>NULL,
'verbose'=>FALSE,
);
protected function _execute(array $params) {
if (! $params['file'])
throw new Kohana_Exception('--file not supplied');
$eo = new Event($params['file']);
if (! $eo->save()) {
if (! Kohana::$config->load('debug')->test_mode)
rename($params['file'],$params['file'].'.bad');
echo 'Bad Event File: '.$params['file'];
die(1);
}
if (! Kohana::$config->load('debug')->test_mode) {
if (Kohana::$config->load('config')->event_file_keep)
rename($params['file'],$params['file'].'.processed');
else
unlink($params['file']);
}
$eo->trigger();
printf("Processed event(s) %s\n",$eo);
}
}
?>

View File

@ -0,0 +1,72 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class overrides Kohana's URL
*
* @package HAlMon
* @category Modifications
* @author Deon George
* @copyright (c) 2009-2013 HAlMon
* @license http://dev.leenooks.net/license.html
*/
class URL extends Kohana_URL {
// Our method paths for different functions
public static $method_directory = array(
'admin'=>'a',
'user'=>'u',
);
public static function admin_url() {
return (Request::current() AND ((Auth::instance()->logged_in() AND ! empty(URL::$method_directory[strtolower(Request::current()->directory())])) OR in_array(strtolower(Request::current()->controller()),array('login','oauth'))));
}
/**
* Function to reveal the real directory for a URL
*/
public static function dir($dir) {
// Quick check if we can do something here
if (! in_array(strtolower($dir),URL::$method_directory))
return $dir;
// OK, we can, find it.
foreach (URL::$method_directory as $k=>$v)
if (strtolower($dir) == $v)
return ucfirst($k);
// If we get here, we didnt have anything.
return $dir;
}
/**
* Wrapper to provide a URL::site() link based on function
*/
public static function link($dir,$src,$site=FALSE) {
if (! $dir)
return $src;
if (! array_key_exists($dir,URL::$method_directory))
throw new Kohana_Exception('Unknown directory :dir for :src',array(':dir'=>$dir,':src'=>$src));
$x = URL::$method_directory[$dir].'/'.$src;
return $site ? URL::site($x) : $x;
}
public static function navbar() {
$result = array();
foreach (array_reverse(static::$method_directory) as $k=>$v)
switch ($k) {
case 'admin': $result[$k] = array('name'=>'Administrator','icon'=>'icon-globe');
break;
case 'user': $result[$k] = array('name'=>Auth::instance()->get_user()->name(),'icon'=>'icon-user');
break;
default: $result[$k] = array('name'=>$k,'icon'=>'icon-question-sign');
}
return $result;
}
}
?>

View File

@ -1,100 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is handling Ademco Contact ID Events
*
* @package HAM
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class ContactID {
// Raw event ID
private $id = '';
private $acct;
private $sub;
private $qualifier;
private $type;
private $area;
private $alarm;
private $checksum;
private $datetime;
public function event($id,$dt,$cf='',$cn='') {
// @todo This shouldnt stop program execution, rather it should generate an email to an admin
if (! $this->check($id))
throw new Kohana_Exception('ContactID event :event is not valid',array(':event'=>$id));
// Process event trigger
$this->id = $id;
$this->acct = substr($id,0,4);
$this->sub = substr($id,4,2);
$this->qualifier = substr($id,6,1);
$this->type = substr($id,7,3);
$this->area = substr($id,10,2);
$this->info = substr($id,12,3);
$this->checksum = substr($id,15,1);
$this->datetime = $dt;
// Check the event is from a valid account
// @todo This shouldnt stop program execution, rather it should generate an email to an admin
$ao = ORM::factory('account',array('alarmphone'=>$cf,'siteid'=>$this->acct));
if (! $ao->loaded())
throw new Kohana_Exception('Event from unknown account :id is not valid',array(':id'=>$ao->id));
$eo = ORM::factory('event');
$eo->account_id = $ao->id;
$eo->alarmevent = $id;
$eo->datetime = $dt;
$eo->save();
// @todo This shouldnt stop program execution, rather it should generate an email to an admin
if (! $eo->saved())
throw new Kohana_Exception('ContactID event :event is not valid',array(':event'=>$id));
return $this;
}
public function __get($k) {
if (isset($this->{$k}))
return $this->{$k};
else
throw new Kohana_Exception('Unknown property :property',array(':property'=>$k));;
}
// Check that this event is valid
private function check($id) {
$checksum_map = array(
'0'=>10,
'1'=>1,
'2'=>2,
'3'=>3,
'4'=>4,
'5'=>5,
'6'=>6,
'7'=>7,
'8'=>8,
'9'=>9,
'*'=>11,
'#'=>12,
'A'=>13,
'B'=>14,
'C'=>15,
);
if (strlen($id) != 16)
throw new Kohana_Exception('ContactID event :event has an invalid length :length',array(':event'=>$id,':length'=>strlen($id)));
// Our checksum should be mod15
$c = $t = 0;
while ($c<strlen($id))
$t += $checksum_map[substr($id,$c++,1)];
if ($t%15 === 0)
return TRUE;
else
return FALSE;
}
}
?>

View File

@ -1,113 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* HomeALarmMONitor Receive an Event
*
* @package HAM
* @subpackage CLI/Event
* @category Controllers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Controller_Task_Event extends Controller_Template {
/**
* Read in the events
*/
public function action_index() {
$dh = opendir(Kohana::config('config.event_dir'));
$fp = Kohana::config('config.event_file_prefix');
while ($f = readdir($dh)) {
if (preg_match("/^{$fp}/",$f)) {
$eventfile = sprintf('%s/%s',Kohana::config('config.event_dir'),$f);
if ($events = $this->event_file(file_get_contents($eventfile))) {
// Delete the event file, so that it isnt processed again
if (Kohana::config('config.event_file_keep'))
rename($eventfile,Kohana::config('config.event_dir').'/processed-'.$f);
else
unlink($eventfile);
// Trigger
$eo = new Events($events);
$eo->trigger();
} else
rename($eventfile,Kohana::config('config.event_dir').'/bad-'.$f);
}
}
}
private function event_file($file) {
$meta = $event = FALSE;
$et = $cf = $cn = $dt = NULL;
$good = TRUE;
$events = array();
foreach (explode("\n",$file) as $line) {
// Ignore out blank lines
if (! trim($line))
continue;
if (preg_match('/^\[metadata\]/',$line)) {
$meta = TRUE;
$event = FALSE;
continue;
} elseif (preg_match('/^\[events\]/',$line)) {
$meta = FALSE;
$event = TRUE;
continue;
}
if ($meta) {
list ($k,$v) = explode('=',$line,2);
switch ($k) {
case 'PROTOCOL':
switch ($v) {
case 'ADEMCO_CONTACT_ID':
$et = 'ContactID';
break;
default:
throw new Kohana_Exception('Unknown protocol :protocol',array(':protocol'=>$v));
}
break;
case 'CALLINGFROM':
$cf = $v;
break;
case 'CALLERNAME':
$cn = $v;
break;
case 'TIMESTAMP':
$dt = $v;
break;
default:
printf('Extra data in event file - meta section (%s)',$line);
}
} elseif ($event) {
if (! $et)
throw new Kohana_Exception('Event data without any protocol');
$eo = new $et;
if (! $eo->event($line,$dt,$cf,$cn))
$good = FALSE;
else
array_push($events,$eo);
}
}
return $events;
}
}
?>

View File

@ -1,74 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is used to handle alarm events just received
*
* @package HAM
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Events {
private $acct;
private $events = array();
public function __construct(array $events) {
foreach ($events as $event) {
// Set our accounts
if (is_null($this->acct))
$this->acct = $event->acct;
elseif ($this->acct != $event->acct)
throw new Kohana_Exception('Events are for multiple accounts, unable to handle this.');
}
// Save our events
$this->events = $events;
}
public function trigger() {
$ao = ORM::factory('account',array('siteid'=>$this->acct));
if (! $ao->loaded())
throw new Kohana_Exception('No site configuration for :siteid?',array(':siteid'=>$this->acct));
if (! $ao->model->model)
throw new Kohana_Exception('No configured Alarm Model for Alarm ID :id',array(':id'=>$ao->model->id));
$ac = sprintf('Panel_%s',$ao->model->model);
if (! class_exists($ac))
throw new Kohana_Exception('Unable to handle events for Alarm :model',array(':model'=>$ao->model->model));
$panel = new $ac($this->events);
foreach ($panel->trigger() as $event) {
$to = $ao->trigger->trigger($event['alarm']);
if (! $to->loaded())
continue;
// We need to email this event
if ($to->email) {
$e = Email::connect();
$sm = Swift_Message::newInstance();
$sm->setSubject('Notice from your alarm');
$sm->setBody(sprintf('Alarm: %s. Received: %s',$event['desc'],date('d-m-Y h:i:s',$event['date'])),'text/plain');
$sm->setTo($to->contact->email);
$sm->setFrom('noreply@leenooks.net');
$e->send($sm);
}
// We need to sms this event
if ($to->sms) {
printf('Alarm: %s, SMS: %s, Email: %s, To: %s (%s)',
$alo->description,
$to->sms,
$to->email,
$to->contact->email,$to->contact->phone);
echo "\n";
}
}
}
}
?>

View File

@ -1,88 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class looks after Ness D8/Clipsal panel events
*
* @package HAM
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Panel_NessD8 extends Panel {
public function trigger() {
$return = array();
foreach ($this->events as $eo) {
$i = count($return);
$return[$i]['date'] = $eo->datetime;
$return[$i]['alarm'] = $eo->type;
if ($eo->sub != 18) {
$return[$i]['desc'] = sprintf('Unknown Alarm: %s',$eo->id);
continue;
}
switch ($eo->type) {
// Alarm
case 130:
switch ($eo->qualifier) {
case 1: $action = 'Alarm'; break;
case 3: $action = 'Reset'; break;
default: $action = 'Unknown';
}
$return[$i]['desc'] = sprintf('Alarm (%s) (Area %s) (%s)',$action,$eo->area,$eo->info);
break;
// Exit Installer Mode
case 306:
switch ($eo->qualifier) {
case 1: $action = 'Exit Installer Mode'; break;
default: $action = 'Unknown';
}
$return[$i]['desc'] = sprintf('Auto Exclude (%s) (Area %s) (%s)',$action,$eo->area,$eo->info);
break;
// Auto Exclude
case 380:
switch ($eo->qualifier) {
case 1: $action = 'Disarmed'; break;
case 3: $action = 'Armed'; break;
default: $action = 'Unknown';
}
$return[$i]['desc'] = sprintf('Auto Exclude (%s) (Area %s) (%s)',$action,$eo->area,$eo->info);
break;
// Arm/Disarm Call
case 402:
switch ($eo->qualifier) {
case 1: $action = 'Disarmed'; break;
case 3: $action = 'Armed'; break;
default: $action = 'Unknown';
}
// @todo Change this to include the user name.
$user = substr($eo->info,1,2)==58 ? 'Short Cut' : substr($eo->info,1,2);
// @todo Change this to include the area name.
$return[$i]['desc'] = sprintf('Panel %s (Area %s) (By %s)',$action,$eo->area,$user);
break;
// Test Call
case 602:
$return[$i]['desc'] = 'Test Call';
break;
default:
$return[$i]['desc'] = sprintf('Unknown Alarm: %s',$eo->id);
}
}
return $return;
}
}
?>

View File

@ -4,7 +4,7 @@ return array
(
'default' => array
(
'type' => 'mysql',
'type' => 'MySQL',
'connection' => array(
/**
* The following options are available for MySQL:

View File

@ -0,0 +1,17 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* HAlMon Configuration - Debug Settings
*
* @package HAlMon
* @category Configuration
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
return array
(
'test_mode'=>FALSE, // Test Mode
);
?>

@ -1 +1 @@
Subproject commit f96694b18fdaa9bd6310debca71427068fe24046
Subproject commit f5c623d89783fc9bf3c8dbea7699fcefa0015c3d

View File

@ -4,14 +4,14 @@
* The directory in which your application specific resources are located.
* The application directory must contain the bootstrap.php file.
*
* @see http://kohanaframework.org/guide/about.install#application
* @link http://kohanaframework.org/guide/about.install#application
*/
$application = 'application';
/**
* The directory in which your modules are located.
*
* @see http://kohanaframework.org/guide/about.install#modules
* @link http://kohanaframework.org/guide/about.install#modules
*/
$modules = 'modules';
@ -24,7 +24,7 @@ $sysmodules = 'includes/kohana/modules';
* The directory in which the Kohana resources are located. The system
* directory must contain the classes/kohana.php file.
*
* @see http://kohanaframework.org/guide/about.install#system
* @link http://kohanaframework.org/guide/about.install#system
*/
$system = 'includes/kohana/system';
@ -32,13 +32,13 @@ $system = 'includes/kohana/system';
* The default extension of resource files. If you change this, all resources
* must be renamed to use the new extension.
*
* @see http://kohanaframework.org/guide/about.install#ext
* @link http://kohanaframework.org/guide/about.install#ext
*/
define('EXT', '.php');
/**
* Set the PHP error reporting level. If you set this in php.ini, you remove this.
* @see http://php.net/error_reporting
* @link http://www.php.net/manual/errorfunc.configuration#ini.error-reporting
*
* When developing your application, it is highly recommended to enable notices
* and strict warnings. Enable them by using: E_ALL | E_STRICT
@ -55,7 +55,7 @@ error_reporting(E_ALL | E_STRICT);
* End of standard configuration! Changing any of the code below should only be
* attempted by those with a working knowledge of Kohana internals.
*
* @see http://kohanaframework.org/guide/using.configuration
* @link http://kohanaframework.org/guide/using.configuration
*/
// Set the full path to the docroot
@ -111,11 +111,21 @@ if ( ! defined('KOHANA_START_MEMORY'))
// Bootstrap the application
require APPPATH.'bootstrap'.EXT;
/**
* Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
* If no source is specified, the URI will be automatically detected.
*/
echo Request::factory()
->execute()
->send_headers()
->body();
if (PHP_SAPI == 'cli') // Try and load minion
{
class_exists('Minion_Task') OR die('Please enable the Minion module for CLI support.');
set_exception_handler(array('Minion_Exception', 'handler'));
Minion_Task::factory(Minion_CLI::options())->execute();
}
else
{
/**
* Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
* If no source is specified, the URI will be automatically detected.
*/
echo Request::factory(TRUE, array(), FALSE)
->execute()
->send_headers(TRUE)
->body();
}