Создаем группы объектов с помощью стандартных механизмов Мажордомо
just for fun
Добрый день, коллеги.
( Когда я занялся этой темой, честно говоря, не знал, что Сергей уже реализовал группы в ПУ. Но чтобы до них добраться, нужно войти в приложение Простые устройства и там уже создавать и настраивать группы.)
Как возникла идея о группах? Очень просто - объектов стало много и управлять ими трудно. Давно уже в коде стали появляться функции для массовой обработки объектов. Стали появляться спецсвойства - Отключать с рассветом, Включать с закатом, Выключать при экономрежиме, Включать при выходе из эконом режима и т.д.
У себя я решил не плодить дополнительные свойства, а создать для этого группы, куда можно добавлять любое количество любых объектов, в том числе и сами группы.
Для этого создал класс Groups со свойствами Items - тут список имен объектов в группе.
Думал, как хранить список имён в текстовом поле?
Просто названиями через разделитель? Плюсы - легко править вручную, минусы - так же легко напортачить.
serialize/json? Плюсы - порядок, минусы - редактирование.
Подумал, что состав группы не так часто меняется и остановился на стандарте php - serialize.
Написал две функции для добавления/удаления объектов из группы:
/**
* Добавим объект в группу
* appObj2Grp("ObjectName","groupName");
*/
function appObj2Grp($objName, $grp) {
if(!isset($grp)||!isset($objName)) return "no params";
if(null == getObject($grp)) return "no group";
$grpObj = getObject($grp);
if(null == getObject($objName) ) return "no object";
$items = unserialize($grpObj->getProperty('Items')); //переведем в массив
$items[] = $objName; //добавим наш объект
$newItems = array_unique($items); //от греха избавимся от дублей
$grpObj->setProperty('Items',serialize($newItems));//сохраним строку
return "ok";
}
function delObjFromGrp($objName, $grp) {
if(!isset($grp)||!isset($objName)) return "no params";
if(null == getObject($grp)) return "no group";
$grpObj = getObject($grp);
$list = $grpObj->getProperty('Items');//получим строку
if(trim($list) == "") { //если пусто, нечего удалять
$grpObj->setProperty('Items','a:0:{}');//сохраним строку
return "ok";
}
$items = unserialize($list); //переведем в массив
foreach($items as $key => $item){ //удалим по значению
if ($item == $objName){
unset($items[$key]);
}
}
$newItems = array_unique($items); //от греха избавимся от дублей
$grpObj->setProperty('Items',serialize($newItems));//сохраним строку
return "ok";
}
Набиваю объектами и редактирую группы с помощью этих двух функций в консоли Панели управления предварительно создав новые группы в классе.
Методы класса:
setGroupProperty Установить всем объектам группы значение свойства(если есть - установится, если нет - новое не появится)
//setGroupProperty
if(!isset($params['property'])) return 0; //no param
$prop = $params['property'];
if(!isset($params['value'])){
$value = 0; //по умолчанию
}else{
$value = $params['value'];
}
$items = unserialize($this->getProperty('Items')); //переведем в массив
foreach($items as $obj){ //переберем объекты
$obj_prop = $obj.".".$prop; //object.property
$rec = SQLSelectOne("SELECT * FROM `pvalues` WHERE `PROPERTY_NAME`='".$obj_prop."'");
if($rec) {
sg($obj_prop,$value);
echo('setGroupProperty '.$obj_prop.' set to '.$value.'<br>');
}else{
echo('setGroupProperty '.$obj_prop.' not find!<br>');
}
}
callGrpMethod Для всех объектов группы выполнить метод(если есть)
//callGrpMethod
if(!isset($params['mg'])) return 0; //no param
$mg = $params['mg'];
$obj_title = $params['ORIGINAL_OBJECT_TITLE'];
$items = unserialize($this->getProperty('Items')); //переведем в массив
foreach($items as $obj){ //переберем имена объектов группы
eval('callMethodSafe("'.$obj.'.'.$mg.'",array("source" =>"'.$obj_title.'"));');
usleep(50000);
//echo('callGroupMethod ->'.$obj.'.'.$mg.' run <br>');
}
return 'grp method done';
Что это дает?
Допустим, у нас есть аналог группы Отключать_с_рассветом - grpSunriseOff, поместим туда нужные объекты и начнём ими управлять - при рассвете просто выполняем групповой метод callGrpMethod
cm('grpSunriseOff.callGrpMethod',array("mg"=>"turnOff")); //в качестве параметра передается имя метода
Создадим группу Освещение - grpLights и включим туда все наши осветительные приборы - реле, диммеры, rgb-подсветку.
и теперь можем управлять освещением одним махом.
//Выключить весь свет везде
cm('grpLights.callGrpMethod',array("mg"=>"turnOff"));
//приведем всё освещение к запомненному состоянию после перезагрузки/аварии
cm('grpLights.callGrpMethod',array("mg"=>"refresh"));
Ещё несколько примеров:
//Перейдем в экономичный режим: Установим целевую температуру 18 для всех термостатов и включим у них режим Авто, если есть
cm('grpThermo.setGroupProperty',array('property'=>'temperature','value'=>18));
cm('grpThermo.setGroupProperty',array('property'=>'regime','value'=>'auto'));
//В комнате несколько окон с автошторами - объединим их группу
cm('grpKitchenBlinds.callGrpMethod',array("mg"=>"open"));
В планах - создать методы групп:
расчет среднего, мин/макс, суммы заданного свойства объектов - на текущий момент, без истории.
Типа
$avglr = cm('grpLivingRooms.AvgGrpProperty',array('property'=>'temperature')); //узнаем среднюю температуру в жилых помещениях
$minlr = cm('grpLivingRooms.MinGrpProperty',array('property'=>'humidity')); //минимальная влажность в жилых помещениях
$sumpw = cm('grpThermo.SumGrpProperty',array('property'=>'power')); //суммарная мощность, отдаваемая сейчас конвекторами группы
Действующие ограничения - объектам в одной группе хорошо иметь (но не обязательно) одноименные свойства/методы(
Так уж нужно это в Мажордомо или нет, не знаю. Мне это помогло избавиться от спецсвойств в объектах и я не пишу циклы перебора foreach() в коде, убрав их в групповые методы.
upd. благодаря Логрусу, найдена и исправлена ошибка в методе вызова метода групп( кавычки, мать их)
Upd.add code for class method AvgGrpProperty/MinGrpProperty/MaxGrpProperty/SumGrpProperty/CountGrpProperty
Для соотв. метода раскоментировать нужную строку.
//пример вызова $avg = cm('myGroup.AvgGrpProperty',array('property'=>'propName');//среднее
//code for class method AvgGrpProperty/MinGrpProperty/MaxGrpProperty/SumGrpProperty/CountGrpProperty
if(!isset($params['property'])) return "no property"; //no param
$prop = $params['property'];
$items = unserialize($this->getProperty('Items')); //переведем в массив
if(count($items) == 0) return "no objects";
$obj_prop = "'".implode("','",$items) . "'"; // 'obj1','obj2',...
$sql = "SELECT avg(`VALUE`+0.0) res FROM `pvalues` p join objects o on o.id=p.`OBJECT_ID` where `PROPERTY_NAME` like '%.".$prop."' and o.title in ($obj_prop) and not p.value is null";
//$sql = "SELECT min(`VALUE`+0.0) res FROM `pvalues` p join objects o on o.id=p.`OBJECT_ID` where `PROPERTY_NAME` like '%.".$prop."' and o.title in ($obj_prop) and not p.value is null";
//$sql = "SELECT max(`VALUE`+0.0) res FROM `pvalues` p join objects o on o.id=p.`OBJECT_ID` where `PROPERTY_NAME` like '%.".$prop."' and o.title in ($obj_prop) and not p.value is null";
//$sql = "SELECT sum(`VALUE`+0.0) res FROM `pvalues` p join objects o on o.id=p.`OBJECT_ID` where `PROPERTY_NAME` like '%.".$prop."' and o.title in ($obj_prop) and not p.value is null";
//$sql = "SELECT count(`VALUE`+0.0) res FROM `pvalues` p join objects o on o.id=p.`OBJECT_ID` where `PROPERTY_NAME` like '%.".$prop."' and o.title in ($obj_prop) and not p.value is null";
//echo $sql;
$rec = SQLSelectOne($sql);
return $rec['res'];
Методы очень похожи и, в принципе, их можно объединить в один, передавая функцию как параметр
Домодедово, Россия
На форуме: xor