Предлагается функция, считающая долю времени исторического свойства в зависимости от его величины
Навеяно блогом о среднем тык(1) и обсуждением на форуме тык
Народ озабачивается вопросом - сколько сегодня работал режим Экономный? или Какая у меня сеть 220? или Сколько времени работали мои нагреватели, управляемые термостатом?
Оказалось, что если свойство является бинарным (0/1), то долю времени работы/активности (т.е., когда значение свойства = 1) можно получить с помощью функции из блога (1).
Пример - есть реле конвектора, управляемое термостатом с пид-регулятором, как узнать сколько времени за день реле включено?
Возьмём функцию getHistoryAvgMy($obj_prop,$start_time,$stop_time) и запустим ее с параметрами:
console>getHistoryAvgMy( 'Noorelay_1.status',-60 * 60 * 24 + 1,0)
console>0.39366196368014
Тут мы смотрели на интервал времени в 24 часа от текущего и узнали, что 39% от суток реле Noorelay_1 было включено. Можно узнать (если история позволяет) время активности объекта на любом интервале, задавая время старта/окончания расчета - за позавчера,с начала суток - strtotime(date("Y-m-d").' 00:00:00'), за час, месяц и т.д.
Но что делать, если свойство не бинарное? Типа, как посчитать долю суток с отрицательной температурой или как долго моя сеть работает в ненормальном режиме - вне диапазона -- пусть от 209 до 231 в?
Родил функцию:
//возвращает долю времени на интервале, где истинно сравнение $objprop со значением $value по правилу $oper
//$oper{'=','<>','>','>=','<','<=','betw','!betw'};
//ex gg('obj.prop') == 1 / gg('obj.prop') betw -1,1/ gg('obj.prop') !betw 10,15
//return t(true part)/t(whole interval)
function getHistoryPart($objprop, $start_time, $stop_time = 0, $oper = "=", $value = '1', $value2 = '0') {
if($start_time <= 0) $start_time = (time() + $start_time);
if($stop_time <= 0) $stop_time = (time() + $stop_time);
$pvalue = getHistoryValueId($objprop);
if(defined('SEPARATE_HISTORY_STORAGE') && SEPARATE_HISTORY_STORAGE == 1) {
$table_name = createHistoryTable($pvalue);
} else {
$table_name = 'phistory';
}
// Получить количество записей за нужный период времени
$arr_s = SQLSelectOne("SELECT COUNT(ID) as COUNT_ID FROM $table_name ".
"WHERE VALUE_ID=".$pvalue." and not value is null ".
"AND ADDED between '".date('Y-m-d H:i:s', $start_time)."' AND '".date('Y-m-d H:i:s', $stop_time)."'");
// Взять это количество записей +1
$arr_s = SQLSelect("SELECT * FROM $table_name WHERE VALUE_ID=".$pvalue." and not value is null ".
" AND ADDED<='".date('Y-m-d H:i:s', $stop_time)."' ORDER BY ADDED DESC LIMIT 0 , ".(1+$arr_s['COUNT_ID']));
$tmr2 = $stop_time;
// Переберем весь массив
foreach($arr_s as $s) {
$tmr1 = $tmr2;
$tmr2 = strtotime($s['ADDED']);
// Ограничить началом
if($tmr2<$start_time) $tmr2 = $start_time;
// Двигаясь вниз по массиву времени складывать отрезки
//echo(date('H:i:s', $tmr1).' - '.date('H:i:s', $tmr2).' = '.($tmr1 - $tmr2).'c t='.$s['VALUE'].'<br>');
if($oper == '=' || $oper == '=='){
if($s['VALUE']==$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '>'){
if($s['VALUE']>$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '<'){
if($s['VALUE']<$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '>='){
if($s['VALUE']>=$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '<='){
if($s['VALUE']<=$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '<>' || $oper == '!='){
if($s['VALUE']<>$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == 'betw'){
if($s['VALUE']>=$value && $s['VALUE']<=$value2) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '!betw'){
if($s['VALUE']<$value || $s['VALUE']>$value2) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}
}//foreach
$all = $stop_time - $start_time; //всего времени с начала интервала до конца
return $tmr_mem/$all;
}
если мы запустим ее с такими параметрами
console>getHistoryPart('Noorelay_1.status',-60*60*24+1,0,'=',1)
console>0.39366196368014
то она отработает, как функция выше. Но эта функция позволяет задавать свои операции сравнения значения свойства
это может быть проверка на равенство ('=','=='), неравенство ('!=','<>'), больше/меньше ('>','>=','<','<='), вхождение/невхождение в интервал ('betw','!betw')
примеры
Наш, c электричеством - как долго моя сеть работает в ненормальном режиме - вне диапазона -- пусть от 209 до 231 в --с начала дня?
console>getHistoryPart('ippon.inVoltage',strtotime(date("Y-m-d").' 00:00:00'),0,'!betw',209,231)
console>0.012494285267855
(ого, больше процента!)
Доля отрицательной наружной температуры за последние сутки:
console>getHistoryPart('Outside.Temperature',-60*60*24+1,0,'<',0)
Доля отрицательной наружной температуры за предпоследние сутки:
console>getHistoryPart('Outside.Temperature',-60*60*24*2+1,-60*60*24,'<',0)
ps Если нужно узнать время вместо доли :
для примера getHistoryPart('Outside.Temperature',-60*60*24*2+1,-60*60*24,'<',0)
//приведём время от смещения к абсолютному для того, чтобы узнать длительность всего интервала
//т.к. у нас в примере указано отрицательное смещение
$start_time = time() - 60*60*24*2+1;
$stop_time = time() - 60*60*24;
$t_sec = ($stop_time-$start_time)*getHistoryPart('Outside.Temperature',$start_time,$stop_time,'<',0);
Для примера getHistoryPart('Outside.Temperature',-60*60*24+1,0,'<',0)
//приведём время от смещения к абсолютному для того, чтобы узнать длительность всего интервала
$start_time = time() - 60*60*24+1;
$stop_time = time();
$t_sec = ($stop_time-$start_time)*getHistoryPart('Outside.Temperature',$start_time,$stop_time,'<',0);
pps По просьбе публики (Логрусу привет!) вариант функции, возвращающий всё массивом:
function getHistoryPart2($objprop, $start_time, $stop_time = 0, $oper = "=", $value = '1', $value2 = '0') {
if($start_time <= 0) $start_time = (time() + $start_time);
if($stop_time <= 0) $stop_time = (time() + $stop_time);
$pvalue = getHistoryValueId($objprop);
if(defined('SEPARATE_HISTORY_STORAGE') && SEPARATE_HISTORY_STORAGE == 1) {
$table_name = createHistoryTable($pvalue);
} else {
$table_name = 'phistory';
}
// Получить количество записей за нужный период времени
$arr_s = SQLSelectOne("SELECT COUNT(ID) as COUNT_ID FROM $table_name ".
"WHERE VALUE_ID=".$pvalue." and not value is null ".
"AND ADDED between '".date('Y-m-d H:i:s', $start_time)."' AND '".date('Y-m-d H:i:s', $stop_time)."'");
// Взять это количество записей +1
$arr_s = SQLSelect("SELECT * FROM $table_name WHERE VALUE_ID=".$pvalue." and not value is null ".
" AND ADDED<='".date('Y-m-d H:i:s', $stop_time)."' ORDER BY ADDED DESC LIMIT 0 , ".(1+$arr_s['COUNT_ID']));
$tmr2 = $stop_time;
// Переберем весь массив
foreach($arr_s as $s) {
$tmr1 = $tmr2;
$tmr2 = strtotime($s['ADDED']);
// Ограничить началом
if($tmr2<$start_time) $tmr2 = $start_time;
// Двигаясь вниз по массиву времени складывать отрезки
//echo(date('H:i:s', $tmr1).' - '.date('H:i:s', $tmr2).' = '.($tmr1 - $tmr2).'c t='.$s['VALUE'].'<br>');
if($oper == '=' || $oper == '=='){
if($s['VALUE']==$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '>'){
if($s['VALUE']>$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '<'){
if($s['VALUE']<$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '>='){
if($s['VALUE']>=$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '<='){
if($s['VALUE']<=$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '<>' || $oper == '!='){
if($s['VALUE']<>$value) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == 'betw'){
if($s['VALUE']>=$value && $s['VALUE']<=$value2) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}elseif($oper == '!betw'){
if($s['VALUE']<$value || $s['VALUE']>$value2) $tmr_mem = $tmr_mem + $tmr1 - $tmr2;
}
}//foreach
$all = $stop_time - $start_time; //всего времени с начала интервала до конца
$ret = array();
$ret['PART'] = $tmr_mem/$all; //тут доля
$ret['PART_TIME'] = $tmr_mem; // тут время в секундах, где условие истинно
$ret['ALL_TIME'] = $all; //всего времени с начала интервала до конца
return $ret;
}
Вызов в консоли
console>print_r(getHistoryPart2('Noorelay_1.status',-60*60*24))
возвращает массив:
Array
(
[PART] => 0.54081018518519
[PART_TIME] => 46726
[ALL_TIME] => 86400
)
1
Домодедово, Россия
На форуме: xor