Свойства класса:
Методы класса:
$s=$params['status'];
if (isset($s)) {
// Если некорректные данные
if (($s > 6) || ($s < 0)) { return; }
// Записать в свойство объекта
$this->setProperty('status',$s);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных
$s = $this->getProperty('status');
}
switch ($s) {
case 0:
$t='Процесс завершен';
say('Завершение процесса дистилляции');
$this->setProperty('tmaxColumn', 0);
$this->setProperty('tempCube', 0);
$this->setProperty('tempColumn', 0);
$this->setProperty('tempStartColumn', 0);
$this->setProperty('startPercentCube',0);
$this->setProperty('currentPercentCube',0);
//sg('cycle_alcoControl','stop');
break;
case 1:
$t='Разогрев куба';
$this->setProperty('tmaxColumn', 0);
$this->setProperty('tempCube', 0);
$this->setProperty('tempColumn', 0);
sg('cycle_alcoControl','start');
setTimeOut($ot.'_status_Timer',"say('Напоминаю о продлении таймера работы печи', 2);", 25*60);
break;
case 2:
$t='Готовность к началу';
break;
case 3:
$t='Работа на себя';
break;
case 4:
$t='Отбор головных фракций';
say('Дальнейшее переключение стадий вручную', 2);
break;
case 5:
$t='Отбор тела';
break;
case 6:
$t='Отбор хвостов';
break;
}
// Убрать задержду для следующего сообщения
$this->setProperty('notifyTime',0);
// для титула переключателя в меню
$this->setProperty('titleStage',$t);
$this->setProperty('log',date('h:m').' '.$t);
if ($s) { say("Стадия $s. $t"); }/* $p - имя датчика
$s - температура
$status - стадия работы
$tmax - максимальная температура колонны в разных режимов + rnd для движения живого графика
*/
// должно быть передано имя свойства датчика
// $params['tempCube'] или $params['tempColumn']
$p = key($params);
$s = current($params);
$status=$this->getProperty('status');
if (isset($s)) {
// Если некорректные данные
if (($s > 150) || ($s < 5)) { return; }
// Записать в свойство объекта
$s=round($s, 3);
$this->setProperty($p, $s);
} else {
say('не передано имя свойства');
return;
}
/* максимальная температура колонны расчитывается при изменении температуры куба
если пришли данные колонны, то читаем её из свойства
*/
if ($p=='tempColumn') {
$tmax=($this->getProperty('tmaxColumn'));
}
$ot=$this->object_title;
// playsound($p.'.wav');
switch ($status.$p) {
/* --------- разогрев --------- */
case '1tempCube':
//$tmax=40;
$tmax=34;
// переключить на стадию 2 при разогреве куба до 85 градусов. ToDo расчитать по указанной спиртуозности
if ($s>85) {
say('Скоро начнется процесс дисциляции', 2);
$this->setProperty('log',date('h:m').' Скоро начнется процесс');
$this->callMethod('statusChanged', array('status'=>2));
}
break;
case '1tempColumn':
// переключить на стадию 2 при неожиданном росте t колонны
if ($s>$tmax) {
// это притормозит переход при неостывшей колонне
if ($this->getProperty('tempCube') > 60) {
say('Неожиданный рост температуры колонны', 2);
$this->setProperty('log',date('h:m').' Неожиданный рост t колонны');
$this->callMethod('statusChanged', array('status'=>2));
}
}
break;
/* --------- готовность к началу --------- */
case '2tempCube':
$tmax=37;
if ($s>90) { $n='Температура близка к началу процесса дисциляции'; } // ToDo расчитать по указанной спиртуозности раствора
break;
case '2tempColumn': //zzzzzzz
if ($s>$tmax) {
// записать температуру куба при прогреве колонны
$this->setProperty('tempStartColumn', $this->getProperty('tempCube'));
say('Прогрев спиртовой колонны', 2);
$this->setProperty('log',date('h:m').' Прогрев колонны');
// переключить на стадию 4 через 5 минут
setTimeOut($ot.'_status_Timer',"cm('$ot.statusChanged', array('status'=>4));", 5*60);
// переключить на стадию 3
$this->callMethod('statusChanged', array('status'=>3));
}
break;
/* --------- работа на себя --------- */
case '3tempCube':
//$tmax=70;
$tmax=74;
break;
case '3tempColumn':
if ($s>$tmax) { $n='Высокая температура колонны'; }
break;
/* --------- головы --------- */
case '4tempCube':
//$tmax=73;
$tmax=75;
break;
case '4tempColumn':
if ($s>$tmax) { $n='Высокая температура колонны'; }
break;
/* --------- тело --------- */
case '5tempCube':
// блок расчета максимальной температуры колонны
$const_tColStart = 75.4; // начальная t колонны. Определена опытным путем. ToDo уточнить
$const_tColEnd = 77.3; // конечная t колонны. Определена опытным путем. t кип этил спирта 78.39
//$const_tColLimitUp = 0.5; // дозволенный предел превышения температуры колонны
$const_tColLimitUp = 0.2; // дозволенный предел превышения температуры колонны
$const_tCubStart = $this->getProperty('tempStartColumn'); // записанная температура куба при подъеме колонны
$const_tCubEnd = 97.8; //завершением процесса отбора тела можно считать температуру куба 97,8 градусов
$kCol = ($const_tColEnd - $const_tColStart) / ($const_tCubEnd - $const_tCubStart); // коэффициент наклона для линии колонны
$tmax = $const_tColStart + $kCol*($s - $const_tCubStart) + $const_tColLimitUp;
// начало /\ подъем /\ лимит /\
if ($s>$const_tCubEnd) { $n='Температура куба на стадии завершения отбора тела'; }
break;
case '5tempColumn':
if ($s>$tmax) { $n='Высокая температура колонны'; }
if ($s<$tmax-2) { $n='Низкая температура колонны'; }
break;
/* --------- хвосты --------- */
case '6tempCube':
//$tmax=max($s-15, 78.4); // максивальная температура колонны принимается на 15 градусов ниже куба, либо 78 градусов
$tmax=min($s-14, 78.4); // максивальная температура колонны принимается на 14 градусов ниже куба, либо 78 градусов. Изопропиловый 82,1
if ($s>99) { $n='Максимальная температура куба. Завершите процесс'; }
break;
case '6tempColumn':
if ($s>$tmax) { $n='Высокая температура колонны'; }
break;
/* --------- завершить --------- */
default:
return;
}
// рандомные данные для графика
$this->setProperty('tmaxColumn', $tmax+rand(0,100)/100000);
// Уведомления с пуш не чаще 1 минуты (либо нет времени последнего уведомления)
if ($n) {
$lastn=$this->getProperty('notifyTime');
if (time() - $lastn > 60) {
// сказать
say($n, 2);
// лог
$this->setProperty('log',date('h:m').' '.$n);
// записать время уведомления
$this->setProperty('notifyTime',time());
}
}
// на стадии >=3 и при данных t куба вычисляем процент спирта
// пишем в currentPercentCube
// если не startPercentCube то пишем и туда
// очень примерно, но можно подогнать под свой аппарат с великолепной точностью
if ($status>=3 && $p=='tempCube' && $s>60) {
//$Ti = ( $s - 89.03 ) / 6.54;
//$ob = 16.75 - 19.05 * $Ti + 12.64 * pow($Ti,2) - 3.69 * pow($Ti,3) - 0.38 * pow($Ti,4);
$Ti = ( $s - 89 ) / 6.49;
$ob = 17.26 - 18.32 * $Ti + 7.81 * pow($Ti,2) - 1.77 * pow($Ti,3) + 4.81 * pow($Ti,4) - 2.95 * pow($Ti,5) - 1.43 * pow($Ti,6) + 0.8 * pow($Ti,7) + 0.05 * pow($Ti,8);
$ob = round($ob,1);
$this->setProperty('currentPercentCube', $ob);
if ($status==3 && !($this->getProperty('startPercentCube'))) {
say("В кубе $ob% спирта");
$this->setProperty('startPercentCube',$s);
$this->setProperty('log',date('h:m')." В кубе $ob% спирта");
}
}
Свойства класса:
Методы класса:
if ($params['NEW_VALUE']) {
$this->setProperty('moveStatus', '0'); // если ворота в крайнем положении, значит мотор отключен. Заплата на мегу!!!
$this->setProperty('bottonColor','#00FF00');
// попробую включить опять, по идее ничему помешать не должно.
$this->setProperty('controlSwitch', $params['NEW_VALUE']); //направление контрола уже задано методом мотора
}global $do_not_execute_object_method_AutoDoors;
$ot=$this->getProperty('title');
// проверка разрешения на управление
if (!$this->getProperty('generalAdmin')) {
say("$ot запрещено администрировать");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка разрешения на открытие
if (!$this->getProperty('openingEnable')) {
say("$ot запрещено открывать");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка движения
if ($this->getProperty('moveStatus')) {
say("$ot сейчас в движении");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка крайнего положения
if ($this->getProperty('positionStatus')==1) {
$do_not_execute_object_method_AutoDoors=true;
say("$ot уже открыты");
return;
}global $do_not_execute_object_method_AutoDoors;
$ot=$this->getProperty('title');
// проверка разрешения на управление
if (!$this->getProperty('generalAdmin')) {
say("$ot запрещено администрировать");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка разрешения на открытие
if (!$this->getProperty('closingEnable')) {
say("$ot запрещено закрывать");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка движения
if ($this->getProperty('moveStatus')) {
say("$ot сейчас в движении");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка крайнего положения
if ($this->getProperty('positionStatus')==-1) {
$do_not_execute_object_method_AutoDoors=true;
say("$ot уже закрыты");
return;
}global $do_not_execute_object_method_AutoDoors;
$ot=$this->getProperty('title');
// проверка разрешения на управление
if (!$this->getProperty('generalAdmin')) {
say("$ot запрещено администрировать");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка движения
if (!$this->getProperty('moveStatus')) {
say("$ot сейчас не движутся");
$do_not_execute_object_method_AutoDoors=true;
return;
}
// проверка крайнего положения
if ($this->getProperty('positionStatus')) {
$do_not_execute_object_method_AutoDoors=true;
say("$ot сейчас в крайнем положении");
return;
}
// если добралить, значит будет выполнен метод объекта stop.
// но сразу после перывания питания будут отправлены статусы конечников ворот.
// убираем кнопку и цвет
$ot=$this->object_title;
setTimeOut($ot.'_controlreset_delayexec',"
sg($ot.'.controlSwitch', 0);
sg($ot.'.bottonColor', NULL);
", 1);if ($params['NEW_VALUE']) {
// направление вращения мотора переключает контрол
$this->setProperty('controlSwitch', $params['NEW_VALUE']);
$this->setProperty('bottonColor','#FF0000');
} else {
// остановка мотора
/*
возможна по конечнику, а так же кнопками стоп на щите или меню.
При вклбючении сообщения Меги о стопе мотора можно через секунду смотреть статусы конечников.
Если не в крайнем положении, значит
$ot=$this->object_title;
setTimeOut($ot.'_controlreset_delayexec',"
sg($ot.'.controlSwitch', 0);
sg($ot.'.bottonColor', NULL);
", 1);
*/
}Свойства класса:
Методы класса:
// Может получить параметр VALUE, а если его нет, возьмет громкость из свойства volumeLevel
if (isset($params['VALUE'])) {
$vl=$params['VALUE'];
$this->setProperty('volumeLevel',$vl);
} else {
$vl=$this->getProperty('volumeLevel');
}
// Громкость, как и любой другой параметр, может быть передан прямо в тексте сообщения
say('-volumemaster:'.$vl." Громкость ".$vl." процентов");Свойства класса:
Методы класса:
if (!isset($params['command'])) { debmes('Класс Dampers. Вызов метода incomingMessage без параметра command'); }
$ot=$this->object_title;
$slider = (int)$this->getProperty('slider');
$min = $this->getProperty('min');
$max = $this->getProperty('max');
// определить время максимальной работы
//if (!is_numeric($max)) { $t_сalib = $max; }
$t_сalib = 5; // доводить придод до конечника ещё 5 секунд
switch ($params['command']) {
case 'openCalibrat':
$this->callMethod('openStop');
say('Калибровка положения открытия заслонки не удалась');
break;
case 'closeCalibrat':
$this->callMethod('closeStop');
say('Калибровка положения закрытия заслонки не удалась');
break;
case 'openStop':
// если слайдер на максимуме и задан максимум
if (is_numeric($max) && $slider>=$max ) {
say('Начинаю калибровку положения открытия заслонки');
// $this->callMethod('openStart'); //в данный момент мотор уже работает
setTimeOut($ot.'_open', "callMethod('$ot.incomingMessage', array('command'=>'openCalibrat'));", $t_сalib);
} else {
$this->callMethod('openStop');
say('Заслонка достигла позиции');
}
break;
case 'closeStop':
if (is_numeric($min) && $slider<=$min ) {
say('Начинаю калибровку положения закрытия заслонки');
// $this->callMethod('closeStart'); //в данный момент мотор уже работает
setTimeOut($ot.'_close', "callMethod('$ot.incomingMessage', array('command'=>'closeCalibrat'));", $t_сalib);
} else {
$this->callMethod('closeStop');
say('Заслонка достигла позиции');
}
break;
case 'openKey':
// удалить таймер конца открытия
cleartimeout($ot.'_open');
// остановить открытие
$this->callMethod('openStop');
// сообщить о полном открытии
say('Заслонка полностью открыта');
break;
case 'closeKey':
cleartimeout($ot.'_close');
$this->callMethod('closeStop');
say('Заслонка полностью закрыта');
break;
default:
debmes('Класс Dampers. Не корректный параметр command='.$params['command'].' при вызове метода incomingMessage');
}
$this->setProperty('position', $slider);
// команда с конечника при его срабатывании
//callMethod('$ot.incomingMessage', array('command'=>'openKey'));//debmes(json_encode($params, JSON_UNESCAPED_UNICODE), 'test');
$ot=$this->object_title;
// при линке с эоементом слайдер будут переданы VALUE и OLD_VALUE. Иначе взять данные из текущих свойств объекта
if (isset($params['VALUE'])) { $slider = (int)$params['VALUE']; } else { $slider = (int)$this->getProperty('slider'); }
if (isset($params['OLD_VALUE'])) { $position = (int)$params['OLD_VALUE']; } else { $position = (int)$this->getProperty('position'); }
// Высчитать текущее положение с учетом возможного перемещения
$position = $position - timeoutresidue($ot.'_open') + timeoutresidue($ot.'_close');
// ОТКРЫТЬ
if ($slider > $position) {
$this->callMethod('closeStop');
say('Открываю заслонку '. ($slider - $position) . ' секунд');
$this->callMethod('openStart');
cleartimeout($ot.'_close');
setTimeOut($ot.'_open', "callMethod('$ot.incomingMessage', array('command'=>'openStop'));", ($slider - $position));
// ЗАКРЫТЬ
} elseif ($slider < $position) {
// остановить открытие
$this->callMethod('openStop');
say('Закрываю заслонку '. ($position - $slider) . ' секунд');
// начать закрытие
$this->callMethod('closeStart');
// запланировать стоп
cleartimeout($ot.'_open');
setTimeOut($ot.'_close', "callMethod('$ot.incomingMessage', array('command'=>'closeStop'));", ($position - $slider));
} else {
say('Заслонка уже на позиции');
}Свойства класса:
Методы класса:
// say('OLD_VALUE='.$params['OLD_VALUE']);
// say('NEW_VALUE='.$params['NEW_VALUE']);
$t='';
$p=$this->getProperty('name');
if ($params['NEW_VALUE']==0) {$t="С провайдером $p потеряно соединение";}
elseif ($params['NEW_VALUE']==1 && $params['OLD_VALUE']==0) {$t="Установлено соединения c провайдером $p";}
elseif ($params['NEW_VALUE']==1 && $params['OLD_VALUE']>=2) {$t="Провайдер $p не предоставляет Интернет";}
elseif ($params['NEW_VALUE']==2 && $params['OLD_VALUE']<=1) {$t="Провайдер $p, Интернет предоставлен";}
elseif ($params['NEW_VALUE']==3) {$t="Провайдер $p выбран главным";}
if ($t) { say($t, gg(NightMode.status)?-1:0); }Свойства класса:
Методы класса:
Свойства класса:
Свойства класса:
Методы класса:
//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("Y-m-d H:i:s",time()));
// Свойство alive для класса тревожных датчиков не актуально
$s=$params['status'];
if (isset($s)) {
$this->setProperty('status',$s);
} else {
$s = $this->getProperty('status');
}
// у датчика есть слинкованная комната и его маркер тревоги
$mark = $this->getProperty('marker'); //маркер fire smoke heat toxic gas flood freeze
$linked_room = $this->getProperty('LinkedRoom');
if ($mark) {
if ($linked_room) {
/* получить тревожную строку у слинкованной комнаты и декодировать её в массив */
$alarms = getGlobal("$linked_room.Alarms");
$alarms_old = $alarms;
/* сценарий - функция для внесения изменений с строку тревог */
$alarms = runscript('editJson', array('key'=>$mark, 'val'=>$this->id, 'js'=>$alarms, 'add'=>$s));
/* записать в свойство комнаты и вызвать метод */
if ($alarms_old != $alarms) {
callMethod("$linked_room.onAlarms", array('Alarms'=>$alarms));
}
} else { sg('alerts_message', 'Объект датчика '. $this->object_title.' не имеет слинкованной комнаты'); } // if_linked_room
} else { sg('alerts_message', 'В объекте датчика '. $this->object_title.' не указано свойство маркер'); } // if_markМетоды класса:
//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("Y-m-d H:i:s",time()));
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=12*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
$s=$params['status'];
if (isset($s)) {
// Записать в свойство объекта
$this->setProperty('status',$s);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных,
$s = $this->getProperty('status');
}
/*
if ($s) {
}
*/Свойства класса:
Методы класса:
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=12*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
// Записать в свойство, если его имя содержит history
foreach ($params as $key => $value) {
$pos = stripos($key, 'history');
if ($pos !== false) {
$this->setProperty($key, $value);
}
}Свойства класса:
Методы класса:
//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("Y-m-d H:i:s",time()));
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=12*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
$s=$params['status'];
if (isset($s)) {
// Если некорректные данные
if (($s > 100) || ($s <= 0)) { return; }
// Записать в свойство объекта
$this->setProperty('status',$s);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных, взять их из свойства.
$s = $this->getProperty('status');
}
// Получение среднего значения из истории ToDo заменить на штатную функцию
//Получить id свойства
$prop_id=$this->getPropertyByName('status', $this->class_id, $this->id);
//Получаем VALUE_ID для следующей таблицы
$pvalue=SQLSelectOne("SELECT * FROM pvalues WHERE PROPERTY_ID='".$prop_id."' AND OBJECT_ID='".$this->id."'");
//Получаем средние значения за последние 30 минут
$start_time=time()-30*60; // 30 минут
$arr_s = SQLSelectOne("SELECT avg(VALUE) as AVG_V FROM phistory WHERE VALUE_ID='".$pvalue['ID']."' AND ADDED>='".date('Y-m-d H:i:s', $start_time)."'");
$avg_s=round($arr_s['AVG_V'], 1);
$s=round($s, 1);
// Сравнение
if ($s-$avg_s > 10) {
$d=1;
} elseif ($s-$avg_s < -10) {
$d=-1;
} else {
$d=0;
}
$this->setProperty('direction',$d);
$this->setProperty('status',$s);
// Передать данные слинкованной комнате
$linked_room=$this->getProperty("LinkedRoom");
if ($linked_room) {
// Получение последней записи истории комнаты ToDo РАЗОБРАТЬСЯ
$obj=getObject($linked_room);
$prop_id=$obj->getPropertyByName('Humidity', $obj->class_id, $obj->id);
$pvalue=SQLSelectOne("SELECT * FROM pvalues WHERE PROPERTY_ID='".$prop_id."' AND OBJECT_ID='".$obj->id."'");
$arr_s = SQLSelectOne("SELECT UNIX_TIMESTAMP(ADDED)as ADDED, VALUE FROM phistory WHERE VALUE_ID='".$pvalue['ID']."' ORDER BY ADDED DESC LIMIT 1");
// Обновить если прошло больше часа. При этом на графике будет горизонтальная и вертикальная линии вместо одной наклонной.
if (time()-$arr_s['ADDED'] > 60*60) {
setGlobal($linked_room.'.Humidity', $arr_s['VALUE']);
}
// Записать новое значение
setGlobal($linked_room.'.Humidity', $s);
}Свойства класса:
Методы класса:
//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("Y-m-d H:i:s",time()));
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=6*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
$s=$params['status'];
if (isset($s)) {
// Если некорректные данные
if (($s > 65535) || ($s < 0)) { return; }
// Записать в свойство объекта
$this->setProperty('status',$s);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных, взять их из свойства.
$s = $this->getProperty('status');
}
// Передать данные слинкованной комнате
$linked_room=$this->getProperty('LinkedRoom');
if ($linked_room) {
// Для этого датчика слинкованой комнате передавать усредненное значение
// эффективно при большом разбросе показаний датчика
if ($ot=='ls_driveway') {
// Определить период усреднения
// чем ниже показания датчика, тем больше период усреднения, чтобы исключить большие скачки у нуля
switch ($s) {
case 0: $avgtime=26; break;
case $s<10: $avgtime=21; break;
case $s<20: $avgtime=16; break;
case $s<50: $avgtime=11; break;
case $s<100: $avgtime=6; break;
default: $avgtime=0;
}
//$avgtime=1;
// Получение среднего значения из истории ToDo заменитьна штатную функцию
if ($avgtime) {
//Получить id свойства
$pvalueid = getHistoryValueId("$ot.status");
//Получаем средние значение за требуемый период
$start_time=time()-$avgtime*60;
//$arr_s = SQLSelectOne("SELECT avg(VALUE) as AVG_V FROM phistory WHERE VALUE_ID=$pvalueid AND ADDED>='".date('Y-m-d H:i:s', $start_time)."'");
$arr_s = SQLSelect("SELECT VALUE FROM phistory WHERE VALUE_ID=$pvalueid AND ADDED>='".date('Y-m-d H:i:s', $start_time)."'");
//Среднее значение округлить до целых если в ответе есть данные
if ($arr_s!==[]) {
//echo 'SQL массив <br/>';
//print_r($arr_s);
// в ответе масив массивов. нам нужено получить простой массив значений
//$arr_s=array_column($arr_s, 'VALUE'); // работает с php версии 5.5.0 У меня сейчас 5.4
// альтернативный вариант функции array_column
function array_column_alt($arr_u) { return $arr_u['VALUE']; }
$arr_s = array_map('array_column_alt', $arr_s);
// добавить в массив текущее значение
// $arr_s[]=array("VALUE"=>$s); // массив уже приведен к простому
$arr_s[]=$s;
//echo 'МОЙ массив <br/>';
//print_r($arr_s);
//debmes('Свет '.$this->object_title.' array_sum($arr_s)='.array_sum($arr_s).'count($arr_s)='.count($arr_s));
// avg
$s=array_sum($arr_s)/count($arr_s);
$s=round($s, 0);
} //else { debmes('Свет '.$this->object_title.' Пустой массив'); }
}
}
//debmes('Свет '.$this->object_title.' отправлено '.$s);
// Передать комнате
setGlobal($linked_room.'.Luminiscence', $s);
}Свойства класса:
Методы класса:
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=24*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
$s=$params['status'];
if (isset($s)) {
// Записать в свойство объекта
$this->setProperty('status',$s);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных, взять их из свойства.
$s = $this->getProperty('status');
}
$linked_room=$this->getProperty("LinkedRoom");
if ($linked_room) {
if ($s) {
// Вызывать метод onActivity при активности
cm($linked_room.'.onActivity', ['source'=>$ot]); //ToDo Передача дескрипшена датчика
} else {
/* ПЕРЕИГРАЛ на вызов метода onActivity с половиной таймера
// Вызывать метод onIdle если статусный датчик потерял движение и прислал 0.
// onIdle прервет выполнение, если существуют другие активные статусные датчики или таймер
cm($linked_room.'.onIdle');
*/
// Вызывать метод onActivity с половиной таймера при получении 0 от датчика
cm($linked_room.'.onActivity', ['source'=>$ot, 'activity_timeout_factor'=>0.5]);
}
}$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=7*24*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
// Установить статус датчика на 30 секунд. ТЕПЕРЬ у импульсных датчиков не должен быть status
//$this->setProperty('status', 1);
//setTimeOut($ot.'_status', "sg('".$ot.".status', 0);", 30);
// Вызывать метод onActivity
$linked_room=$this->getProperty("LinkedRoom");
if ($linked_room) {
cm($linked_room.'.onActivity', ['source'=>$ot]);
}Свойства класса:
Методы класса:
//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("Y-m-d H:i:s",time()));
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=12*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
$s=$params['status'];
if (isset($s)) {
// Записать в свойство объекта
$this->setProperty('status',$s);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных,
//u $s = $this->getProperty('status');
}
/*
if ($s) {
}
*/Свойства класса:
Методы класса:
$this->setProperty('alive', 1);
$ot = $this->object_title;
$alive_timeout = (int)$this->getProperty('aliveTimeOut');
if (!$alive_timeout) { $alive_timeout = 6*60*60; }
setTimeOut($ot.'_alive', "sg('$ot.alive', 0);", $alive_timeout);
// *** Получение среднего значения из истории
$start_time = time() - 30*60; // секунд
// средние значения температуры за последее время
$s_avg = getHistoryAvg("$ot.status", $start_time);
// *** принять или прочитать данные
if (isset($params['status'])) {
$s = $params['status'];
// Если некорректные данные
if (($s > 150) || ($s < -50)) { return; }
// Записать в свойство объекта
$this->setProperty('status', $s);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных, взять их из свойства.
$s = $this->getProperty('status');
}
$s = round($s, 1);
// *** Сравнение
if ($s_avg === false) {
$d = 0; // в истории нет записей
} else {
$s_avg = round($s_avg, 1);
if ($s-$s_avg > 0.3) {
$d = 1; // вверх
} elseif ($s-$s_avg < -0.3) {
$d = -1; // вниз
} else {
$d = 0; // нет существенных изменений
}
}
$this->setProperty('direction', $d);
// *** Передать данные слинкованной комнате
$linked_room = $this->getProperty("LinkedRoom");
if ($linked_room) {
// Если НЕ задано (пустота, 0) свойство distance, то датчик считается главным, и его данные обязательно будут
// переданы объекту комнаты. Иначе будет проведен поиск других живых датчиков с более короткой дистанцией.
if (!$this->getProperty('distance')) {
setGlobal($linked_room.'.Temperature', $s);
} else {
// Получить id свойств для работы с базой данных. Свои id свойств этого класса я уже знаю.
$alive_pid = 49; //$this->getPropertyByName('alive', $this->class_id, $this->id);
$distance_pid = 647; //$this->getPropertyByName('distance', $this->class_id, $this->id);
$LinkedRoom_pid = 253; //$this->getPropertyByName('LinkedRoom', $this->class_id, $this->id);
/* Выбрать все записи свойств дистанции у объектов которых:
свойство $linked_room такое же как и у текущего объекта И
свойство $alive > 0 И
это не этот объект
*/
$sql = "
SELECT VALUE FROM pvalues WHERE PROPERTY_ID = $distance_pid
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = $LinkedRoom_pid AND VALUE = '$linked_room')
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = $alive_pid AND CAST(VALUE AS INT) > 0 )
AND OBJECT_ID <> $this->id
ORDER BY VALUE LIMIT 1
";
$rec = SQLSelectOne($sql);
// Если не найдено других живых датчиков с более короткой дистанцией
if (is_null($rec) || $this->getProperty('distance') <= $rec['VALUE']) {
setGlobal($linked_room.'.Temperature', $s);
sg('alerts_message', "Объекту $linked_room переданы данные с резервного датчика температуры $ot");
}
}
}Свойства класса:
Методы класса:
/* Общий код метода:
Установка статуса alive "Живой"
Запуск метода activate при первом отклике
*/
$reclog = 1; // Писать логи отладки ( 0-нет, 1-только крит, 2-все )
$ot = $this->object_title;
if ($reclog > 1) { debmes('Megad class log => incomingMessage method: received params '.serialize($params)); }
// Безусловная установка флага "Живой" т.к. метод был вызван самой мегой, или методом getData при успешном ответе
if ($this->getProperty('alive') <> 1) {
if ($reclog) { debmes('Megad class log => incomingMessage method: previous alive value 0. Received params '.serialize($params)); }
say("Мега $ot ответила",2);
$this->callMethod('activate');
}
$this->setProperty('alive', 1);// Expects 'output' and 'value' in $params
$reclog = 1; // Писать логи отладки ( 0-нет, 1-только крит, 2-все )
// Открывает лог если нужно
if ($reclog) { $log = getLogger($this); }
if (isset($params['command'])) {
$cmd = $params['command'];
} else {
$cmd = intval($params['port']).':'.intval($params['value']);
}
/*
$cmdUrl = sprintf('http://%s/%s/?cmd=%d:%d', $this->getProperty('IpAddress'), $this->getProperty('Password'),
intval($params['port']), intval($params['value']));
*/
$cmdUrl = sprintf('http://%s/%s/?cmd=%s', $this->getProperty('IpAddress'), $this->getProperty('Password'), $cmd);
// Запись данных в лог
if ($reclog == 2) {
$log->trace('setOutput method: '.$cmdUrl);
}
getURL($cmdUrl, 0);/* Варианты что можно спросить
callMethod('MegaD99.getData', array('port'=>'all')); // спросить сразу все.
callMethod('MegaD99.getData', array('port'=>0)); // состояние первого порта
callMethod('MegaD99.getData', array('port'=>'tget')); // показания встроенного температурного датчика (только для версии прошивки 3.25 и до 3.52 не вкл)
callMethod('MegaD99.getData', array('port'=>2, 'cmd'=>'list')); // получить массив 1WireBUS датчиков с порта 2
*/
$reclog = 1; // Писать логи отладки ( 0-нет, 1-только крит, 2-все )
$ot = $this->object_title;
// Проверка что есть ip адрес
if (!filter_var($this->getProperty('IpAddress'), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
if ($reclog) { debmes('Megad class error => ip address is not set for object '.$ot); }
return;
}
// Проверка что есть пароль
if (!$this->getProperty('Password')) {
if ($reclog) { debmes('Megad class error => Password is not set for object '.$ot); }
return;
}
// Сборка строки начала запроса для Меги
$cmdUrl = sprintf("http://%s/%s/", $this->getProperty('IpAddress'), $this->getProperty('Password'));
// Добавление дополнительных параметров запроса в зависимости от его типа
switch (strval($params['port'])) {
case 'tget': // Температура встроенного датчика
$cmdUrl .= '?tget=1';
$ta = 2;
break;
case 'all': // Спросить сразу все
$cmdUrl .= '?cmd=all';
$ta = 4; //Таймаут ожидания меги
break;
default: // Состояние указанного порта
//$cmdUrl .= sprintf("?pt=%d&cmd=get", intval($params['port']));
$cmdUrl .= '?pt='.intval($params['port']);
if (!isset($params['cmd'])) { $params['cmd']='get'; }
$cmdUrl .= '&cmd='.$params['cmd'];
$ta = 4;
}
// формирование массива параметров для запроса
$ctx = stream_context_create(array(
'http' => array('timeout'=>$ta)
)
);
// запрос данных у Меги
$dt = file_get_contents($cmdUrl, 0, $ctx);
// Повторный запрос при отсутствии ответа если была жива
if ($dt===false) {
if ($this->getProperty('alive')) {
//say("Повторный запрос у Меги $ot",gg(NightMode.status)?-1:0);
sg('alerts_message', "Повторный запрос у Меги $ot");
$dt = file_get_contents($cmdUrl, 0, $ctx);
}}
// При отсутствии ответа установить флаг "НеЖивой" и завершить работу
if ($dt===false) {
// ToThink установка неживой с задержкой. Убрать таймер если получили ответ
$this->setProperty('alive',0);
if ($reclog) { debmes("Megad class log => getData method: No response from $cmdUrl"); }
say("Мега $ot не отвечает",2);
sg('alerts_message', "Мега $ot не отвечает");
return;
}
// возможно были лишние пробелы. до проверки условия $dt===false удалять нельзя.
$dt = trim($dt);
// Запись данных в лог
if ($reclog > 1) { debmes(sprintf('Megad class log => getData method: %s returned %s', $cmdUrl, $dt)); }
// Обработка ответа в зависимости от его типа, и передача его в метод incomingMessage
// В методе incomingMessage безусловно будет установлен флаг "Живой" т.к. метод может быть вызван и самой мегой
switch (strval($params['port'])) {
// Температура внутреннего датчика
case 'tget':
if (strlen($dt)) {
// Проверить $dt на число и Записать в свойство объекта
// в 2561 мегах больше нет датчика температуры. Новые прошивки 328-х тоже больше не отвечают на tget
// поэтому периодическим опросом мег мы можем только убедиться, что она отвечает (живая)
if (is_numeric($dt)) {
//записать в свойство температуру мени если в ответе число
$this->setProperty('temperature', $dt);
} elseif (stripos($dt, 'MegaD-328') !== false) {
if ($reclog > 2) { debmes('Megad class log => getData method: Does not report temperature for object '.$ot); }
} elseif (stripos($dt, 'MegaD-2561') !== false) {
if ($reclog > 2) { debmes('Megad class log => getData method: Does not report temperature for object '.$ot); }
} else {
if ($reclog) { debmes('Megad class error => getData method: Failed to get data internal temperature sensor for object '.$ot); }
}
}
// Нужно вызнать родительский метод для установки флага живой
// в методах класса реакция на $params['port'] = 'tget' пропускается
// Запретить выполнение кода методов объектов никак
$this->callMethod('incomingMessage', array('pt'=>$params['port'], 'iasked'=>'ping'));
break;
/* Теперь ответ на запрос all отправляется как ответ на обычный порт
// Запустить метод incomingMessage с передачей всего ответа в параметре all
case 'all':
$this->callMethod('incomingMessage', array('all'=>$dt));
break;
*/
// Запустить метод incomingMessage с передачей параметров как есть в параметре 'iasked' с номером указанного порта в параметре 'pt'
default:
$this->callMethod('incomingMessage', array('pt'=>$params['port'], 'iasked'=>$dt));
}/* Варианты что можно спросить
callMethod('MegaD3.sendCommand', array('params'=>'pt=0&cmd=get&cnt=0')); // Сбросить счетчик импульсов.
*/
$reclog = 1; // Писать логи отладки ( 0-нет, 1-только крит, 2-все )
$ot = $this->object_title;
// Проверка что есть ip адрес
if (!filter_var($this->getProperty('IpAddress'), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
if ($reclog) { debmes('Megad class error => ip address is not set for object '.$ot); }
return;
}
// Проверка что есть пароль
if (!$this->getProperty('Password')) {
if ($reclog) { debmes('Megad class error => Password is not set for object '.$ot); }
return;
}
// Сборка строки начала запроса для Меги
$cmdUrl = sprintf("http://%s/%s/?%s", $this->getProperty('IpAddress'), $this->getProperty('Password'), strval($params['params']));
// запрос данных у Меги
$ta = 2; //секунд
$ctx = stream_context_create(array(
'http' => array('timeout'=>$ta)
)
);
$dt = trim(file_get_contents($cmdUrl, 0, $ctx));
// Живой или При отсутствии ответа установить флаг "НеЖивой"
// Запись данных в лог
if (isset($dt)) {
$this->setProperty('alive',1);
if ($reclog > 1) { debmes(sprintf('Megad class log => sendCommand method: %s returned %s', $cmdUrl, $dt)); }
} else {
$this->setProperty('alive',0);
if ($reclog) { debmes("Megad class log => sendCommand method: No response from $cmdUrl"); }
}$ot = $this->object_title;
say("Мега $ot включилась");Свойства класса:
Методы класса:
/* Объекты могут быть двух типов.
1 Переключатель - имеет только один настраиваемый метод modeChanged. Свойство Status указывает на режим.
2 Выключатель - имеет настраиваемые методы activate и deactivate. Свойство Status может быть = 0 или 1.
Оба типа существуют одновременно.
Для изменения вызов метода modeChanged с указанием параметра status; либо линком (установкой) status и вызовом modeChanged без папаметров.
Для типа Выключатель можно сразу просто вызывать методы activate и deactivate.
*/
$s=$params['status'];
if (isset($s)) {
// Записать в свойство объекта при его передаче в параметре
$this->setProperty('status',$s);
} else {
// Для слинкованных свойств наоборот взять значение из объекта
$s = $this->getProperty('status');
}
// Вызов метода
if ($s) {
$this->callMethod('activate');
} else {
$this->callMethod('deactivate');
}//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date('H:i'));
// Для типа Выключатель записать в свойство status единицу, если там был ноль
// Для типа Переключатель в этом методе нет смысла, но он всё равно будет вызван из общего кода метода,
// при этом в статусе полюбому будет что то отличное от нуля, и изменений не будет.
if (!$this->getProperty('status')) { $this->setProperty('status',1); }//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date('H:i'));
//Единственное возможное новое значение свойства status при вызове этого метода
$this->setProperty('status',0);Свойства класса:
Методы класса:
$status=$this->getProperty('status');
if ($status) {
$this->callMethod('turnOn');
} else {
$this->callMethod('turnOff');
}$status=$this->getProperty("status");
if ($status) {
$this->callMethod('turnOff');
} else {
$this->callMethod('turnOn');
}/*
Параметр onTime в секундах для включения на время.
Если у объекта задано свойство modeSwitch 0,1,3 то оно будет установлено на 3,
и по истечении времени установлено 0 и реле выключено методом turnOff.
Если 2 то по по истечении вызван метод logic.
Если modeSwitch не определеноЮ, то оно не будет изменено. По истечении метод turnOff.
Пример: callMethod('RelayFrontDoorOpen.turnOn', array('onTime'=>1));
*/
$this->setProperty('status', 1);
$m = $this->getProperty('modeSwitch');
// Передан параметр для включения на время onTime
if (array_key_exists('onTime', $params)) {
$ot = $this->object_title;
// Время по умолчанию
if (!$params['onTime']) { $params['onTime'] = 5; }
//$m=$this->getProperty('modeSwitch');
if (is_numeric($m)) {
// После выбора Time возврат на Off если было Off, On или Time
if (in_array($m, [0, 1, 3])) { $code="sg('$ot.modeSwitch', 0); cm('$ot.turnOff');"; }
// Возврат на Auto если было выбрано ранее
if ($m == 2) { $code="sg('$ot.modeSwitch', 2); cm('$ot.logic', array('status'=>0));"; }
$this->setProperty('modeSwitch', 3);
} else {
// Просто выключить если modeSwitch не был числом
$code="cm('$ot.turnOff');";
}
clearTimeOut($ot.'_nowork');
setTimeOut($ot.'_work', $code, $params['onTime']);
// Обычный вызов метода
} else {
if (is_numeric($m) && $m==0) {
$this->setProperty('modeSwitch', 1);
}
}
//$ot=$this->object_title;
$this->callMethod("turnOn");
//setTimeOut($ot."_click","cm('".$ot.".turnOff');",2);
$this->callMethod("turnOff");/*
вкл/выкл реле если modeSwitch число и = 0, 1, >=2 и существует таймер
При этом передать указания для отмены кода личного метода.
Родительский код вернет в ответе 3, если решение принято им на основании
modeSwitch, таймеров и предложения статуса; или вернет 2.
Код метода объекта перезапишет на 1, если он существует.
т.е. ответ логики:
3 - если modeSwitch = 0; 1; >=2 и есть таймер или (предлодение и нет личной логки)
2 - если нет логики объекта и родительский код не принял решение
1 - есть логика в объекте
Возможность отправить методу логики предложение вкл/выкл если modeSwitch >= 2
В большинстве случаев при этом нет надобности в создании логики метода у объекта.
Имя глобальной переменной доступно из всех методов, вызванных по цепочке
Важно если в коде метода объекта вызываются другие методы,
например рекомандация вкл/выкл реле
*/
global $do_not_execute_object_method_Relays;
$ms=$this->getProperty('modeSwitch');
if (is_numeric($ms)) {
if ($ms==0) { $f=0; }
elseif ($ms==1) { $f=1; }
elseif ($ms>=2) {
// вкл/выкл при существовании таймера
if (timeOutExists($this->object_title.'_nowork')) { $f=0; }
elseif (timeOutExists($this->object_title.'_work')) { $f=1; }
// вкл/выкл при существовании рекомендации и отсутствии личной логики объекта
elseif (isset($params['status'])) {
$om = SQLSelectOne("SELECT ID FROM methods WHERE TITLE='logic' AND OBJECT_ID=".$this->id);
if (!$om) {
if ($params['status']) { $f=1; } else { $f=0; }
//debmes('у объекта ' . $this->object_title . ' нет метода логики', 'test');
}
}
}
}
if (isset($f)) {
// переключить реле
$s=$this->getProperty('status');
if ($f>$s) { $this->callMethod('turnOn'); }
if ($f<$s) { $this->callMethod('turnOff'); }
// запретить выполнение кода метода объекта
$do_not_execute_object_method_Relays=true;
return 3;
} else {
// решение на усмотрение метода объекта при его наличии
$do_not_execute_object_method_Relays=false;
return 2;
// если метод объекта есть, он перезапишет на 1
// стоит обратить внимание, что echo в коде метода добавляет текст в начало ответа
}$this->setProperty('status', 0);
if ($this->getProperty('modeSwitch') == 1) {
$this->setProperty('modeSwitch', 0);
}Свойства класса:
Методы класса:
/* Активность будет регистрироваться каждый раз при срабатывании датчика
Для уменьшения числа срабатываний можно сравнивать $latestActivity с time()
На сценах можно использовать условие time() - LatestActivity <= 10 секунд например
*/
$latestActivity=$this->getProperty('LatestActivity');
$this->setProperty('LatestActivity',time());
$this->setProperty('LatestActivityTime',date('H:i'));
$ot=$this->object_title;
global $do_not_execute_object_method_onActivity;
/* Установить активность в комнате */
// Передать источник события вместо 1 ToDo НА ДИКИЙ ТЕСТ!!!
$source = 1;
if (isset($params['source'])) { $source = $params['source']; }
$prev_SomebodyHere = $this->getProperty('SomebodyHere');
$this->setProperty('SomebodyHere', $source);
/*** КАЖДЫЙ раз при подтверждении активности ***/
/* Установить (отодвинуть) таймер активности в комнате.
Свойство объекта комнаты класса Rooms может быть не задано вовсе,
тогда таймаут активности будет принят как 10 минут.
Задано простым числом, или задано последовательностью из 5 чисел,
разделенных ; для разных режимов работы энергопотребления
*/
$idl = $this->getProperty("IdleDelay");
if (strpos($idl, ';')) {
$activity_timeout=explode(";", $idl);
$activity_timeout= $activity_timeout[(int)gg('EconomMode.status')+2];
} elseif ($idl) {
$activity_timeout=(int)$idl;
} else {
$activity_timeout=10*60;
}
// умножить таймер на множитель, если был передан в параметре
// используеься для запуска половины времени таймера, нарпимер.
if (isset($params['activity_timeout_factor'])) {
$activity_timeout = round($activity_timeout * $params['activity_timeout_factor']);
//debmes($ot . '.onActivity вызов со множителем ' . $params['activity_timeout_factor'] . ' activity_timeout=' . $activity_timeout, 'test');
// Запустить таймер, если он не существует (меньше)
if (timeoutresidue($ot.'_activity_timeout') < $activity_timeout) {
setTimeOut($ot.'_activity_timeout', "callMethod('$ot.onIdle');", $activity_timeout);
}
} else {
// Запустить таймер
setTimeOut($ot.'_activity_timeout', "callMethod('$ot.onIdle');", $activity_timeout);
}
// блокировка повторных вызовов после выполнения первой активности
if ($prev_SomebodyHere) {
$do_not_execute_object_method_onActivity=true;
return;
} else {
$do_not_execute_object_method_onActivity=false;
}
/*** ДАЛЕЕ только при первой активности ***/
/* В свойстве msAlarmLeven нужно указать цифры соответствующих режимов на которые будет реагировать объект комнаты
Группа условий сработает на первой максимальной цифре, указанной в свойстве msAlarmLeven.
К примеру при GuardMode.status=3 и msAlarmLeven = 12, стаботает группа 2, и выполнение кода закончится.
GuardMode.status=2 и msAlarmLeven = 12, стаботает группа 2, и выполнение кода закончится.
GuardMode.status=1 и msAlarmLeven = 12, стаботает группа 1.
GuardMode.status=3 и msAlarmLeven = 3, стаботает группа 3. Других вариантов срабатывания нет.
msAlarmLeven:
0- Пищалка
1- Сообщение о движении только в чате
2- Чат и голос
3- Тревога
GuardMode.status:
0- Отключить все уведомления и сообщения (в данный момент к выбору не предложено, но технически возвожно)
1- Снят с охраны
2- Наблюдение за перриметром
3- Охрана объекта
*/
$al = $this->getProperty('msAlarmLeven');
// Обратите внимание на break; Он сработает только если выполенно условие if. Иначе выполнение кода групп case продолжится.
switch (gg('GuardMode.status')) {
case 3: /*** добавить тревогу security в свойство общих тревог и вызвать сценарий ***/
if (strpos($al, '3') !== false) {
// получить строку общих тревог
$gal = getGlobal('globalAlarms');
$gal_old = $gal;
// сценарий - функция для внесения изменений в строку тревог
$gal = runscript('editJson', array('key'=>'security', 'val'=>$this->id, 'js'=>$gal));
// вызвать сценарий с передачей параметра
if ($gal_old != $gal) { runScript('generalAlarms', array('alarms'=>$gal)); }
break;
}
case 2: /*** кричалка при движении в режиме охраны периметра ***/
if (strpos($al, '2') !== false) {
say ('Внимание, активность '.$this->getProperty('inRoomText'), (gg('GuestsMode.status'))?2:3);
break;
}
case 1:
if (strpos($al, '1') !== false) {
// Написать в чат
say('Активность '.$this->getProperty("inRoomText"), -1);
}
if (strpos($al, '0') !== false) {
// Пищалка при активности. В папке sounds должен быть wav файл с именем объекта класса ROOMS
// если у объекта присутствует 0 в свойстве msAlarmLeven
playSound($ot.'.wav');
}
}
/* Декативировать режим "Никого нет"
В этом методе возможна только деактивация режима
Решение об активации режима будет принято в методе onIdle после перебора всех комнат
*/
switch ($this->location_id) {
case 1:
if (gg('NobodyHomeMode.status')) {
debmes('RVC => ROOMS-onActivity => Активность '.$this->getProperty("inRoomText"). '. Деактивация режима');
cm('NobodyHomeMode.deactivate');
}
break;
case 2:
if (gg('NobodyBathMode.status')) {
debmes('RVC => ROOMS-onActivity => Активность '.$this->getProperty("inRoomText"). '. Деактивация режима');
cm('NobodyBathMode.deactivate');
}
break;
}$ot=$this->object_title;
global $do_not_execute_object_method_onIdle;
/* БЛОКИРОВКА выполнения личного кода метода, если существует таймер или есть активный статусный датчик */
$rec = null;
if (timeoutexists($ot."_activity_timeout")) {
/*
Существует таймер активности в комнате.
Ситуация происходит когда статусный датчик присылает 0 и пробует снять активность в комнате,
но существует таймер активности, запущенный импульсным датчиком
*/
$rec = true;
} else {
/*
У импульсных датчиков не должно быть параметра status. При срабатывании они, например, вызывают метод motionDetected подкласса MovementSensors.
Что приведет к вызову метода onActivity в комнате и запуску таймера для onIdle
Статусные датчики при срабатывании устанавливают параметр status 1 и при потере движения 0, вызывая метод statusChanged, либо вызов метода сразу с параметром status.
При 1 вызывается onActivity. Таймер при этом можно не запускать, чтобы не выполнять лишние действия, он просто не нужен.
При 0 вызывается onIdle, но...
В методе onIdle идет запрос всех слинкованных с комнатой датчиков, у которых status = 1, (да ещё и живых). Если список не пустой, то прервать выполнение метода.
*/
// 49-alive 51-status 246-LinkedRoom
$sql = "
SELECT ID FROM pvalues WHERE
OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = 49 AND CAST(VALUE AS INT) > 0)
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = 51 AND CAST(VALUE AS INT) > 0)
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = 246 AND VALUE = '$ot')
";
$rec = SQLSelectOne($sql);
}
// Прервать выполнение если существуют слинкованные живые датчики со status=1. У импульсных не должно быть свойства status.
// Это означает что в дальнейшем этот метод будет вызван снова, когда с датчика придет 0
if (!is_null($rec)) {
//say("В $ot Есть статусные датчики",1);
$do_not_execute_object_method_onIdle=true;
return;
} else {
$do_not_execute_object_method_onIdle=false;
}
/* ДАЛЬНЕЙШЕЕ выполнение кода */
$this->setProperty('SomebodyHere',0);
// Определяем метод по лакации
// 2-баня 1-дом
$location_id = $this->location_id;
switch ($location_id) {
case 1: $m = 'NobodyHomeMode'; break;
case 2: $m = 'NobodyBathMode'; break;
default: $m = 0;
}
if ($m) {
// *** Получить всех гостей ***
/* WHERE PROPERTY_ID = 124 id свойстви TITLE например для получения названия.
В данном случае нам всё равно, и нужен только факт есть хоть какаянибудь комната или нет.
Поэтому в ответе будут все свойства выбранных объектов.
Ограничим вывод только ID, т.к. нам и тут всё равно.
Используем SQLSelectOne, список нам не нужен.
*/
// 61-SomebodyHere 25-ROOMS
$sql = "
SELECT ID FROM pvalues WHERE
OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = 61 AND value is not null and value <> '0' and value <> '' )
AND OBJECT_ID IN ( SELECT ID FROM objects WHERE CLASS_ID = 25 AND LOCATION_ID = $location_id )
";
$rec = SQLSelectOne($sql);
/* Условие активации режима никого нет в локации.
проверка статуса режима не должна быть нужна,
т.к. до этого комната была активной,
и сделовательно была общая активность в локации
*/
if (is_null($rec)) {
cm("$m.activate");
}
}$al = $params['Alarms'];
if (isset($al)) {
// Записать в свойство объекта
$this->setProperty('Alarms',$al);
} else {
// Для слинкованных свойств и запуска этого метода без передачи данных,
$al = $this->getProperty('Alarms');
}
//$al - тревоги комнаты $alarms - общие
$alarms = getGlobal('globalAlarms');
$alarms_old = $alarms;
$alarmsKeys = (array)array_keys(json_decode($alarms, true));
$alKeys = (array)array_keys(json_decode($al, true));
/*
callMethod('as_drivewayArea_freeze1.statusChanged', array('status'=>1));
1.1 вычесть из ключей глобала ключи комнаты
1.2 попытаться удалить из ключей глобала эту разничу т.е. всё что нет у нас, но с нашим id
2 просто добавить в глобал все что у нас есть c нашим id
*/
/* сценарий - функция для внесения изменений с строку тревог */
$alarms = runscript('editJson', array('key'=>array_values(array_diff($alarmsKeys, $alKeys)), 'val'=>$this->id, 'js'=>$alarms, 'add'=>0));
$alarms = runscript('editJson', array('key'=>$alKeys, 'val'=>$this->id, 'js'=>$alarms, 'add'=>1));
//debMes("тревоги комнаты $al общие было $alarms_old общие стало $alarms");
/* записать в общее свойство тревоги и вызвать сценарий */
if ($alarms_old != $alarms) {
// setGlobal('globalAlarms', $alarms);
runScript('generalAlarms', array('alarms'=>$alarms));
}Свойства класса:
Методы класса:
Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SDevices_setUpdatedText.php');
/* end injection of {SDevices} */require(DIR_MODULES.'devices/SDevices_logicAction.php');
require(DIR_MODULES.'devices/SDevices_statusUpdated.php');
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SDevices_keepAlive.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
require(DIR_MODULES.'devices/SButtons_pressed.php');
Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SCameras_motionDetected.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SCameras_updatePreview.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SCameras_takeSnapshot.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SCameras_takeSeries.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
require(DIR_MODULES.'devices/SControllers_turnOn.php');
require(DIR_MODULES.'devices/SControllers_turnOff.php');
require(DIR_MODULES.'devices/SControllers_switch.php');
Свойства класса:
Методы класса:
require(DIR_MODULES.'devices/SDimmers_levelUpdated.php');
require(DIR_MODULES.'devices/SDimmers_turnOn.php');
require(DIR_MODULES.'devices/SDimmers_turnOff.php');
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SDimmers_setLevel.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SDimmers_statusUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SDimmers_levelWorkUpdated.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SGroups_turnOn.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SGroups_statusUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SGroups_switch.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SGroups_turnOff.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SRGB_colorUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SRGB_setColor.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SRGB_turnOn.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SRGB_turnOff.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_setTargetTemperature.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_valueUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_statusUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_tempUp.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_tempDown.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_switchEnable.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_enable.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
//require(DIR_MODULES.'devices/SThermostats_disable.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_turnOn.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SThermostats_turnOff.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SCounters_valueUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SCounters_valueWorkUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SCounters_refreshStats.php');
/* end injection of {SDevices} */Свойства класса:
Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SLeak_statusUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SLeak_alert.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SLeak_blockSensor.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SLeak_unblockSensor.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
require(DIR_MODULES.'devices/SMotions_motionDetected.php');
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SMotions_blockSensor.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SMotions_unblockSensor.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SOpenable_statusUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SOpenable_switch.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SOpenable_open.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SOpenable_close.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
require(DIR_MODULES.'devices/SOpenClose_statusUpdated.php');
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SOpenClose_blockSensor.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SOpenClose_unblockSensor.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
require(DIR_MODULES.'devices/SSensors_valueUpdated.php');
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SSensors_alert.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SSensors_blockSensor.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SSensors_unblockSensor.php');
/* end injection of {SDevices} */Свойства класса:
Свойства класса:
Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SPowerSensors_valueUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SPowerSensors_loadStatusChanged.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
/* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SSmoke_statusUpdated.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SSmoke_alert.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SSmoke_blockSensor.php');
/* end injection of {SDevices} *//* begin injection of {SDevices} */
require(DIR_MODULES.'devices/SSmoke_unblockSensor.php');
/* end injection of {SDevices} */Свойства класса:
Методы класса:
Свойства класса:
Методы класса:
/* Расчет целевой температуры воздуха в зависимости от времени суток
В результате записывается свойство с историей airRequiredTemp
для построения графика и контроля достижения заданной температуры;
и свойство без истории airShiftTemp со сдвигом по свойству timeShift
для расчета температуры подачи с учетом инерции системы.
При изменении будет вызван метод waterCalculate
Свойство airFunc должно быть задано массивом, иначе выполнение будет прервано.
*/
$ot=$this->object_title;
if (defined('THRM_LOG_LEVEL') && THRM_LOG_LEVEL != '') { $log_level = THRM_LOG_LEVEL; } else { $log_level = 0; }
if ($log_level>1) { DebMes("$ot.$name Start Called " . mb_substr($source, 0, 50) . '...','thrm'); }
// Аборт
$airFunc=$this->getProperty('airFunc');
if (empty($airFunc)) {
if ($log_level>1) { DebMes("$ot.airCalculate Не задана airFunc",'thrm'); }
return;
}
// Преобразовать строку в массив. ToDo использовать регулярку
$arrTemp=explode(' ', $airFunc);
// Проверить корректность массива температур. ToDo использовать регулярку
if (count($arrTemp)<>24) {
if ($log_level>0) { DebMes("$ot.airCalculate ИСКЛЮЧЕНИЕ в методе! Не корректный массив в свойстве airFunc",'thrm'); }
return;
}
$h=(int)date('G',time());
$m=date('i',time());
$airRequiredTemp=(float)$this->getProperty('airRequiredTemp');
$airShiftTemp=(float)$this->getProperty('airShiftTemp');
// Получить значение температуры текущего часа
$t_desire=$arrTemp[$h];
// следующий элемент массива
$hn=$h+1;
if ($hn>23) {$hn-=24;}
// пропорционально изменить на разницу значения следующего часа
$t_desire+=($arrTemp[$hn]-$arrTemp[$h])*$m/60;
$t_desire=round($t_desire, 1);
// airRequiredTemp используется в основном для построения графиков
// и показа желаемого значения температуры на элементах термостатов
if ($airRequiredTemp <> $t_desire) {
if ($log_level>1) { DebMes("$ot.airCalculate уст. t текущего часа $arrTemp[$h], следующего часа $arrTemp[$hn]",'thrm'); }
if ($log_level>0) { DebMes("$ot.airCalculate целевая температура воздуха $t_desire",'thrm'); }
$airRequiredTemp = $t_desire;
$this->setProperty('airRequiredTemp', $airRequiredTemp);
} else {
if ($log_level>1) { DebMes("$ot.airCalculate Целевая этого часа не извенилась",'thrm'); }
}
// Смотреть в будущее чтобы успеть по причине инерционности системы
$h += (int)$this->getProperty('timeShift');
if ($h>23) {$h-=24;}
// Получить значение температуры будущего часа
$t_desire=$arrTemp[$h];
// следующий элемент массива
$hn=$h+1;
if ($hn>23) {$hn-=24;}
// пропорционально изменить на разницу значения следующего часа
$t_desire+=($arrTemp[$hn]-$arrTemp[$h])*$m/60;
$t_desire=round($t_desire, 1);
if ($airShiftTemp <> $t_desire) {
if ($log_level>1) { DebMes("$ot.airCalculate уст. t будущего часа $arrTemp[$h], следующего часа $arrTemp[$hn]",'thrm'); }
if ($log_level>0) { DebMes("$ot.airCalculate Требуемая будущая температура $t_desire",'thrm'); }
$airShiftTemp = $t_desire;
$this->setProperty('airShiftTemp', $airShiftTemp);
$this->setProperty('log', 'расчет t воздуха');
$this->callMethod('waterCalculate', array('airRequiredTemp'=>$airRequiredTemp, 'airShiftTemp'=>$airShiftTemp));
} else {
if ($log_level>1) { DebMes("$ot.airCalculate Целевая будущего часа не извенилась",'thrm'); }
}/* Расчет требуемой температуры подачи по ПЗА
Учитывается уличная температура, скорость ветра, яркость солнца
Многие коэффициенты влияния этих факторов указаны в коде
*/
$ot=$this->object_title;
if (defined('THRM_LOG_LEVEL') && THRM_LOG_LEVEL != '') { $log_level = THRM_LOG_LEVEL; } else { $log_level = 0; }
if ($log_level>1) { DebMes("$ot.$name Start Called $source",'thrm'); }
/* *** Сбор данных *** */
// При вызове метода после изменения свойства, его значение будет передано в массиве. В данном методе это не должно случиться. Код оставлен как шаблон.
if (isset($params['PROPERTY'])) {
// Прекратить выполнение если данные не изменились
if ($params['NEW_VALUE'] == $params['OLD_VALUE']) {
if ($log_level>1) {DebMes("$ot.waterCalculate вызван свойством ".$params['PROPERTY']. " и получил одинаковые значения ".$params['NEW_VALUE']." Выполнение прервано",'thrm');}
return;
}
// Составить список всех переменных (одну)
list($params['PROPERTY']) = array($params['NEW_VALUE']);
}
// создать переменные из массива
// Если переменная с таким именем существует, её текущее значение не будет перезаписано.
extract($params, EXTR_SKIP);
if (!isset($airRequiredTemp)) { $airRequiredTemp=$this->getProperty('airRequiredTemp'); }
if (!isset($k1)) { $k1 = $this->getProperty('k1'); }
if (!isset($k2)) { $k2 = $this->getProperty('k2'); }
// ВНИМАНИЕ данные берутся с других объектов
if (!isset($t_outside)) { $t_outside = gg('weather_now.temperature'); }
if (!isset($windSpeed)) { $windSpeed = gg('weather_now.windSpeed'); }
if (!isset($Luminiscence)) { $Luminiscence = gg('DrivewayArea.Luminiscence'); }
// *** формат данных и значения по умолчанию
if (is_numeric($airRequiredTemp)) { $airRequiredTemp = (float)$airRequiredTemp; } else { $airRequiredTemp = null; }
if (is_numeric($k1)) { $k1 = (float)$k1; } else { $k1 = 0.6; }
if (is_numeric($k2)) { $k2 = (float)$k2; } else { $k2 = 0.6; }
if (is_numeric($t_outside)) { $t_outside = (int)$t_outside; } else { $t_outside = null; }
if (is_numeric($windSpeed)) { $windSpeed = (float)$windSpeed; } else { $windSpeed = null; }
if (is_numeric($Luminiscence)) { $Luminiscence = (int)$Luminiscence; } else { $Luminiscence = null; }
// Вертикальное поднятие кривой вверх. При отсутствии берется для 20 градусов по классике
if ($airRequiredTemp) { $t_air = $airRequiredTemp; } else { $t_air = 20; }
// В начале примет подачу как значение воздуха.
$Tp = $t_air;
/* Старый вариант расчета с типовыми коэффициентами k1=1.2 k2=20
// Рассчитать изгиб кривой
$Tp = sqrt((20-$t)*$k1)*10;
if (!isset($params['t_outside']) && $log_level>1) { DebMes("$ot.pzaCalculate Изгиб кривой $Tp",'thrm'); }
// При увеличении желаемой комнатной температуры на 1°C кривая традиционно смещается на 5°C:
$Tp = $Tp + ($k2-20)*5;
if (!isset($params['t_outside']) && $log_level>1) { DebMes("$ot.pzaCalculate Смещение кривой $Tp",'thrm'); }
*/
/* Рассчитать изгиб кривой по формуле 0.3*sqrt((20-x))*7 + 0.7*(20-x) + 20
коэффициенты k1 + k2 дают классическую кривую. k1 влияет на резкий подъем, k2 дает линейную зависимость
вертикальный побъем кривой обеспечивает $airRequiredTemp. Если не задано то считается как 20
*/
if (!is_null($t_outside)) {
// можно использовать кубический корень и добавить режим охлаждения. Пока мне это не нужно.
if ($t_air > $t_outside ) {
$Tp = round( $k1*sqrt($t_air-$t_outside)*7 + $k2*($t_air-$t_outside) + $t_air, 2 );
}
if ($log_level>0) { DebMes("$ot.pzaCalculate t по холодной кривой $Tp",'thrm'); }
if (isset($params['log'])) { echo "Расчет по холодной кривой $Tp <br>"; }
}
/* Правка на коррекцию
В данный момент корректировка включена для всех термостатов
*/
//if ($ot == 'thrm_beta') {
$pazSrt = gg('pzaStr');
if ($pazSrt) { $pzaArr=explode(' ', $pazSrt); } else { $pzaArr=[]; }
// проверка массива
if (count($pzaArr) == 50) {
$corrective = $pzaArr[20-$t_outside];
$Tp += $corrective;
if ($log_level>1) { DebMes("$ot.pzaCalculate Коррекция $corrective",'thrm'); }
if (isset($params['log'])) { echo "Коррекция $corrective <br>"; }
}
//}
/* Правка на ветер
<3 Слабый <6 Сильный <9 Очень сильный Иначе Шквальный
поправку вносим из расчета 0- ничего, 10 м*с - 20%
*/
if (!is_null($windSpeed) && !isset($params['justcount'])) {
$corrective = round( $Tp*$windSpeed*2/100, 2 ); //2 - коэффициент соответствия скорости к процентам
$Tp += $corrective;
if ($log_level>1) { DebMes("$ot.pzaCalculate Поправка на ветер $corrective",'thrm'); }
if (isset($params['log'])) { echo "Поправка на ветер $corrective <br>"; }
}
/* Правка на солнце
Освещенность у меня наблюдается от 0 до 600 пунктов
поправку вносим из расчета 1 процент с каждой сотни света
*/
if (!is_null($Luminiscence) && !isset($params['justcount'])) {
$corrective = -round( $Tp*$Luminiscence/100/100, 2 );
$Tp += $corrective;
if ($log_level>1) { DebMes("$ot.pzaCalculate Поправка на солнце $corrective",'thrm'); }
if (isset($params['log'])) { echo "Поправка на солнце $corrective <br>"; }
}
/* Правка по истории уличной t
Долговременное воздействии уличной t на стены здания вызывает необходимость коррекции t подачи.
Для упрощения будем только увеличивать подачу, учитывая этот момент при первоначальном задании кривой.
т.к. 0 градусов это просто условность шкалы, то из t улицы вычтем 20 и поменяем знак на +
получится коэффициент от 0 до 50. Чем он выше, тем больше будет корректировка.
Возьмем среднюю t улицы на последние два дня (48 часов)
*/
// средние значения температуры за последние 2 дня (максимальная глубина истории weather_now)
if (!isset($params['justcount'])) {
$t_avg = getHistoryAvg('weather_now.temperature', time() - 1*24*60*60);
if (is_numeric($t_avg)) {
$percent = max(0, -($t_avg - 20)) ** 1.6 / 35;
$corrective = round($Tp * $percent / 100, 2);
$Tp += $corrective;
if ($log_level>1) { DebMes("$ot.pzaCalculate Поправка на холодные стены $corrective",'thrm'); }
if (isset($params['log'])) { echo "История t улицы " . round($t_avg). " Правка на " . round($percent) . "% <br>"; }
if (isset($params['log'])) { echo "Поправка на холодные стены $corrective <br>"; }
}
}
// *** Округлить до целого числа
$Tp = round($Tp);
if ($log_level>0) { DebMes("$ot.pzaCalculate Итоговая t по ПЗА $Tp",'thrm'); }
if (isset($params['log'])) { echo "На запрос уличной $t_outside ответ $Tp <br>"; }
// *** Итоговые действия
if (isset($params['justcount'])) {
// Возврат для графиков℃
return($Tp);
} else {
// установка свойства и запуск метода
$pzaTemp = $this->getProperty('pzaTemp');
if ($pzaTemp <> $Tp) {
$pzaTemp = $Tp;
$this->setProperty('pzaTemp', $pzaTemp);
$this->setProperty('log', 'расчет t ПЗА');
$this->callMethod('waterCalculate', array('pzaTemp'=>$pzaTemp, 'airRequiredTemp'=>$airRequiredTemp));
}
}/* Расчет температуры подачи
если фактическая температура воздуха +3 <= заблаговременной расчетной
т.е. запаздываем на 3 градуса, то берем максимальную температуру подачи из ПЗА.
иначе если температура воздуха +1 <= заблаговременной расчетной
т.е. меньше заданной на 1 градус, то берем температуру по ПЗА
иначе при приближении к заблаговременной температуре воздуха,
начинаем уменьшать t подачи
*/
$ot=$this->object_title;
if (defined('THRM_LOG_LEVEL') && THRM_LOG_LEVEL != '') { $log_level = THRM_LOG_LEVEL; } else { $log_level = 0; }
if ($log_level>1) { DebMes("$ot.$name Start Called " . mb_substr($source, 0, 50) . '...','thrm'); }
/* *** Сбор данных *** */
// При вызове метода после изменения свойства, его значение будет передано в массиве
if (isset($params['PROPERTY'])) {
// Прекратить выполнение если данные не изменились
if ($params['NEW_VALUE'] == $params['OLD_VALUE']) {
if ($log_level>1) {DebMes("$ot.waterCalculate значение ".$params['PROPERTY']. " не изменилось",'thrm');}
return;
}
// Составить список всех переменных (одну)
list($params['PROPERTY']) = array($params['NEW_VALUE']);
}
// создать переменные из массива
// Если переменная с таким именем существует, её текущее значение не будет перезаписано.
extract($params, EXTR_SKIP);
// Воздух
if (!isset($airCurrentTemp)) { $airCurrentTemp = $this->getProperty('airCurrentTemp'); }
if (!isset($airRequiredTemp)) { $airRequiredTemp = $this->getProperty('airRequiredTemp'); }
if (!isset($airShiftTemp)) { $airShiftTemp = $this->getProperty('airShiftTemp'); }
if (!isset($hysteresis)) { $hysteresis = $this->getProperty('hysteresis'); }
if (!isset($pzaTemp)) { $pzaTemp = $this->getProperty('pzaTemp'); }
// Вода
if (!isset($waterRequiredTemp)) { $waterRequiredTemp = $this->getProperty('waterRequiredTemp'); }
if (!isset($waterMaxTemp)) { $waterMaxTemp = $this->getProperty('waterMaxTemp'); }
if (!isset($waterMinTemp)) { $waterMinTemp = $this->getProperty('waterMinTemp'); }
// *** формат данных и значения по умолчанию
if (is_numeric($airCurrentTemp)) { $airCurrentTemp = (float)$airCurrentTemp; } else { $airCurrentTemp = null; }
if (is_numeric($airRequiredTemp)) { $airRequiredTemp = (float)$airRequiredTemp; } else { $airRequiredTemp = null; }
if (is_numeric($airShiftTemp)) { $airShiftTemp = (float)$airShiftTemp; } else { $airShiftTemp = $airRequiredTemp; } // !
if (is_numeric($hysteresis)) { $hysteresis = (float)$hysteresis; } else { $hysteresis = 0.2; }
if (is_numeric($pzaTemp)) { $pzaTemp = (int)$pzaTemp; } else { $pzaTemp = null; }
if (is_numeric($waterRequiredTemp)) { $waterRequiredTemp = (int)$waterRequiredTemp; } else { $waterRequiredTemp = null; }
if (is_numeric($waterMaxTemp)) { $waterMaxTemp = (int)$waterMaxTemp; } else { $waterMaxTemp = 85; }
if (is_numeric($waterMinTemp)) { $waterMinTemp = (int)$waterMinTemp; } else { $waterMinTemp = 10; }
if (is_null($airCurrentTemp) || is_null($airShiftTemp)) {
$t = 'Нет air данных. t подачи по ПЗА';
$wrt = $pzaTemp;
}
elseif ($airCurrentTemp + 3 <= $airShiftTemp) {
$t = 'Сильно отстаём. максимальная t подачи из ПЗА';
$wrt = (int)$this->callMethod('pzaCalculate', array('t_outside'=>-30, 'option'=>'tm'));
}
elseif ($airCurrentTemp + 0.6 <= $airShiftTemp) {
$t = 'В пределах нормы. t подачи по ПЗА';
$wrt = $pzaTemp;
}
else {
$t = 'Коррекция t при приближении к целевой';
// 10% от температуры ПЗА * коэффициент приближения
// коррекция идет по логарифмической шкале (третья степень)
$wrt = $pzaTemp;
$wrt -= $pzaTemp*10/100 * min(max((1-$airShiftTemp+$airCurrentTemp)**3,0),2);
$wrt = round($wrt);
}
// предельные температуры подачи
$wrt = max($wrt, $waterMinTemp);
$wrt = min($wrt, $waterMaxTemp);
if ($log_level>0) { DebMes("$ot.waterCalculate $t $wrt",'thrm'); }
if ($waterRequiredTemp <> $wrt || 1) {
$waterRequiredTemp = $wrt;
$this->setProperty('waterRequiredTemp', $waterRequiredTemp);
$this->setProperty('log', 'расчет t подачи');
/* $arr=[];
$arr['airCurrentTemp'] = $airCurrentTemp;
$arr['airRequiredTemp'] = $airRequiredTemp;
$arr['airShiftTemp'] = $airShiftTemp;
$arr['hysteresis'] = $hysteresis;
$arr['pzaTemp'] = $pzaTemp;
$arr['waterRequiredTemp'] = $waterRequiredTemp;
$arr['waterMaxTemp'] = $waterMaxTemp;
$arr['waterMinTemp'] = $waterMinTemp;
*/
$arr = compact('airCurrentTemp','airRequiredTemp','airShiftTemp',
'hysteresis','pzaTemp',
'waterRequiredTemp','waterMaxTemp','waterMinTemp');
// Запуск исполняющих методов
$answers = $this->callMethod('workDecision', $arr);
//DebMes("$ot.waterCalculate метод workDecision ОТВЕТИЛ ".serialize($answers),'thrm');
// Передача целевой. Сервопривод? ToDo
if (isset($answers['status']) && $answers['status'] > 0 ) {
$this->callMethod('setTemperature', array('waterRequiredTemp'=>$waterRequiredTemp));
//$this->callMethod('positionServo', $arr); // ToDo определиться после монтажа
}
}// Вызывается когда меняется текущая или расчетная температура подачи,
// передает другому объекту или агрегату расчетную температуру подачи.
$ot=$this->object_title;
if (defined('THRM_LOG_LEVEL') && THRM_LOG_LEVEL != '') { $log_level = THRM_LOG_LEVEL; } else { $log_level = 0; }
if ($log_level>1) { DebMes("$ot.$name Start Called $source",'thrm'); }
$this->setProperty('log', 'установка t');
/* Принимает решение о работе котла или насоса, на основе текущей и требуемой температуры воздуха
Запускается из метода airCalculate, а так же может быть вызван при необходимости проверки решения
о работе котла из других элементов системы
*/
$ot=$this->object_title;
if (defined('THRM_LOG_LEVEL') && THRM_LOG_LEVEL != '') { $log_level = THRM_LOG_LEVEL; } else { $log_level = 0; }
if ($log_level>1) { DebMes("$ot.$name Start Called " . mb_substr($source, 0, 50) . '...','thrm'); }
// Не выполнять логику если установлен ручной режим
if (!$this->getProperty('auto')) {
if ($log_level>0) { DebMes("$ot.workDecision режим auto не выбран",'thrm'); }
return;
}
/* *** Сбор данных *** */
// При вызове метода после изменения свойства, его значение будет передано в массиве
if (isset($params['PROPERTY'])) {
// Прекратить выполнение если данные не изменились
if ($params['NEW_VALUE'] == $params['OLD_VALUE']) {
if ($log_level>1) {DebMes("$ot.workDecision значение " . $params['PROPERTY'] . " не изменилось",'thrm');}
return;
}
// Составить список всех переменных (одну)
list($params['PROPERTY']) = array($params['NEW_VALUE']);
}
// создать переменные из массива
// Если переменная с таким именем существует, её текущее значение не будет перезаписано.
extract($params, EXTR_SKIP);
// *** Воздух
if (!isset($airCurrentTemp)) { $airCurrentTemp=$this->getProperty('airCurrentTemp'); }
if (!isset($airRequiredTemp)) { $airRequiredTemp=$this->getProperty('airRequiredTemp'); }
if (!isset($airShiftTemp)) { $airShiftTemp=$this->getProperty('airShiftTemp'); }
if (!isset($hysteresis)) { $hysteresis=$this->getProperty('hysteresis'); }
// *** Вода
if (!isset($waterCurrentTemp)) { $waterCurrentTemp=$this->getProperty('waterCurrentTemp'); }
if (!isset($waterRequiredTemp)) { $waterRequiredTemp=$this->getProperty('waterRequiredTemp'); }
if (!isset($waterReturnTemp)) { $waterReturnTemp=$this->getProperty('waterReturnTemp'); }
if (!isset($waterMaxTemp)) { $waterMaxTemp=$this->getProperty('waterMaxTemp'); }
if (!isset($waterMinTemp)) { $waterMinTemp=$this->getProperty('waterMinTemp'); }
/* *** Разрешения
Получить значение метода, запрещающего работу. В некоторых ситуациях необходимо запретить работу.
Например, в данный момент у нас работает бойлер нагрева горячей воды,
и предел допустимой мощности не позвоняет включить электрический.
Либо будут открыты ворота, и нужно заранее повысить температуру.
Методы в МД возвращают 1. В ответе метода число с цифрами ступеней будет прибавлено к этой единице.
Например: ответ 1: 1-1=0 ничего; ответ 2: 2-1=1 первая ступень; ответ 24: 24-1=23 вторая и третья
*/
$mayBanOn = intval($this->callmethod('mayBanOn'))-1;
$mayResolve = intval($this->callmethod('mayResolve'))-1;
// запрет по таймерам на вкл/выкл в т.ч. быстрое изменение мощности ступеней.
$timeWork = false; $timeNoWork = false;
if (timeOutExists($ot.'_work')) { $timeWork = true; }
if (timeOutExists($ot.'_nowork')) { $timeNoWork = true; }
// *** текущий статус работы. Количество работающих ступеней.
$status = (int)$this->getProperty('status');
//$arr_status = mygetGlobalWithUpd("$ot.status");
//$status = (int)$arr_status['VALUE'];
// *** формат данных и значения по умолчанию
if (is_numeric($airCurrentTemp)) { $airCurrentTemp = (float)$airCurrentTemp; } else { $airCurrentTemp = null; }
if (is_numeric($airRequiredTemp)) { $airRequiredTemp = (float)$airRequiredTemp; } else { $airRequiredTemp = null; }
if (is_numeric($airShiftTemp)) { $airShiftTemp = (float)$airShiftTemp; } else { $airShiftTemp = $airRequiredTemp; }
if (is_numeric($hysteresis)) { $hysteresis = (float)$hysteresis; } else { $hysteresis = 0.2; }
if (is_numeric($waterCurrentTemp)) { $waterCurrentTemp = (float)$waterCurrentTemp; } else { $waterCurrentTemp = null; }
if (is_numeric($waterRequiredTemp)) { $waterRequiredTemp = (float)$waterRequiredTemp; } else { $waterRequiredTemp = null; }
if (is_numeric($waterReturnTemp)) { $waterReturnTemp = (float)$waterReturnTemp; } else { $waterReturnTemp = null; }
if (is_numeric($waterMaxTemp)) { $waterMaxTemp = (int)$waterMaxTemp; } else { $waterMaxTemp = 80; }
if (is_numeric($waterMinTemp)) { $waterMinTemp = (int)$waterMinTemp; } else { $waterMinTemp = 10; }
$f_on = true;
// Разрешающие факоры:
if (!is_null($airCurrentTemp) && !is_null($airShiftTemp) && $airCurrentTemp < $airShiftTemp - $hysteresis) {
DebMes("$ot.workDecision текущая t воздуха $airCurrentTemp < заблаговременной требуемой $airShiftTemp - гистерезис $hysteresis",'thrm');
} elseif (!is_null($waterCurrentTemp) && !is_null($waterRequiredTemp) && $waterCurrentTemp < $waterRequiredTemp - 3) {
DebMes("$ot.workDecision t подачи $waterCurrentTemp < целевой $waterRequiredTemp - гист",'thrm');
} elseif (!is_null($waterCurrentTemp) && $waterCurrentTemp < $waterMinTemp) {
DebMes("$ot.workDecision t подачи $waterCurrentTemp < минимальной $waterMinTemp",'thrm');
//} elseif (timeOutExists($n.'_work')) {
// DebMes("$ot.workDecision существует таймер работы",'thrm');
} elseif ($mayResolve) {
DebMes("$ot.workDecision существует рекомендация на включение",'thrm');
} else {
$f_on = false;
}
$f_off = true;
// Запрещаюшие факторы:
if (!is_null($airCurrentTemp) && !is_null($airShiftTemp) && $airCurrentTemp > $airShiftTemp + $hysteresis) {
DebMes("$ot.workDecision текущая t воздуха $airCurrentTemp > заблаговременной требуемой $airShiftTemp + гистерезис $hysteresis",'thrm');
} elseif (!is_null($waterCurrentTemp) && !is_null($waterRequiredTemp) && $waterCurrentTemp > $waterRequiredTemp + 3) {
DebMes("$ot.workDecision t подачи $waterCurrentTemp > целевой $waterRequiredTemp + гист",'thrm');
} elseif (!is_null($waterCurrentTemp) && $waterCurrentTemp > $waterMaxTemp) {
DebMes("$ot.workDecision t подачи $waterCurrentTemp > максимальной $waterMaxTemp",'thrm');
//} elseif (timeOutExists($n.'_nowork')) {
// DebMes("$ot.workDecision существует таймер запрета",'thrm');
} elseif ($mayBanOn) {
DebMes("$ot.workDecision существует бан на включение",'thrm');
} else {
$f_off = false;
}
/* запрет по таймеру на вкл/выкл в т.ч. быстрое изменение мощности ступеней.
Включение запрещает таймер отдыха и таймер работы (для быстрого набора ступеней)
ВЫключение запрещает только таймер работы
*/
if ($f_on && ($timeWork || $timeNoWork)) {
DebMes("$ot.workDecision запрет за включение по таймеру",'thrm');
$f_on=false;
}
if ($f_off && $timeWork) {
DebMes("$ot.workDecision запрет за выключение по таймеру",'thrm');
$f_off=false;
}
// В итоге есть решения о необходимости работы или отключеня.
DebMes("$ot.workDecision status=$status f_on=$f_on f_off=$f_off",'thrm');
/*
Для подсчета общей мощности должно быть задано свойство powerLevels (массивом для нескольких ступеней)
В случае массива это свойство ДАЕТ разрещение на управление дополнительными ступенями.
*/
// Управление. Включить (добавить)
if ($f_on && !$f_off) {
/* Первое включение после бездействия.
При первом пуске сначала включем только первую ступень. Она по факту есть у любого котла.
*/
if (!$status) { $new_status = 1; }
/* Рассчитать количество требуемых ступеней. Формулу расчета требуемой мощности можно использовать только когда котёл,
работая на любых ступенях, выйдет на заявленную мощность.
Старый вариант: cмотреть на время записи свойства статус, Дадим ему поработать пять минут.
Новый вариант: смотреть на существование таймера минимальной работы. Условие таймера _work уже отменяет включение.
P.S. По формуле расчета мощности проточного нагревателя W = Q×(t2–t1)×0,073 возможно сразу рассчитать количество нужных ступеней.
Но скорость потока через котел будет неизвестной для большинства моделей. Поэтому сделаем расчет исходя из заявленной мощности котла.
*/
// котел включен и работает какое то время И существуют все температуры воды
//if ($status && time()-$arr_status['UPDATED'] > 60*5 && is_numeric($waterRequiredTemp) && is_numeric($waterCurrentTemp) && is_numeric($waterReturnTemp)) {
if ($status && is_numeric($waterRequiredTemp) && is_numeric($waterCurrentTemp) && is_numeric($waterReturnTemp)) {
// Разбить powerLevels на массив мощностей
$powerLevels=$this->getProperty('powerLevels');
preg_match_all('/(\d+\.?\d?)/', $powerLevels, $matches, PREG_PATTERN_ORDER);
// ЗНАЧИТ котел со ступенями
if (count($matches[0]) > 1) {
// Получить текущую мощность работающих ступеней
$W = 0;
for ($i = 0; $i < $status; $i++) { $W += $matches[0][$i]; }
DebMes("$ot.workDecision мощность работы $status ступеней $W кВт",'thrm');
// Вычислить требуемую мощность
$W = $W * ($waterRequiredTemp - $waterReturnTemp) / ($waterCurrentTemp - $waterReturnTemp);
$W = round($W);
DebMes("$ot.workDecision требуемая мощность для выхода на целевую t подачи $W кВт",'thrm');
// Найти нужное количество ступеней
$P=0;
for ($i = 0; $i < count($matches[0]); $i++) {
// Требуемая мощность <= 40% мощности ступени + сумма всех предыдущих ступеней
if ($W <= $matches[0][$i]*40/100 + $P) { break; }
$P += $matches[0][$i];
}
DebMes("$ot.workDecision Нужно $i ступеней",'thrm');
$new_status=$i;
}
}
}
// Управление. Выключить (убавить)
elseif ($status && $f_off) {
/* Ступени будут отключаться по одной.
Таймер мин работы должен удержать быстрое отключение сразу всех.
Расчета мощности тут не провожу.
*/
$new_status = max($status - 1, 0);
// уже не пойму что это такое было. Просто уменьшаем количество работающих ступеней
//if (count($matches[0]) > 1 && $status > 1) { DebMes("$ot.workDecision Условие отключает ступень не по мощности!",'thrm'); }
}
// Выполнение
if (isset($new_status) && $status <> $new_status) {
$status = $new_status;
DebMes("$ot.workDecision вызов меода managePower с параметром status = $status",'thrm');
$this->setProperty('status', $status);
$this->callMethod('managePower', array('status'=>$status));
}
return array('status'=>$status); // ответ уходим в ватеркальк$ot=$this->object_title;
if (defined('THRM_LOG_LEVEL') && THRM_LOG_LEVEL != '') { $log_level = THRM_LOG_LEVEL; } else { $log_level = 0; }
if ($log_level>1) { DebMes("$ot.$name Start Called " . mb_substr($source, 0, 50) . '...','thrm'); }
if (isset($params['status'])) { $status = $params['status']; } else { $status=(int)$this->getProperty('status'); }
// Время таймеров
$mintimeoff = $this->getProperty('mintimeoff');
if (is_numeric($mintimeoff)) { $mintimeoff = (int)$mintimeoff; } else { $mintimeoff = 15*60; }
$mintimeon = $this->getProperty('mintimeon');
if (is_numeric($mintimeon)) { $mintimeon = (int)$mintimeon; } else { $mintimeon = 10*60; }
// Cтатус уже устанавливается в методе workDecision
// Создание таймеров
if ($status) {
$this->setProperty('log', "Включаю $status ступень");
setTimeOut($ot.'_work', "debmes('Tаймер '.$ot.'_work закончен'); cm('$ot.workDecision');", $mintimeon);
clearTimeOut($ot.'_nowork');
} else {
$this->setProperty('log', 'Выключаю устройство');
setTimeOut($ot.'_nowork', "debmes('Tаймер '.$ot.'_nowork закончен'); cm('$ot.workDecision');", $mintimeoff);
clearTimeOut($ot.'_work');
}Свойства класса:
Методы класса:
//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("H:i",time()));
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=1*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);
$cmdUrl = $this->getProperty("ipAddress");
if (!$cmdUrl) { return; }
$cmdUrl = 'http://'.$cmdUrl;
$ctx = stream_context_create(array(
'http' => array('timeout'=>1)
)
);
$state = file_get_contents($cmdUrl, 0, $ctx);
if (!$state) {
$this->setProperty("alive",0);
return;
}
$this->setProperty("alive",1);
$value = explode('</br>',$state);
// Report - 04.01.2015 14:02:18
$value[0] = substr($value[0],17,18);
// I/P Voltage = 217.5 V
$value[2] = substr($value[2],16,5);
// I/P Fault Voltage = 217.5 V
$value[3] = substr($value[3],22,5);
// O/P Voltage = 217.5 V
$value[4] = substr($value[4],16,5);
// O/P Current = 015 %
$value[5] = substr($value[5],16,3);
// I/P Frequency = 50.0 Hz
$value[6] = substr($value[6],18,4);
// Battery Voltage = 0108 V
$value[7] = substr($value[7],20,4);
// Temperature = 53.2 °C
$value[8] = trim(substr($value[8],16,5));
// UPS Status = 00001001
$value[9] = substr($value[9],15,8);
/*
battery.voltage - battery.voltage.low
battery.charge = ------------------------------------------ x 100 %
battery.voltage.high - battery.voltage.low
*/
$bh = gg('UPS.batVoltHigh');
$bl = gg('UPS.batVoltLow');
$bc = round( ($value[7] - $bl) / ($bh - $bl) *100 );
$this->setProperty('measurTime',$value[0]);
$this->setProperty('inVoltage',$value[2]);
$this->setProperty('faultVoltage',$value[3]);
$this->setProperty('outVoltage',$value[4]);
$this->setProperty('load',$value[5]);
$this->setProperty('Frequency',$value[6]);
$this->setProperty('batVoltage',$value[7]);
$this->setProperty('inTemp',$value[8]);
$this->setProperty('status',$value[9]);
$this->setProperty('batCharge',$bc);
Методы класса:
//$params["LOCATION_OBJECT"], $params["LOCATION"]
//$params["LOCATION_OBJECT"], $params["LOCATION"]
Свойства класса:
Методы класса:
$msg = $this->description.' '.$this->getProperty('weatherType').'.';
$s=round($this->getProperty('temperature'));
/*
$i=abs($s);
if ($i >= 11 and $i <= 14){
$t='ов';
} else {
while ($i > 9){ $i=$i-10; }
if ($i == 0 or $i >= 5 and $i <= 9) { $t='ов'; }
elseif ($i == 1) { $s=''; }
elseif ($i >= 2 and $i <= 4) { $t='а'; }
}
$msg.=' Температура '.$s.' градус'.$t.'. ';
*/
$msg.=' Температура '.$s.'°.';
$msg.=' Относительная влажность '.$this->getProperty('humidity').'%.';
$s=$this->getProperty('pressure');
if ($s<728) {
$msg.=' Атмосферное давление пониженное.';
} elseif ($s>768) {
$msg.=' Атмосферное давление повышенное.';
} else {
$msg.=' Атмосферное давление нормальное.';
}
$s=$this->getProperty('windSpeed');
if ($s==0) { $msg.=' Ветра не ожидается.'; }
elseif ($s<3) { $msg.=' Слабый'; }
elseif ($s<6) { $msg.=' Сильный'; }
elseif ($s<9) { $msg.=' Очень сильный'; }
else { $msg.=' Шквальный'; }
if ($s) {
switch (strtolower($this->getProperty('windDirection'))){
case 's': $msg.=" южный"; break;
case 'n': $msg.=" северный"; break;
case 'w': $msg.=" западный"; break;
case 'e': $msg.=" восточный"; break;
case 'sw': $msg.=" юго-западный"; break;
case 'nw': $msg.=" северо-западный"; break;
case 'se': $msg.=" юго-восточный"; break;
case 'ne': $msg.=" северо-восточный"; break;
}
$msg.= ' ветер.';
}
say($msg);Свойства класса:
Методы класса:
$s=$this->object_title;
// переопределить имя точки. [0] имя [1] где
$s=runscript('CAPsFriendlyName',array('name'=>$s))[1];
say("Точка $s активна", 1);
$s=$this->object_title;
// переопределить имя точки. [0] имя [1] где
$s=runscript('CAPsFriendlyName',array('name'=>$s))[1];
say("Внимание. Точка $s не активна", 1);Свойства класса:
Методы класса:
$ot=$this->object_title;
// *** Уведомления о статусе устройства в сети ***
$n=$this->getProperty('notify');
switch ($n[0]) {
case '0': $i=-1; break;
case '1': $i=0; break;
case '2': $i=1; break;
}
if (isset($i)) {
// переопределить имя точки. [0] имя [1] где
$t=$this->getProperty('CAPname');
$t=runscript('CAPsFriendlyName',array('name'=>$t))[1];
// получить имя девайса
$s=$this->getProperty('deviceName');
if (!$s) {$s='Неизвестный девайс';}
say("$s сейчас в сети. Точка доступа - $t", $i);
if ($s == 'Неизвестный девайс') {
say($this->getProperty('MAC'), -1);
say('Последний раз в сети '.$this->getProperty('lastActive'), -1);
}
}
// *** Буквы маркера ***
$m=$this->getProperty('marker');
if (preg_match("/[fd]/i", $m, $match)) {
// активность у подъезда, если телефон первый раз обнаружен на этой точке
switch ($this->getProperty('CAPname')) {
case 'CAP--Bagir-1':
cm('DrivewayArea.onActivity', ['source'=>$ot]);
break;
}
// Пустить своих домой
if (in_array('d', $match)) {
// режим хозяин дома
if (!gg('OwnerMode.status')) {
cm('OwnerMode.activate');
}
switch ($this->getProperty('CAPname')) {
case 'CAP--Door':
// Открыть дверь ToDo использовать функцию склонения имени
say('Открываю входную дверь');
callMethod('RelayFrontDoorOpen.click');
break;
}
}
// Активация гостевого режима
if (in_array('f', $match)) {
if (!gg('GuestsMode.status')) {
cm('GuestsMode.activate');
}
}
}// Получить id свойств для работы с базой данных. Свои id свойств этого класса я уже знаю.
$online_pid = 573; //$this->getPropertyByName('online', $this->class_id, $this->id);
$marker_pid = 707; //$this->getPropertyByName('marker', $this->class_id, $this->id);
$owner_pid = 575; //$this->getPropertyByName('owner', $this->class_id, $this->id);
//debmes($online_pid.' '.$marker_pid.' '.$owner_pid, 'test');
$notify = $this->getProperty('notify');
$marker = $this->getProperty('marker');
// *** Уведомление ***
switch ($notify[1]) {
case '0': $i=-1; break;
case '1': $i=0; break;
case '2': $i=1; break;
}
if (isset($i)) {
$s=$this->getProperty('deviceName');
if (!$s) {$s='Неизвестный девайс';}
say("$s покинул сеть", $i);
}
/* Выбрать все свойства имен владельцев, свойства объектов которых живые и содержат букву */
// *** Маркер f ***
if (stripos($marker, 'f') !== false) {
$sql = "
SELECT VALUE FROM pvalues WHERE PROPERTY_ID = $owner_pid
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = $online_pid AND CAST(VALUE AS INT) > 0)
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = $marker_pid AND VALUE LIKE '%f%')
";
$rec = SQLSelectOne($sql);
// отключить гостевой режим если больше гостей нет и режим был включен
if (is_null($rec) && gg('GuestsMode.status')) {
cm('GuestsMode.deactivate');
}
}
// *** Маркер d ***
if (stripos($marker, 'd') !== false) {
$sql = "
SELECT VALUE FROM pvalues WHERE PROPERTY_ID = $owner_pid
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = $online_pid AND CAST(VALUE AS INT) > 0)
AND OBJECT_ID IN ( SELECT OBJECT_ID FROM pvalues WHERE PROPERTY_ID = $marker_pid AND VALUE LIKE '%d%')
";
$rec = SQLSelectOne($sql);
if (is_null($rec) && gg('OwnerMode.status')) {
cm('OwnerMode.deactivate');
}
}// *** Уведомление о смене точки ***
$n=$this->getProperty('notify');
switch ($n[2]) {
case '0': $i=-1; break;
case '1': $i=0; break;
case '2': $i=1; break;
}
if (isset($i)) {
// переопределить имя точки. [0] имя [1] где
$t=$this->getProperty('CAPname');
$t=runscript('CAPsFriendlyName',array('name'=>$t))[1];
// Получить имя девайса
$s=$this->getProperty('deviceName');
if (!$s) {$s='Неизвестный девайс';}
say("$s передан точке $t", $i);
}
// *** Маркер ***
if (stripos($this->getProperty('marker'), 'd') !== false) {
switch ($this->getProperty('CAPname')) {
// Открыть дверь ToDo использовать функцию склонения имени
case 'CAP--Door':
if ($params['oldCAPName']<>'CAP--hAPmini-1') { //запретить открытие при переходе из кухни в гараж
say('Открываю входную дверь');
callMethod('RelayFrontDoorOpen.click');
}
break;
}
}// ToDo передать в параметре всё что можно, особенно CAPname и marker
$ot=$this->object_title;
if (preg_match("/[fd]/i", $this->getProperty('marker'), $match)) {
switch ($this->getProperty('CAPname')) {
case 'CAP--Bagir-1':
// только друзья продлевают активность у подъезда
if (!in_array('f', $match)) { break; }
// моя функция получения времени изменения свойства. Ссылка на форум есть в блоге
$rec = mygetGlobalWithUpd('KitchenArea.SomebodyHere');
if ($rec['VALUE']<>$ot || time()-$rec['UPDATED'] > 60*5) {
cm('DrivewayArea.onActivity', ['source'=>$ot]);
}
break;
case 'CAP--SXT-1':
// свои и друзья продлевают активность беседки
$rec = mygetGlobalWithUpd('KitchenArea.SomebodyHere');
if ($rec['VALUE']<>$ot || time()-$rec['UPDATED'] > 60*5) {
cm('Gazebo.onActivity', ['source'=>$ot]);
}
break;
case 'CAP--hAPmini-1':
// свои и друзья продлевают активность кухни
$rec = mygetGlobalWithUpd('KitchenArea.SomebodyHere');
if ($rec['VALUE']<>$ot || time()-$rec['UPDATED'] > 60*5) {
cm('KitchenArea.onActivity', ['source'=>$ot]);
}
break;
}
}Свойства класса:
Методы класса:
//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("Y-m-d H:i:s",time()));
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=24*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);//u $this->setProperty("updated",time());
//u $this->setProperty("updatedTime",date("m.d.Y H:i",time()));
$this->setProperty("alive",1);
$ot=$this->object_title;
$alive_timeout=(int)$this->getProperty("aliveTimeOut");
if (!$alive_timeout) { $alive_timeout=24*60*60; }
setTimeOut($ot."_alive","sg('".$ot.".alive',0);",$alive_timeout);, Россия
На форуме: Bagir