Devices class php: различия между версиями
Материал из MajorDoMo инфо
Mixman (обсуждение | вклад) (Новая страница: «Category:SDevices Devices.class.php Возможно где-то ошибки с закрывающими или открывающими {} в связи с добавлением коментов, мог гдето херакнуть, прошу заранее прощения, сам ищу косяки и поправлю если найду. Но вроде бы не должно быть. <pre> <?php /** * Общий коммент к понима...») |
Vik Tam (обсуждение | вклад) (попробовал убрать точки в заглавии) |
||
| Строка 1: | Строка 1: | ||
[[Category:SDevices]] | [[Category:SDevices]] | ||
Devices_class_php | |||
Возможно где-то ошибки с закрывающими или открывающими {} в связи с добавлением коментов, мог гдето херакнуть, прошу заранее прощения, сам ищу косяки и поправлю если найду. Но вроде бы не должно быть. | Возможно где-то ошибки с закрывающими или открывающими {} в связи с добавлением коментов, мог гдето херакнуть, прошу заранее прощения, сам ищу косяки и поправлю если найду. Но вроде бы не должно быть. | ||
<pre> | <pre> | ||
Текущая версия от 09:13, 30 марта 2024
Devices_class_php Возможно где-то ошибки с закрывающими или открывающими {} в связи с добавлением коментов, мог гдето херакнуть, прошу заранее прощения, сам ищу косяки и поправлю если найду. Но вроде бы не должно быть.
<?php
/**
* Общий коммент к пониманию стандарта PHPDoc:
* Аннотация @method для указания на то, что это комментарий к методу.
* Аннотация @param для описания параметров метода.
* Аннотация @return для описания возвращаемого значения метода.
* Аннотация @see для ссылок на другие классы или методы.
* Аннотация @since для указания версии, с которой был добавлен метод.
*
* Типы параметров и возвращаемых значений:
* - string: строковое значение.
* - int: целочисленное значение.
* - float: число с плавающей точкой.
* - bool: булево значение (true или false).
* - array: массив.
* - object: объект.
* - mixed: любой тип данных.
* - callable: функция или метод.
* - resource: ресурс (например, файл).
* - null: специальное значение, обозначающее отсутствие значения.
*
* Пример использования:
* @method void myVoidMethod() Описание метода, который не возвращает значение.
* @param string $param1 Параметр типа string.
* @param int $param2 Параметр типа int.
* @param float $param3 Параметр типа float.
* @param bool $param4 Параметр типа bool.
* @param array $param5 Параметр типа array.
* @param object $param6 Параметр типа object.
* @param mixed $param7 Параметр типа mixed (любой тип).
* @param callable $param8 Параметр типа callable (функция или метод).
* @param resource $param9 Параметр типа resource (ресурс, например, файл).
* @param null $param10 Параметр типа null.
* @return string Возвращает значение типа string.
* @return int Возвращает значение типа int.
* @return float Возвращает значение типа float.
* @return bool Возвращает значение типа bool.
* @return array Возвращает значение типа array.
* @return object Возвращает значение типа object.
* @return mixed Возвращает значение типа mixed (любой тип).
* @return callable Возвращает значение типа callable (функция или метод).
* @return resource Возвращает значение типа resource (ресурс, например, файл).
* @return null Возвращает значение типа null.
*/
/**
* Класс Devices
* @package project
* @author Wizard <sergejey@gmail.com>
* @copyright http://majordomo.smartliving.ru/ (c)
* @version 0.1 (wizard, 13:07:05 [Jul 19, 2016])
* @class Devices
* @property string $name Имя модуля
* @property string $title Заголовок модуля
* @property string $module_category Категория модуля
* @method void __construct() Конструктор класса
* @method void saveParams($data = 0) Сохранение параметров модуля
* @method void getParams() Получение параметров модуля из строки запроса
* @method void setDictionary() Установка словаря для модуля
* @method void run() Основная логика модуля
* @see module
* @since 0.1
*/
// Класс devices расширяет модуль, что позволяет использовать функциональность модуля в классе devices.
class devices extends module
{
var $view;
var $id;
/**
* Конструктор класса модуля
* @method void __construct()
* @see module
* @since 0.1
*/
function __construct()
{
// Инициализация имени модуля.
$this->name = "devices";
// Установка заголовка модуля, который будет отображаться в интерфейсе.
$this->title = "<#LANG_SECTION_DEVICES#>";
// Установка категории модуля, которая также будет отображаться в интерфейсе.
$this->module_category = "<#LANG_SECTION_DEVICES#>";
// Проверка, установлен ли модуль.
$this->checkInstalled();
// Установка словаря для модуля.
$this->setDictionary();
}
/**
* saveParams
*
* Сохранение параметров модуля
*
* @method void saveParams($data = 0)
* @param mixed $data Данные для сохранения
* @return void
* @see module
* @since 0.1
*/
function saveParams($data = 0)
{
$p = array();
// Проверка наличия идентификатора модуля и его сохранение в массив параметров.
if (isset($this->id)) {
$p["id"] = $this->id;
}
// Проверка наличия режима просмотра и его сохранение в массив параметров.
if (isset($this->view_mode)) {
$p["view_mode"] = $this->view_mode;
}
// Проверка наличия режима редактирования и его сохранение в массив параметров.
if (isset($this->edit_mode)) {
$p["edit_mode"] = $this->edit_mode;
}
// Проверка наличия вкладки и ее сохранение в массив параметров.
if (isset($this->tab)) {
$p["tab"] = $this->tab;
}
// Вызов родительского метода saveParams с передачей массива параметров.
return parent::saveParams($p);
}
/**
* getParams
*
* Получение параметров модуля из строки запроса
* Этот фрагмент кода содержит два метода:
* saveParams и getParams.
* Метод saveParams сохраняет параметры модуля,
* а метод getParams получает их из строки запроса.
* Оба методы используют глобальные переменные для работы с параметрами
*
* @method void getParams()
* @return void
* @see module
* @since 0.1
*/
function getParams()
{
global $id;
global $mode;
global $view_mode;
global $edit_mode;
global $tab;
// Проверка наличия идентификатора и его присвоение свойству класса.
if (isset($id)) {
$this->id = $id;
}
// Проверка наличия режима и его присвоение свойству класса.
if (isset($mode)) {
$this->mode = $mode;
}
// Проверка наличия режима просмотра и его присвоение свойству класса.
if (isset($view_mode)) {
$this->view_mode = $view_mode;
}
// Проверка наличия режима редактирования и его присвоение свойству класса.
if (isset($edit_mode)) {
$this->edit_mode = $edit_mode;
}
// Проверка наличия вкладки и ее присвоение свойству класса.
if (isset($tab)) {
$this->tab = $tab;
}
}
/**
* setDictionary
* Метод setDictionary включает два файла,
* которые содержат структуру устройств и связи между ними.
* Это необходимо для корректной работы модуля устройств.
*
* @method void setDictionary()
* @return void
* @see module
* @since 0.1
*/
function setDictionary()
{
// Включение файлов, содержащих структуру устройств и связи между ними.
include(dirname(__FILE__) . '/devices_structure.inc.php');
include(dirname(__FILE__) . '/devices_structure_links.inc.php');
}
/**
* Run
*
* Метод run выполняет основную логику модуля.
* Он проверяет действие, которое необходимо выполнить, и вызывает соответствующий метод.
* Затем он устанавливает различные параметры,
* такие как режим просмотра, режим редактирования, режим, действие и вкладку.
* После этого он сохраняет данные в свойстве класса и создает новый объект парсера,
* используя указанный шаблон и данные.
* Результат парсинга сохраняется в свойстве класса.
*
* @method void run()
* @return void
* @see module
* @since 0.1
*/
function run()
{
// Инициализация массива для хранения данных.
$out = array();
// Проверка действия и вызов соответствующего метода.
if ($this->action == 'admin') {
$this->admin($out);
} elseif ($this->action == 'link') {
$this->link($out);
} else {
$this->usual($out);
}
// Проверка и установка действия родительского объекта.
if (isset($this->owner->action)) {
$out['PARENT_ACTION'] = $this->owner->action;
}
// Проверка и установка имени родительского объекта.
if (isset($this->owner->name)) {
$out['PARENT_NAME'] = $this->owner->name;
}
// Установка режима просмотра.
$out['VIEW_MODE'] = $this->view_mode;
// Установка режима редактирования.
$out['EDIT_MODE'] = $this->edit_mode;
// Установка режима.
$out['MODE'] = $this->mode;
// Установка действия.
$out['ACTION'] = $this->action;
// Установка вкладки.
$out['TAB'] = $this->tab;
// Сохранение данных в свойстве класса.
$this->data = $out;
// Создание нового объекта парсера с указанным шаблоном и данными.
$p = new parser(DIR_TEMPLATES . $this->name . "/" . $this->name . ".html", $this->data, $this);
// Сохранение результата парсинга в свойстве класса.
$this->result = $p->result;
}
/**
* link
*
* Метод link обрабатывает связь устройства.
* Он проверяет наличие различных параметров,
* таких как тип устройства, исходная таблица, идентификатор исходной таблицы, префикс,
* дополнительный заголовок и связанный объект.
* Если все параметры корректны, он генерирует уникальный идентификатор для устройства
* и устанавливает флаг успешного выполнения.
*
* @method void link()
* @return void
* @see module
* @since 0.1
*/
function link(&$out)
{
$ok = 1;
// Проверка наличия типа устройства и его сохранение в массив вывода.
if ($this->type) {
$out['TYPE'] = $this->type;
} else {
// Если тип устройства не определен, устанавливаем флаг ошибки.
$ok = 0;
}
// Проверка наличия исходной таблицы и ее сохранение в массив вывода.
if ($this->source_table) {
$out['SOURCE_TABLE'] = $this->source_table;
} else {
// Если исходная таблица не определена, устанавливаем флаг ошибки.
$ok = 0;
}
// Проверка наличия идентификатора исходной таблицы и его сохранение в массив вывода.
if ($this->source_table_id) {
$out['SOURCE_TABLE_ID'] = $this->source_table_id;
} else {
// Если идентификатор исходной таблицы не определен, устанавливаем флаг ошибки.
$ok = 0;
}
// Проверка наличия префикса и его сохранение в массив вывода.
if ($this->prefix) {
$out['PREFIX'] = $this->prefix;
}
// Проверка наличия дополнительного заголовка и его сохранение в массив вывода.
if (isset($this->add_title)) {
$out['ADD_TITLE'] = urlencode($this->add_title);
}
// Проверка наличия связанного объекта и его сохранение в массив вывода.
if ($this->linked_object) {
$device_rec = SQLSelectOne("SELECT ID,TITLE FROM devices WHERE LINKED_OBJECT LIKE '" . DBSafe($this->linked_object) . "'");
if (isset($device_rec['TITLE'])) {
$out['TITLE'] = $device_rec['TITLE'];
// Если установлен флаг предварительного просмотра, обрабатываем устройство и сохраняем результат в массив вывода.
if ($this->preview) {
$data = $this->processDevice($device_rec['ID']);
$out['HTML'] = $data['HTML'];
}
$out['ID'] = $device_rec['ID'];
}
$out['LINKED_OBJECT'] = $this->linked_object;
}
// Генерация уникального идентификатора для устройства.
$out['UNIQ'] = uniqid('dev');
// Если все параметры корректны, устанавливаем флаг успешного выполнения.
if ($ok) {
$out['OK'] = 1;
}
}
/**
* getTypeDetails
*
* Метод getTypeDetails возвращает детали типа устройства из словаря типов устройств.
*
* @method array getTypeDetails($type)
* @param string $type Тип устройства
* @return array Детали типа устройства
* @see module
* @since 0.1
*/
function getTypeDetails($type)
{
// Возвращает детали типа устройства из словаря типов устройств.
return $this->device_types[$type];
}
/**
* getTypeLinks
*
* Метод getTypeLinks возвращает все связи, которые связаны с указанным типом устройства.
* Он сначала получает детали типа устройства,
* а затем проходит по всем связям устройств, проверяя,
* присутствует ли класс или родительский класс типа устройства в типах связей.
* Если да, то все связи этого типа добавляются в результирующий массив.
*
* @method array getTypeLinks($type)
* @param string $type Тип устройства
* @return array Все связи, связанные с указанным типом устройства
* @see module
* @since 0.1
*/
function getTypeLinks($type)
{
// Получаем детали типа устройства.
$type_details = $this->getTypeDetails($type);
$res_links = array();
// Проходимся по всем связям устройств.
foreach ($this->device_links as $k => $v) {
// Разделяем типы связей на отдельные элементы.
$link_types = explode(',', $k);
$link_types = array_map('trim', $link_types);
// Если класс или родительский класс типа устройства присутствует в типах связей,
if (in_array($type_details['CLASS'], $link_types) || in_array($type_details['PARENT_CLASS'], $link_types)) {
// добавляем все связи этого типа в результирующий массив.
foreach ($v as $link) {
$res_links[] = $link;
}
}
}
// Возвращаем результирующий массив связей.
return $res_links;
}
/**
* getLinkDetails
*
* Метод getLinkDetails возвращает детали связи устройства по указанному имени связи.
* Он проходит по всем связям устройств и возвращает детали той связи,
* имя которой совпадает с указанным именем связи.
*
* @method array getLinkDetails($link_name)
* @param string $link_name Имя связи устройства
* @return array Детали связи устройства
* @see module
* @since 0.1
*/
function getLinkDetails($link_name)
{
// Проходимся по всем связям устройств.
foreach ($this->device_links as $k => $v) {
foreach ($v as $link) {
// Если имя связи совпадает с указанным именем связи, возвращаем детали этой связи.
if ($link['LINK_NAME'] == $link_name) {
return $link;
}
}
}
}
/**
* getAllGroups
*
* Метод getAllGroups возвращает все группы устройств, которые применимы к указанному типу устройства.
* Он выбирает все группы устройств из базы данных,
* проходит по ним и добавляет в результирующий массив те группы,
* типы которых присутствуют в типах, применимых к группе.
*
* @method array getAllGroups($type)
* @param string $type Тип устройства
* @return array Все группы устройств, применимые к указанному типу устройства
* @see module
* @since 0.1
*/
function getAllGroups($type)
{
// Выбираем все группы устройств из базы данных.
$groups = SQLSelect("SELECT * FROM devices_groups");
$res = array();
$total = count($groups);
// Проходимся по всем группам.
for ($i = 0; $i < $total; $i++) {
$tmp = explode(',', $groups[$i]['APPLY_TYPES']);
// Если тип устройства присутствует в типах, применимых к группе, добавляем группу в результирующий массив.
if (in_array($type, $tmp)) {
$res[] = $groups[$i];
}
}
// Возвращаем результирующий массив групп.
return $res;
}
/**
* getAllProperties
*
* Метод getAllProperties возвращает все свойства указанного типа устройства,
* включая свойства его родительского класса.
* Он сначала получает свойства текущего типа устройства,
* а затем, если у типа устройства есть родительский класс,
* проходит по всем типам устройств, ищет свойства родительского класса и добавляет их в свойства текущего типа,
* если они еще не присутствуют.
*
* @method array getAllProperties($type)
* @param string $type Тип устройства
* @return array Все свойства указанного типа устройства, включая свойства его родительского класса
* @see module
* @since 0.1
*/
function getAllProperties($type)
{
// Получаем свойства текущего типа устройства.
$properties = $this->device_types[$type]['PROPERTIES'];
$parent_class = isset($this->device_types[$type]['PARENT_CLASS']) ? $this->device_types[$type]['PARENT_CLASS'] : '';
// Если у типа устройства есть родительский класс,
if ($parent_class != '') {
// проходимся по всем типам устройств.
foreach ($this->device_types as $k => $v) {
// Если класс текущего типа совпадает с родительским классом,
if ($v['CLASS'] == $parent_class) {
// получаем свойства родительского класса.
$parent_properties = $this->getAllProperties($k);
// Проходимся по всем свойствам родительского класса.
foreach ($parent_properties as $pk => $pv) {
// Если свойство родительского класса еще не присутствует в свойствах текущего типа, добавляем его.
if (!isset($properties[$pk])) {
$properties[$pk] = $pv;
}
}
}
}
}
// Возвращаем все свойства текущего типа устройства, включая свойства родительского класса.
return $properties;
}
/**
* getAllMethods
*
* Метод getAllMethods возвращает все методы указанного типа устройства,
* включая методы его родительского класса.
* Он сначала получает методы текущего типа устройства,
* а затем, если у типа устройства есть родительский класс,
* проходит по всем типам устройств,
* ищет методы родительского класса и добавляет их в методы текущего типа,
* если они еще не присутствуют.
*
* @method array getAllMethods($type)
* @param string $type Тип устройства
* @return array Все методы указанного типа устройства, включая методы его родительского класса
* @see module
* @since 0.1
*/
function getAllMethods($type)
{
// Получаем методы текущего типа устройства.
$methods = $this->device_types[$type]['METHODS'];
$parent_class = isset($this->device_types[$type]['PARENT_CLASS']) ? $this->device_types[$type]['PARENT_CLASS'] : '';
// Если у типа устройства есть родительский класс,
if ($parent_class != '') {
// проходимся по всем типам устройств.
foreach ($this->device_types as $k => $v) {
// Если класс текущего типа совпадает с родительским классом,
if ($v['CLASS'] == $parent_class) {
// получаем методы родительского класса.
$parent_methods = $this->getAllMethods($k);
// Проходимся по всем методам родительского класса.
foreach ($parent_methods as $pk => $pv) {
// Если метод родительского класса еще не присутствует в методах текущего типа, добавляем его.
if (!isset($methods[$pk])) {
$methods[$pk] = $pv;
}
}
}
}
}
// Возвращаем все методы текущего типа устройства, включая методы родительского класса.
return $methods;
}
/**
* getNewObjectIndex
*
* Метод getNewObjectIndex возвращает новый индекс для объекта указанного класса.
* Он сначала получает объекты указанного класса, а затем, если префикс не пустой,
* выбирает дополнительные объекты, которые начинаются с этого префикса.
* Затем он проходит по всем объектам, ищет числа в их названиях и обновляет индекс,
* если найденное число больше текущего индекса.
* В конце метод возвращает индекс, увеличенный на 1, и добавляет в начало ноль, если индекс меньше 10.
*
* @method string getNewObjectIndex($class, $prefix = '')
* @param string $class Имя класса
* @param string $prefix Префикс для поиска объектов
* @return string Новый индекс для объекта указанного класса
* @see module
* @since 0.1
*/
function getNewObjectIndex($class, $prefix = '')
{
// Получаем объекты указанного класса.
$objects = getObjectsByClass($class);
if ($prefix != '') {
// Если префикс не пустой, выбираем дополнительные объекты, которые начинаются с этого префикса.
$other_objects = SQLSelect("SELECT TITLE FROM objects WHERE TITLE LIKE '" . $prefix . "%'");
foreach ($other_objects as $obj) {
$objects[] = $obj;
}
}
$index = 0;
$total = count($objects);
// Проходимся по всем объектам.
for ($i = 0; $i < $total; $i++) {
// Если в названии объекта присутствует число,
if (preg_match('/(\d+)/', $objects[$i]['TITLE'], $m)) {
$current_index = (int)$m[1];
// и это число больше текущего индекса, обновляем индекс.
if ($current_index > $index) {
$index = $current_index;
}
}
}
$index++;
// Если индекс меньше 10, добавляем в начало ноль.
if ($index < 10) {
$index = '0' . $index;
}
// Возвращаем индекс.
return $index;
}
/**
* processDevice
*
* Метод processDevice обрабатывает устройство с указанным идентификатором.
* Он выбирает запись устройства из базы данных, получает шаблон для объекта класса устройства,
* обрабатывает шаблон и сохраняет результат в массив результатов.
* Если тип устройства - 'camera', он устанавливает высоту результата.
* В конце метод возвращает результат.
*
* @method array processDevice($device_id, $view = '')
* @param int $device_id Идентификатор устройства
* @param string $view Название представления
* @return array Результат обработки устройства
* @see module
* @since 0.1
*/
function processDevice($device_id, $view = '')
{
// Начинаем измерение времени выполнения метода.
startMeasure('processDevice');
// Выбираем запись устройства из базы данных по его идентификатору.
$device_rec = SQLSelectOne("SELECT * FROM devices WHERE ID=" . (int)$device_id);
$result = array('HTML' => '', 'DEVICE_ID' => $device_rec['ID']);
// Получаем шаблон для объекта класса устройства.
$template = getObjectClassTemplate($device_rec['LINKED_OBJECT'], $view);
// Обрабатываем шаблон и сохраняем результат в массив результатов.
$result['HTML'] = processTitle($template, $this);
// Если тип устройства - 'camera', устанавливаем высоту результата.
if ($device_rec['TYPE'] == 'camera') {
$result['HEIGHT'] = 5;
}
// Завершаем измерение времени выполнения метода.
endMeasure('processDevice');
// Возвращаем результат.
return $result;
}
/**
* getWatchedProperties
*
* Метод getWatchedProperties возвращает все свойства устройств, которые нужно отслеживать.
* Он сначала устанавливает словарь для модуля,
* затем выбирает устройства из базы данных и проходит по ним.
* Для каждого устройства он получает все свойства текущего типа устройства и добавляет их в результирующий массив.
* Если тип устройства - 'html', он обрабатывает содержимое устройства,
* удаляет из него все символы, которые не являются частью имени свойства,
* ищет все имена свойств в содержимом устройства
* и добавляет каждое найденное свойство в результирующий массив.
* В конце метод возвращает результирующий массив свойств.
*
* @method array getWatchedProperties($device_id = 0)
* @param int $device_id Идентификатор устройства
* @return array Все свойства устройств, которые нужно отслеживать
* @see module
* @since 0.1
*/
function getWatchedProperties($device_id = 0)
{
// Устанавливаем словарь для модуля.
$this->setDictionary();
$properties = array();
$qry = 1;
if ($device_id) {
// Если указан идентификатор устройства, добавляем его в запрос.
$qry .= " AND devices.ID IN (" . $device_id . ")";
}
// Выбираем устройства из базы данных.
$devices = SQLSelect("SELECT * FROM devices WHERE $qry");
$total = count($devices);
// Проходимся по всем устройствам.
for ($i = 0; $i < $total; $i++) {
if (!$devices[$i]['LINKED_OBJECT']) {
continue;
}
// Получаем все свойства текущего типа устройства.
$props = $this->getAllProperties($devices[$i]['TYPE']);
if (is_array($props)) {
foreach ($props as $k => $v) {
// Если имя свойства начинается с символа подчеркивания, пропускаем его.
if (substr($k, 0, 1) == '_') continue;
// Добавляем свойство в результирующий массив.
$properties[] = array('PROPERTY' => mb_strtolower($devices[$i]['LINKED_OBJECT'] . '.' . $k, 'UTF-8'), 'DEVICE_ID' => $devices[$i]['ID']);
}
}
// Если тип устройства - 'html', обрабатываем содержимое устройства.
if ($devices[$i]['TYPE'] == 'html') {
$content = getGlobal($devices[$i]['LINKED_OBJECT'] . '.data');
// Удаляем из содержимого устройства все символы, которые не являются частью имени свойства.
$content = preg_replace('/%([\w\d\.]+?)\.([\w\d\.]+?)\|(\d+)%/uis', '%\1.\2%', $content);
$content = preg_replace('/%([\w\d\.]+?)\.([\w\d\.]+?)\|(\d+)%/uis', '%\1.\2%', $content);
$content = preg_replace('/%([\w\d\.]+?)\.([\w\d\.]+?)\|".+?"%/uis', '%\1.\2%', $content);
// Ищем все имена свойств в содержимом устройства.
if (preg_match_all('/%([\w\d\.]+?)%/is', $content, $m)) {
$totalm = count($m[1]);
for ($im = 0; $im < $totalm; $im++) {
// Добавляем каждое найденное свойство в результирующий массив.
$properties[] = array('PROPERTY' => mb_strtolower($m[1][$im], 'UTF-8'), 'DEVICE_ID' => $devices[$i]['ID']);
}
}
}
}
// Возвращаем результирующий массив свойств.
return $properties;
}
/**
* updateGroupObjects
*
* Метод updateGroupObjects обновляет объекты групп устройств.
* Он сначала выбирает все группы устройств из базы данных,
* затем проходит по ним и добавляет объект класса 'SGroups'
* с указанным именем и описанием для каждой группы.
* Затем он устанавливает свойство 'groupName' для каждого объекта
* и сохраняет его в массив добавленных объектов.
* После этого он получает все объекты класса 'SGroups'
* и удаляет те из них, которые не присутствуют в массиве добавленных объектов.
*
* @method void updateGroupObjects()
* @return void
* @see module
* @since 0.1
*/
function updateGroupObjects()
{
// Выбираем все группы устройств из базы данных.
$groups = SQLSelect("SELECT * FROM devices_groups WHERE 1");
$total = count($groups);
$added_objects = array();
// Проходимся по всем группам.
for ($i = 0; $i < $total; $i++) {
// Добавляем объект класса 'SGroups' с указанным именем и описанием.
$object_id = addClassObject('SGroups', 'group' . $groups[$i]['SYS_NAME'], 'group' . $groups[$i]['SYS_NAME']);
$object_rec = SQLSelectOne("SELECT * FROM objects WHERE ID=" . $object_id);
if ($object_rec['ID']) {
// Обновляем описание объекта.
$object_rec['DESCRIPTION'] = $groups[$i]['TITLE'];
SQLUpdate('objects', $object_rec);
}
// Устанавливаем свойство 'groupName' для объекта.
sg($object_rec['TITLE'] . '.groupName', $groups[$i]['SYS_NAME']);
$added_objects[] = $object_id;
}
// Получаем все объекты класса 'SGroups'.
$group_objects = getObjectsByClass('SGroups');
foreach ($group_objects as $rec) {
// Если объект не присутствует в массиве добавленных объектов, удаляем его.
if (!in_array($rec['ID'], $added_objects)) {
deleteObject($rec['ID']);
}
}
}
/**
* renderStructure
*
* Эта функция отвечает за рендеринг структуры устройств.
* Она проходит по всем типам устройств и для каждого типа выполняет следующие действия:
* - Добавляет класс устройства, если он не существует.
* - Обновляет описание класса, если оно задано.
* - Добавляет свойства класса, если они не существуют.
* - Добавляет методы класса, если они не существуют.
* - Добавляет объекты класса, если они не существуют.
* - Подписывается на события 'COMMAND' и 'MINUTELY' для модуля устройств.
* - Обновляет превью камер.
* - Обновляет объекты устройств.
* - Обновляет объекты групп устройств.
*
* @method void renderStructure()
* @return void
* @see module
* @since 0.1
*/
function renderStructure()
{
// Проверяем, определена ли константа DISABLE_SIMPLE_DEVICES и равна ли она 1
if (defined('DISABLE_SIMPLE_DEVICES') && DISABLE_SIMPLE_DEVICES == 1) {
// Если условие выполняется, отписываемся от событий 'COMMAND' и 'MINUTELY' для модуля устройств и прекращаем выполнение функции
unsubscribeFromEvent('devices', 'COMMAND');
unsubscribeFromEvent('devices', 'MINUTELY');
return;
}
// Проходимся по всем типам устройств
foreach ($this->device_types as $k => $v) {
// Класс устройства
if (isset($v['PARENT_CLASS'])) {
// Если у устройства есть родительский класс, добавляем класс с указанием родительского класса
$class_id = addClass($v['CLASS'], $v['PARENT_CLASS']);
} else {
// Если у устройства нет родительского класса, добавляем класс без указания родительского класса
$class_id = addClass($v['CLASS']);
}
// Если класс успешно добавлен
if ($class_id) {
// Получаем информацию о классе из базы данных
$class = SQLSelectOne("SELECT * FROM classes WHERE ID=" . $class_id);
// Если у устройства есть описание, обновляем описание класса в базе данных
if (isset($v['DESCRIPTION'])) {
$class['DESCRIPTION'] = $v['DESCRIPTION'];
SQLUpdate('classes', $class);
}
}
// Свойства класса
if (isset($v['PROPERTIES']) && is_array($v['PROPERTIES'])) {
// Проходимся по всем свойствам класса
foreach ($v['PROPERTIES'] as $pk => $pv) {
// Добавляем свойство класса с указанием, нужно ли сохранять историю изменений свойства
$prop_id = addClassProperty($v['CLASS'], $pk, isset($pv['KEEP_HISTORY']) ? $pv['KEEP_HISTORY'] : 0);
// Если свойство успешно добавлено
if ($prop_id) {
// Получаем информацию о свойстве из базы данных
$property = SQLSelectOne("SELECT * FROM properties WHERE ID=" . $prop_id);
// Если свойство является массивом
if (is_array($pv)) {
// Проходимся по всем элементам массива свойства
foreach ($pv as $ppk => $ppv) {
// Если ключ свойства начинается с символа подчеркивания, пропускаем его
if (substr($ppk, 0, 1) == '_') continue;
// Если свойство 'KEEP_HISTORY' уже установлено, пропускаем его
if ($ppk == 'KEEP_HISTORY' && $property[$ppk]) continue;
// Обновляем значение свойства
$property[$ppk] = $ppv;
}
// Обновляем информацию о свойстве в базе данных
SQLUpdate('properties', $property);
}
}
}
}
// Методы класса
if (isset($v['METHODS']) && is_array($v['METHODS'])) {
// Проходимся по всем методам класса
foreach ($v['METHODS'] as $mk => $mv) {
// Добавляем метод класса с указанием кода метода и класса, к которому он принадлежит
$method_id = addClassMethod($v['CLASS'], $mk, "require(DIR_MODULES.'devices/" . $v['CLASS'] . "_" . $mk . ".php');", 'SDevices');
// Если файл метода не существует, создаем его
if (!file_exists(dirname(__FILE__) . '/' . $v['CLASS'] . "_" . $mk . ".php")) {
$code = '<?php' . "\n\n";
@SaveFile(dirname(__FILE__) . "/" . $v['CLASS'] . "_" . $mk . ".php", $code);
}
// Если метод успешно добавлен
if ($method_id) {
// Получаем информацию о методе из базы данных
$method = SQLSelectOne("SELECT * FROM methods WHERE ID=" . $method_id);
// Если метод является массивом
if (is_array($mv)) {
// Проходимся по всем элементам массива метода
foreach ($mv as $mmk => $mmv) {
// Если ключ метода начинается с символа подчеркивания, пропускаем его
if (substr($mmk, 0, 1) == '_') continue;
// Обновляем значение метода
$method[$mmk] = $mmv;
}
// Обновляем информацию о методе в базе данных
SQLUpdate('methods', $method);
}
}
}
}
// Внедрение методов
if (isset($v['INJECTS']) && is_array($v['INJECTS'])) {
// Проходимся по всем внедренным методам
foreach ($v['INJECTS'] as $class_name => $methods) {
// Добавляем класс
addClass($class_name);
// Проходимся по всем методам внедренного класса
foreach ($methods as $mk => $mv) {
// Разделяем имя объекта и имя метода
list($object, $method_name) = explode('.', $mk);
// Добавляем объект класса
addClassObject($class_name, $object);
// Если файл метода не существует, создаем его
if (!file_exists(dirname(__FILE__) . "/" . $mv . ".php")) {
$code = '<?php' . "\n\n";
@SaveFile(dirname(__FILE__) . "/" . $mv . ".php", $code);
}
// Внедряем код метода в объект
injectObjectMethodCode($mk, 'SDevices', "require(DIR_MODULES.'devices/" . $mv . ".php');");
}
}
}
}
// Подписываемся на события 'COMMAND' и 'MINUTELY' для модуля устройств
subscribeToEvent('devices', 'COMMAND');
subscribeToEvent('devices', 'MINUTELY');
// Обновление камер
$objects = getObjectsByClass('SCameras');
$total = count($objects);
for ($i = 0; $i < $total; $i++) {
$ot = $objects[$i]['TITLE'];
callMethod($ot . '.updatePreview');
}
// Обновление объектов устройств
$devices = SQLSelect("SELECT ID, LINKED_OBJECT FROM devices");
foreach ($devices as $device) {
SQLExec("UPDATE objects SET `SYSTEM`='sdevice" . $device['ID'] . "' WHERE TITLE='" . DBSafe($device['LINKED_OBJECT']) . "' AND `SYSTEM`=''");
}
// Обновление объектов групп устройств
$this->updateGroupObjects();
}
/**
* processSubscription
*
* Эта функция обрабатывает подписки на события.
* Она обрабатывает различные операции, такие как клик по устройству, получение устройства, получение устройств,
* загрузка всех устройств HTML, клик по устройству и получение устройств.
*
* @method void processSubscription($event, &$details)
* @param string $event Имя события
* @param array $details Детали события
* @return void
* @see module
* @since 0.1
*/
function processSubscription($event, &$details)
{
// Если событие равно 'COMMAND' и есть идентификатор участника
if ($event == 'COMMAND' && $details['member_id']) {
// Включаем файл для обработки команды
include_once(dirname(__FILE__) . '/processCommand.inc.php');
}
// Если событие равно 'MINUTELY'
if ($event == 'MINUTELY') {
// Выбираем все активные точки планировщика устройств
$points = SQLSelect("SELECT devices_scheduler_points.*, devices.LINKED_OBJECT FROM devices_scheduler_points LEFT JOIN devices ON devices_scheduler_points.DEVICE_ID=devices.ID WHERE ACTIVE=1");
$total = count($points);
// Проходимся по всем точкам планировщика
for ($i = 0; $i < $total; $i++) {
$rec = $points[$i];
// Если дни не установлены, пропускаем текущую итерацию
if ($rec['SET_DAYS'] === '') {
continue;
}
// Разделяем дни на отдельные элементы
$run_days = explode(',', $rec['SET_DAYS']);
// Если текущий день не входит в список дней, пропускаем текущую итерацию
if (!in_array(date('w'), $run_days)) {
continue;
}
// Преобразуем время запуска в метку времени
$tm = strtotime(date('Y-m-d') . ' ' . $rec['SET_TIME']);
// Вычисляем разницу между текущим временем и временем запуска
$diff = time() - $tm;
// Преобразуем время последнего запуска в метку времени
$latestRun = strtotime($rec['LATEST_RUN']);
// Вычисляем разницу между текущим временем и временем последнего запуска
$diff2 = time() - $latestRun;
// Если разница меньше нуля, разница больше или равна 10 минутам или разница между последним запуском и текущим временем меньше или равна 10 минутам, пропускаем текущую итерацию
if ($diff < 0 || $diff >= 10 * 60 || $diff2 <= 10 * 60) {
continue;
}
// Проверяем доступ к точке планировщика
if (!checkAccess('spoint', $rec['ID'])) continue;
// Получаем связанный объект
$linked_object = $rec['LINKED_OBJECT'];
// Удаляем связанный объект из записи
unset($rec['LINKED_OBJECT']);
// Обновляем время последнего запуска
$rec['LATEST_RUN'] = date('Y-m-d H:i:s');
// Обновляем запись в базе данных
SQLUpdate('devices_scheduler_points', $rec);
// Записываем сообщение о запуске точки планировщика
DebMes("Running point: " . $linked_object . '.' . $rec['LINKED_METHOD'] . ' (' . $rec['VALUE'] . ')', 'devices_schedule');
// Если значение установлено, вызываем метод с этим значением
if ($rec['VALUE'] != '') {
callMethodSafe($linked_object . '.' . $rec['LINKED_METHOD'], array('value' => $rec['VALUE']));
} else {
// Если значение не установлено, вызываем метод без параметров
callMethodSafe($linked_object . '.' . $rec['LINKED_METHOD']);
}
}
}
}
/**
* computePermutations
*
* Эта функция вычисляет все возможные перестановки элементов массива.
* Она использует рекурсивный подход для генерации всех возможных комбинаций.
*
* @method array computePermutations($array)
* @param array $array Массив для перестановок
* @return array Все возможные перестановки элементов массива
* @see module
* @since 0.1
*/
function computePermutations($array)
{
$result = [];
$recurse = function ($array, $start_i = 0) use (&$result, &$recurse) {
// Если индекс начала равен индексу последнего элемента массива, добавляем текущую перестановку в результат
if ($start_i === count($array) - 1) {
array_push($result, $array);
}
// Проходимся по всем элементам массива, начиная с указанного индекса
for ($i = $start_i; $i < count($array); $i++) {
// Меняем местами элементы массива по индексам $i и $start_i
$t = $array[$i];
$array[$i] = $array[$start_i];
$array[$start_i] = $t;
// Рекурсивно вызываем функцию для следующего индекса
$recurse($array, $start_i + 1);
// Восстанавливаем исходный порядок элементов массива
$t = $array[$i];
$array[$i] = $array[$start_i];
$array[$start_i] = $t;
}
};
// Вызываем рекурсивную функцию для начального массива
$recurse($array);
// Возвращаем результат, содержащий все возможные перестановки
return $result;
}
/**
* generate_combinations
*
* Эта функция генерирует все возможные комбинации среди набора вложенных массивов.
*
* @method array generate_combinations(array $data, array &$all = array(), array $group = array(), $value = null, $i = 0)
* @param array $data Входной массив-контейнер.
* @param array $all Конечный контейнер (используется внутри функции).
* @param array $group Подконтейнер (используется внутри функции).
* @param mixed $val Значение для добавления (используется внутри функции).
* @param int $i Индекс ключа (используется внутри функции).
* @return array Все возможные комбинации среди набора вложенных массивов.
* @see module
* @since 0.1
*/
function generate_combinations(array $data, array &$all = array(), array $group = array(), $value = null, $i = 0, $key = null)
{
$keys = array_keys($data);
// Если значение установлено, добавляем его в подконтейнер
if (isset($value) === true) {
$group[$key] = $value;
}
// Если индекс больше или равен количеству элементов в данных, добавляем подконтейнер в конечный контейнер
if ($i >= count($data)) {
array_push($all, $group);
} else {
$currentKey = $keys[$i];
$currentElement = $data[$currentKey];
// Если в текущем элементе данных нет элементов, рекурсивно вызываем функцию для следующего индекса
if (count($data[$currentKey]) <= 0) {
$this->generate_combinations($data, $all, $group, null, $i + 1, $currentKey);
} elseif (is_array($currentElement)) {
// Если текущий элемент является массивом, проходимся по всем его элементам и рекурсивно вызываем функцию для каждого из них
foreach ($currentElement as $val) {
$this->generate_combinations($data, $all, $group, $val, $i + 1, $currentKey);
}
}
}
// Возвращаем конечный контейнер с всеми сгенерированными комбинациями
return $all;
}
/**
* homebridgeSync
*
* Эта функция синхронизирует устройства с HomeBridge.
* Она проверяет доступность HomeBridge и, если доступна, включает файл для синхронизации.
*
* @method void homebridgeSync($device_id = 0, $force_refresh = 0)
* @param int $device_id Идентификатор устройства (по умолчанию 0).
* @param int $force_refresh Принудительное обновление (по умолчанию 0).
* @return void
* @see module
* @since 0.1
*/
function homebridgeSync($device_id = 0, $force_refresh = 0)
{
// Проверяем доступность HomeBridge
if ($this->isHomeBridgeAvailable()) {
// Включаем файл для синхронизации с HomeBridge
include_once(dirname(__FILE__) . '/homebridgeSync.inc.php');
}
}
/**
* admin
*
* Функция обрабатывает административный интерфейс модуля.
* Она обрабатывает различные действия, такие как синхронизация с HomeBridge, поиск устройств, управление группами,
* управление расписанием, редактирование устройств, быстрое редактирование,
* рендеринг структуры и удаление устройств.
*
* @method void admin(&$out)
* @param array $out Массив для вывода данных
* @return void
* @see module
* @since 0.1
*/
function admin(&$out)
{
// Проверяем, установлен ли источник данных и не переданы ли параметры GET или POST
if (isset($this->data_source) && !$_GET['data_source'] && !$_POST['data_source']) {
$out['SET_DATASOURCE'] = 1;
}
// Если источник данных равен 'devices' или пустой строке
if ($this->data_source == 'devices' || $this->data_source == '') {
// Если режим равен 'homebridgesync', вызываем функцию синхронизации с HomeBridge и перенаправляем на главную страницу
if ($this->mode == 'homebridgesync') {
$this->homebridgeSync();
$this->redirect("?");
}
// Если режим просмотра пустой или равен 'search_devices', вызываем функцию поиска устройств
if ($this->view_mode == '' || $this->view_mode == 'search_devices') {
$this->search_devices($out);
// Если доступна HomeBridge, устанавливаем флаг ENABLE_HOMEBRIDGE
if ($this->isHomeBridgeAvailable()) {
$out['ENABLE_HOMEBRIDGE'] = 1;
}
}
// Если режим просмотра равен 'manage_groups', вызываем функцию управления группами
if ($this->view_mode == 'manage_groups') {
$this->manage_groups($out);
}
// Если режим просмотра равен 'schedule', вызываем функцию управления расписанием
if ($this->view_mode == 'schedule') {
$this->manage_schedule($out);
}
// Если режим просмотра равен 'edit_devices', вызываем функцию редактирования устройств
if ($this->view_mode == 'edit_devices') {
$this->edit_devices($out, $this->id);
}
// Если режим просмотра равен 'quick_edit', вызываем функцию быстрого редактирования
if ($this->view_mode == 'quick_edit') {
$this->quick_edit($out);
}
// Если режим просмотра равен 'render_structure', вызываем функцию рендеринга структуры
if ($this->view_mode == 'render_structure') {
$this->renderStructure();
$this->redirect("?");
}
// Если режим просмотра равен 'delete_devices', вызываем функцию удаления устройств
if ($this->view_mode == 'delete_devices') {
$this->delete_devices($this->id);
$this->redirect("?type=" . gr('type') . '&location_id=' . gr('location_id') . '&group_name=' . gr('group_name'));
}
}
}
/**
* isHomeBridgeAvailable
*
* Эта функция проверяет доступность HomeBridge.
* Она выполняет запрос к базе данных, чтобы найти объект с названием 'HomeBridge'.
* Если такой объект существует, функция возвращает true, иначе false.
*
* @method bool isHomeBridgeAvailable()
* @return bool true если HomeBridge доступна, иначе false
* @see module
* @since 0.1
*/
function isHomeBridgeAvailable()
{
//return true; // temporary
// Выполняем запрос к базе данных, чтобы найти объект с названием 'HomeBridge'
$tmp = SQLSelectOne("SELECT ID FROM objects WHERE TITLE='HomeBridge'");
// Если объект найден, возвращаем true
if (isset($tmp['ID'])) {
return true;
} else {
// Если объект не найден, возвращаем false
return false;
}
}
/**
* manage_groups
*
* Эта функция управляет группами устройств.
* Она включает файл для управления группами устройств.
*
* @method void manage_groups(&$out)
* @param array $out Массив для вывода данных
* @return void
* @see module
* @since 0.1
*/
function manage_groups(&$out)
{
// Включаем файл для управления группами устройств
require(dirname(__FILE__) . '/devices_manage_groups.inc.php');
}
/**
* manage_schedule
*
* Эта функция управляет расписанием устройств.
* Она включает файл для управления расписанием устройств.
*
* @method void manage_schedule(&$out)
* @param array $out Массив для вывода данных
* @return void
* @see module
* @since 0.1
*/
function manage_schedule(&$out)
{
// Включаем файл для управления расписанием устройств
require(dirname(__FILE__) . '/devices_manage_schedule.inc.php');
}
/**
* usual
*
* Эта функция отвечает за обычный режим работы модуля.
* Она обрабатывает различные действия, такие как поиск устройств, управление группами,
* управление расписанием, редактирование устройств, быстрое редактирование,
* удаление устройств и рендеринг структуры.
*
* @method void usual(&$out)
* @param array $out Массив для вывода данных
* @return void
* @see module
* @since 0.1
*/
function usual(&$out)
{
// Получаем значение параметра 'view' из запроса
$view = gr('view');
// Если значение параметра 'view' установлено, присваиваем его свойству класса
if ($view) $this->view = $view;
// Проверяем, является ли текущий запрос AJAX-запросом
if ($this->ajax) {
// Устанавливаем заголовки ответа
header("HTTP/1.0: 200 OK\n");
header('Content-Type: text/html; charset=utf-8');
// Получаем значение параметра 'op' из запроса
$op = gr('op');
// Инициализируем массив для хранения результатов
$res = array();
// Если значение параметра 'op' равно 'clicked'
if ($op == 'clicked') {
// Получаем значение параметра 'object' из запроса
$object = gr('object');
// Если значение параметра 'object' не пустое
if ($object != '') {
// Выполняем запрос к базе данных, чтобы найти устройство с соответствующим связанным объектом
$device_rec = SQLSelectOne("SELECT ID, TITLE FROM devices WHERE LINKED_OBJECT='" . DBSafe($object) . "'");
// Если устройство найдено
if ($device_rec['ID']) {
// Обновляем время последнего клика по устройству в базе данных
SQLExec("UPDATE devices SET CLICKED=NOW() WHERE ID='" . $device_rec['ID'] . "'");
// Записываем действие в журнал
logAction('device_clicked', $device_rec['TITLE']);
}
}
}
// Если значение параметра 'op' равно 'get_device'
if ($op == 'get_device') {
// Получаем значение параметра 'id' из запроса
$id = gr('id');
// Обрабатываем устройство с указанным идентификатором и сохраняем результат в массив результатов
$res = $this->processDevice($id, $view);
}
// Если значение параметра 'op' равно 'get_devices'
if ($op == 'get_devices') {
// Получаем значение параметра 'ids' из запроса
$ids = gr('ids');
// Разделяем строку идентификаторов на отдельные элементы
$tmp = explode(',', $ids);
// Инициализируем массив для хранения результатов
$res = array();
// Проходимся по всем идентификаторам
foreach ($tmp as $id) {
// Если идентификатор пустой, пропускаем текущую итерацию
if (!$id) continue;
// Обрабатываем устройство с указанным идентификатором
$record = $this->processDevice($id, $view);
// Если устройство не найдено, пропускаем текущую итерацию
if (!$record['DEVICE_ID']) continue;
// Добавляем обработанное устройство в массив результатов
$res['devices'][] = $record;
}
}
// Если значение параметра 'op' равно 'loadAllDevicesHTML'
if ($op == 'loadAllDevicesHTML') {
// Выполняем запрос к базе данных, чтобы получить все устройства, которые не являются системными и не архивированы
$devices = SQLSelect("SELECT ID, LINKED_OBJECT FROM devices WHERE SYSTEM_DEVICE=0 AND ARCHIVED=0");
// Получаем общее количество устройств
$total = count($devices);
// Проходимся по всем устройствам
for ($i = 0; $i < $total; $i++) {
// Если устройство имеет связанный объект
if ($devices[$i]['LINKED_OBJECT']) {
// Обрабатываем устройство и сохраняем результат в переменную
$processed = $this->processDevice($devices[$i]['ID'], $view);
// Сохраняем HTML-представление устройства в массиве устройств
$devices[$i]['HTML'] = $processed['HTML'];
}
}
// Сохраняем массив устройств в массив результатов
$res['DEVICES'] = $devices;
}
// Выводим результаты в формате JSON и завершаем выполнение скрипта
echo json_encode($res);
exit;
}
// Проверяем, является ли текущее действие родительского объекта 'apps'
if ($this->owner->action == 'apps') {
// Если действие равно 'apps', перенаправляем на страницу модуля устройств
//$this->redirect(ROOTHTML."module/devices.html");
}
// Получаем значение параметра 'location_id' из запроса
$location_id = gr('location_id');
// Получаем значение параметра 'type' из запроса
$type = gr('type');
// Получаем значение параметра 'collection' из запроса
$collection = gr('collection');
// Инициализируем строку запроса
$qry = "1";
// Получаем значение параметра 'linked_object' из запроса
$linked_object = gr('linked_object');
// Если значение параметра 'linked_object' установлено
if ($linked_object) {
// Выполняем запрос к базе данных, чтобы найти устройство с соответствующим связанным объектом
$device_rec = SQLSelectOne("SELECT ID FROM devices WHERE LINKED_OBJECT='" . DbSafe($linked_object) . "'");
// Если устройство найдено
if ($device_rec['ID']) {
// Присваиваем идентификатор устройства свойству класса
$this->id = $device_rec['ID'];
}
}
// Генерируем уникальный идентификатор для устройства
if (isset($this->id)) {
$out['UNIQ'] = uniqid('dev' . $this->id);
// Добавляем условие в строку запроса, чтобы выбрать устройство с указанным идентификатором
$qry .= " AND devices.ID=" . (int)$this->id;
// Устанавливаем флаг, что мы работаем с одним устройством
$out['SINGLE_DEVICE'] = 1;
// Устанавливаем режим просмотра
$out['VIEW'] = $this->view;
}
// Если установлены параметры 'location_id', 'type' или 'collection'
if ($location_id || $type || $collection) {
// Инициализируем строку запроса и порядок сортировки
$qry = "1 AND SYSTEM_DEVICE=0 AND ARCHIVED=0";
$orderby = 'locations.PRIORITY DESC, LOCATION_ID, TYPE, TITLE';
// Если в параметре 'type' содержится идентификатор локации
if (preg_match('/loc(\d+)/', $type, $m)) {
// Извлекаем идентификатор локации и очищаем параметр 'type'
$location_id = $m[1];
$type = '';
}
// Если в параметре 'type' содержится имя коллекции
if (preg_match('/col\_(\w+)/', $type, $m)) {
// Извлекаем имя коллекции и очищаем параметр 'type'
$collection = $m[1];
$type = '';
}
// Если установлен параметр 'location_id'
if ($location_id) {
// Если 'location_id' не равен 'all'
if ($location_id != 'all') {
// Добавляем условие в строку запроса, чтобы выбрать устройства с указанным идентификатором локации
$qry .= " AND devices.LOCATION_ID=" . (int)$location_id;
// Выполняем запрос к базе данных, чтобы получить информацию о локации
$location = SQLSelectOne("SELECT * FROM locations WHERE ID=" . (int)$location_id);
// Сохраняем информацию о локации в массиве вывода
foreach ($location as $k => $v) {
$out['LOCATION_' . $k] = $v;
}
// Сохраняем название локации в массиве вывода
$out['TITLE'] = $location['TITLE'];
} else {
// Если 'location_id' равен 'all', устанавливаем соответствующий флаг в массиве вывода
$out['LOCATION_ID'] = 'All';
// Добавляем условие в строку запроса, чтобы выбрать все устройства
$qry .= " AND 1";
}
}
// Если установлен параметр 'type'
if ($type) {
// Если 'type' не равен 'all'
if ($type != 'all') {
// Добавляем условие в строку запроса, чтобы выбрать устройства с указанным типом
$qry .= " AND devices.TYPE LIKE '" . DBSafe($type) . "'";
// Сохраняем название типа устройства в массиве вывода
$out['TITLE'] = $this->device_types[$type]['TITLE'];
} else {
// Если 'type' равен 'all', изменяем порядок сортировки
$orderby = 'TYPE, locations.PRIORITY DESC, locations.TITLE, LOCATION_ID, TITLE';
}
// Сохраняем тип устройства в массиве вывода
$out['TYPE'] = $type;
}
// Если установлена коллекция
if ($collection != '') {
// Получаем идентификаторы устройств, входящих в коллекцию
$ids = $this->getCollectionIds($collection);
// Добавляем условие в строку запроса, чтобы выбрать устройства с указанными идентификаторами
$qry .= " AND devices.ID IN (" . implode(',', $ids) . ")";
// Сохраняем название коллекции в массиве вывода
$out['TITLE'] = constant('LANG_DEVICES_COLLECTION_' . strtoupper($collection));
// Сохраняем имя коллекции в массиве вывода
$out['COLLECTION'] = $collection;
}
// Инициализируем переменные для хранения названий локации и типа устройства
$location_title = '';
$type_title = '';
// Выполняем запрос к базе данных, чтобы получить устройства, соответствующие условиям запроса
$devices = SQLSelect("SELECT devices.*, locations.TITLE as LOCATION_TITLE FROM devices LEFT JOIN locations ON devices.LOCATION_ID=locations.ID WHERE $qry ORDER BY $orderby");
// Получаем общее количество устройств
$total = count($devices);
// Проходимся по всем устройствам
for ($i = 0; $i < $total; $i++) {
// Если тип устройства равен 'all'
if ($type == 'all') {
// Получаем название типа устройства
$devices[$i]['LOCATION_TITLE'] = $this->device_types[$devices[$i]['TYPE']]['TITLE'];
// Если название типа устройства отличается от предыдущего
if ($devices[$i]['LOCATION_TITLE'] != $location_title) {
// Устанавливаем флаг, что это новая локация
$devices[$i]['NEW_LOCATION'] = 1;
// Сохраняем текущее название типа устройства
$location_title = $devices[$i]['LOCATION_TITLE'];
}
} else {
// Если название типа устройства отличается от предыдущего и не установлено название локации в массиве вывода
if ($devices[$i]['LOCATION_TITLE'] != $location_title && !isset($out['LOCATION_TITLE'])) {
// Устанавливаем флаг, что это новая локация
$devices[$i]['NEW_LOCATION'] = 1;
// Сохраняем текущее название типа устройства
$location_title = $devices[$i]['LOCATION_TITLE'];
}
// Если название типа устройства отличается от предыдущего
if ($this->device_types[$devices[$i]['TYPE']]['TITLE'] != $type_title) {
// Сохраняем текущее название типа устройства
$type_title = $this->device_types[$devices[$i]['TYPE']]['TITLE'];
// Устанавливаем флаг, что это новый тип устройства
$devices[$i]['NEW_TYPE'] = 1;
}
}
} else {
// Устанавливаем порядок сортировки
$orderby = 'locations.PRIORITY DESC, locations.TITLE, LOCATION_ID, TYPE, TITLE';
// Добавляем условие в строку запроса, чтобы выбрать все устройства, которые не являются системными и не архивированы
$qry .= " AND SYSTEM_DEVICE=0 AND ARCHIVED=0";
// Устанавливаем флаг, что мы работаем со всеми устройствами
$out['ALL_DEVICES'] = 1;
// Выполняем запрос к базе данных, чтобы получить все устройства, которые не являются системными и не архивированы
$devices = SQLSelect("SELECT devices.*, locations.TITLE as LOCATION_TITLE FROM devices LEFT JOIN locations ON devices.LOCATION_ID=locations.ID WHERE $qry ORDER BY $orderby");
// Выполняем запрос к базе данных, чтобы получить недавно использованные устройства
$recent_devices = SQLSelect("SELECT devices.* FROM devices WHERE !IsNull(CLICKED) ORDER BY CLICKED DESC LIMIT 10");
}
// Если устройства найдены
if ($devices[0]['ID']) {
// Если установлены параметры 'location_id', 'type' или 'collection'
if ($location_id || $type || 1) {
// Получаем общее количество устройств
$total = count($devices);
// Проходимся по всем устройствам
for ($i = 0; $i < $total; $i++) {
// Если устройство имеет связанный объект
if ($devices[$i]['LINKED_OBJECT']) {
// Обрабатываем устройство и сохраняем результат в переменную
$processed = $this->processDevice($devices[$i]['ID'], $this->view);
// Сохраняем HTML-представление устройства в массиве устройств
$devices[$i]['HTML'] = $processed['HTML'];
}
}
}
// Сохраняем массив устройств в массиве вывода
$out['DEVICES'] = $devices;
// Если свойство класса 'id' установлено
if ($this->id) {
// Завершаем выполнение функции
return;
}
}
// Выполняем запрос к базе данных, чтобы получить все локации, упорядоченные по приоритету и названию
$locations = SQLSelect("SELECT ID, TITLE FROM locations ORDER BY PRIORITY DESC, TITLE");
// Получаем общее количество устройств
$total_devices = count($devices);
// Если устройства найдены
if ($total_devices) {
// Инициализируем массивы для хранения избранных, предупреждающих и проблемных устройств
$favorite_devices = array();
$warning_devices = array();
$problem_devices = array();
// Проходимся по всем устройствам
for ($idv = 0; $idv < $total_devices; $idv++) {
// Если устройство помечено как избранное
if ($devices[$idv]['FAVORITE']) {
// Добавляем устройство в массив избранных устройств
$favorite_devices[] = $devices[$idv];
} elseif ($devices[$idv]['LINKED_OBJECT']) {
// Если устройство имеет связанный объект
// Проверяем, является ли устройство предупреждающим
if (
gg($devices[$idv]['LINKED_OBJECT'] . '.normalValue') == '0' &&
gg($devices[$idv]['LINKED_OBJECT'] . '.notify') == '1'
) {
// Добавляем устройство в массив предупреждающих устройств
$warning_devices[] = $devices[$idv];
// Устанавливаем флаг, что это новая секция
$warning_devices[0]['NEW_SECTION'] = 1;
// Устанавливаем название секции
$warning_devices[0]['SECTION_TITLE'] = LANG_WARNING;
} elseif (
// Проверяем, является ли устройство проблемным
($devices[$idv]['TYPE'] == 'motion' ||
$devices[$idv]['TYPE'] == 'openclose' ||
$devices[$idv]['TYPE'] == 'leak' ||
$devices[$idv]['TYPE'] == 'smoke' ||
$devices[$idv]['TYPE'] == 'counter' ||
preg_match('/^sensor/', $devices[$idv]['TYPE']) ||
$this->device_types[$devices[$idv]['TYPE']]['PARENT_CLASS'] == 'SSensors' ||
(int)gg($devices[$idv]['LINKED_OBJECT'] . '.aliveTimeout') > 0
) && gg($devices[$idv]['LINKED_OBJECT'] . '.alive') === '0'
) {
// Добавляем устройство в массив проблемных устройств
$problem_devices[] = $devices[$idv];
// Устанавливаем флаг, что это новая секция
$problem_devices[0]['NEW_SECTION'] = 1;
// Устанавливаем название секции
$problem_devices[0]['SECTION_TITLE'] = LANG_OFFLINE;
}
}
}
// Если в массиве избранных устройств есть элементы
if (count($favorite_devices) > 0) {
// Сортируем массив избранных устройств по значению 'FAVORITE'
usort($favorite_devices, function ($a, $b) {
if ($a['FAVORITE'] == $b['FAVORITE']) {
return 0;
}
return ($a['FAVORITE'] > $b['FAVORITE']) ? -1 : 1;
});
}
// Добавляем предупреждающие устройства в массив избранных устройств
foreach ($warning_devices as $device) {
$favorite_devices[] = $device;
}
// Если в массиве недавно использованных устройств есть элементы
if (isset($recent_devices[0]['ID'])) {
// Устанавливаем флаг, что это новая секция
$recent_devices[0]['NEW_SECTION'] = 1;
// Устанавливаем название секции
$recent_devices[0]['SECTION_TITLE'] = LANG_RECENTLY_USED;
// Проходимся по всем недавно использованным устройствам
foreach ($recent_devices as &$device) {
// Если устройство имеет связанный объект
if ($device['LINKED_OBJECT']) {
// Обрабатываем устройство и сохраняем результат в переменную
$processed = $this->processDevice($device['ID']);
// Сохраняем HTML-представление устройства в массиве устройств
$device['HTML'] = $processed['HTML'];
}
// Добавляем устройство в массив избранных устройств
$favorite_devices[] = $device;
}
}
// Добавляем проблемные устройства в массив избранных устройств
foreach ($problem_devices as $device) {
$favorite_devices[] = $device;
}
// Получаем общее количество устройств в массиве избранных устройств
$devices_count = count($favorite_devices);
// Если в массиве избранных устройств есть элементы
if ($devices_count > 0) {
// Создаем запись для секции избранных устройств
$loc_rec = array();
$loc_rec['ID'] = 0;
$loc_rec['TITLE'] = LANG_FAVORITES;
$loc_rec['DEVICES'] = $favorite_devices;
$loc_rec['DEVICES_TOTAL'] = $devices_count;
// Добавляем запись в начало массива локаций
array_unshift($locations, $loc_rec);
}
// Получаем общее количество локаций
$total = count($locations);
// Проходимся по всем локациям
for ($i = 0; $i < $total; $i++) {
// Если у локации есть идентификатор
if ($locations[$i]['ID']) {
// Инициализируем счетчик устройств
$devices_count = 0;
// Если есть устройства
if ($total_devices) {
// Проходимся по всем устройствам
for ($idv = 0; $idv < $total_devices; $idv++) {
// Если идентификатор локации устройства совпадает с идентификатором текущей локации
if ($devices[$idv]['LOCATION_ID'] == $locations[$i]['ID']) {
// Увеличиваем счетчик устройств
$devices_count++;
// Добавляем устройство в массив устройств текущей локации
$locations[$i]['DEVICES'][] = $devices[$idv];
}
}
}
// Сохраняем общее количество устройств в массиве локации
$locations[$i]['DEVICES_TOTAL'] = $devices_count;
}
// Устанавливаем индекс текущей локации
$locations[$i]['INDEX'] = $i;
}
// Сохраняем массив локаций в массиве вывода
$out['GROUPS'] = $locations;
// Инициализируем массив для хранения типов устройств
$types = array();
// Если свойство класса 'device_types' является массивом
if (is_array($this->device_types)) {
// Проходимся по всем типам устройств
foreach ($this->device_types as $k => $v) {
// Если у типа устройства есть название
if (isset($v['TITLE'])) {
// Создаем запись для типа устройства
$type_rec = array('NAME' => $k, 'TITLE' => $v['TITLE']);
// Выполняем запрос к базе данных, чтобы получить количество устройств данного типа
$tmp = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices WHERE SYSTEM_DEVICE=0 AND ARCHIVED=0 AND TYPE='" . $k . "'");
// Сохраняем количество устройств в записи
$type_rec['TOTAL'] = (int)$tmp['TOTAL'];
// Если количество устройств больше нуля
if ($type_rec['TOTAL'] > 0) {
// Добавляем запись в массив типов устройств
$types[] = $type_rec;
}
}
}
// Сортируем массив типов устройств по названию
usort($types, function ($a, $b) {
return strcmp($a["TITLE"], $b["TITLE"]);
});
}
// Обрабатываем коллекции устройств
$col_name = 'is_heating';
$col_ids = $this->getCollectionIds($col_name);
$col_total = count($col_ids) - 1;
$col = array('NAME' => 'col_' . $col_name, 'TITLE' => LANG_DEVICES_COLLECTION_IS_HEATING, 'TOTAL' => $col_total);
if ($col_total > 0) array_unshift($types, $col);
$col_name = 'is_on';
$col_ids = $this->getCollectionIds($col_name);
$col_total = count($col_ids) - 1;
$col = array('NAME' => 'col_' . $col_name, 'TITLE' => LANG_DEVICES_COLLECTION_IS_ON, 'TOTAL' => $col_total);
if ($col_total > 0) array_unshift($types, $col);
$col_name = 'is_open';
$col_ids = $this->getCollectionIds($col_name);
$col_total = count($col_ids) - 1;
$col = array('NAME' => 'col_' . $col_name, 'TITLE' => LANG_DEVICES_COLLECTION_IS_OPEN, 'TOTAL' => $col_total);
if ($col_total > 0) array_unshift($types, $col);
// Обрабатываем локации
$list_locations = $locations;
if (is_array($list_locations)) {
// Сортируем массив локаций по названию
usort($list_locations, function ($a, $b) {
return strcmp($a["TITLE"], $b["TITLE"]);
});
// Добавляем запись для локаций в массив типов устройств
$types[] = array('NAME' => '', 'TITLE' => LANG_LOCATION);
// Проходимся по всем локациям
foreach ($list_locations as $location) {
// Если название локации не равно 'Избранное'
if ($location['TITLE'] == LANG_FAVORITES) continue;
// Добавляем запись для локации в массив типов устройств
$types[] = array('NAME' => 'loc' . $location['ID'], 'TITLE' => $location['TITLE'], 'TOTAL' => $location['DEVICES_TOTAL']);
}
}
// Сохраняем массив типов устройств в массиве вывода
$out['TYPES'] = $types;
/**
* getCollectionIds
*
* Эта функция возвращает идентификаторы устройств, которые входят в указанную коллекцию.
* Она обрабатывает различные коллекции, такие как 'is_on', 'is_open', 'is_heating'.
*
* @method array getCollectionIds($collection)
* @param string $collection Название коллекции
* @return array Идентификаторы устройств, которые входят в указанную коллекцию
* @see module
* @since 0.1
*/
function getCollectionIds($collection)
{
$ids = array(0);
if ($collection == 'is_on') {
// Выполняем запрос к базе данных, чтобы получить устройства типа 'relay', 'dimmer', 'rgb'
$devices = SQLSelect("SELECT ID, LINKED_OBJECT FROM devices WHERE devices.TYPE IN ('relay','dimmer','rgb')");
// Проходимся по всем устройствам
foreach ($devices as $device) {
// Если статус устройства равен 'on'
if (gg($device['LINKED_OBJECT'] . '.status')) {
// Добавляем идентификатор устройства в массив идентификаторов
$ids[] = $device['ID'];
}
}
} elseif ($collection == 'is_open') {
// Выполняем запрос к базе данных, чтобы получить устройства типа 'openable', 'openclose'
$devices = SQLSelect("SELECT ID, LINKED_OBJECT FROM devices WHERE devices.TYPE IN ('openable','openclose')");
// Проходимся по всем устройствам
foreach ($devices as $device) {
// Если статус устройства равен 'off'
if (!gg($device['LINKED_OBJECT'] . '.status')) {
// Добавляем идентификатор устройства в массив идентификаторов
$ids[] = $device['ID'];
}
}
} elseif ($collection == 'is_heating') {
// Выполняем запрос к базе данных, чтобы получить устройства типа 'thermostat'
$devices = SQLSelect("SELECT ID, LINKED_OBJECT FROM devices WHERE devices.TYPE IN ('thermostat')");
// Проходимся по всем устройствам
foreach ($devices as $device) {
// Если статус устройства равен 'on'
if (gg($device['LINKED_OBJECT'] . '.relay_status')) {
// Добавляем идентификатор устройства в массив идентификаторов
$ids[] = $device['ID'];
}
}
}
// Возвращаем массив идентификаторов устройств
return $ids;
}
/**
* devices search
*
* Функция для поиска устройств.
* Она включает в себя логику поиска, определенную в файле 'devices_search.inc.php'.
*
* @method void devices_search(&$out)
* @param array $out Массив для вывода данных
* @return void
* @see module
* @since 0.1
*/
function search_devices(&$out)
{
// Включаем файл 'devices_search.inc.php', который содержит логику поиска устройств
require(dirname(__FILE__) . '/devices_search.inc.php');
}
/**
* devices edit/add
*
* Функция для редактирования или добавления устройств.
* Она включает в себя логику редактирования/добавления,
* определенную в файле 'devices_edit.inc.php'.
*
* @method void edit_devices(&$out, $id)
* @param array $out Массив для вывода данных
* @param int $id Идентификатор устройства для редактирования (0 для добавления нового устройства)
* @return void
* @see module
* @since 0.1
*/
function edit_devices(&$out, $id)
{
// Включаем файл 'devices_edit.inc.php', который содержит логику редактирования/добавления устройств
require(dirname(__FILE__) . '/devices_edit.inc.php');
}
/**
* quick_edit
*
* Функция для быстрого редактирования устройств.
* Она включает в себя логику быстрого редактирования, определенную в файле 'devices_quick_edit.inc.php'.
*
* @method void quick_edit(&$out)
* @param array $out Массив для вывода данных
* @return void
* @see module
* @since 0.1
*/
function quick_edit(&$out)
{
// Включаем файл 'devices_quick_edit.inc.php', который содержит логику быстрого редактирования устройств
require(dirname(__FILE__) . '/devices_quick_edit.inc.php');
}
/**
* devices delete record
*
* Функция для удаления записи об устройстве.
* Она также выполняет дополнительные действия, связанные с удалением устройства, такие как удаление связанных элементов, объектов и команд.
*
* @method void delete_devices($id)
* @param int $id Идентификатор устройства для удаления
* @return void
* @see module
* @since 0.1
*/
function delete_devices($id)
{
// Получаем запись об устройстве по идентификатору
$rec = SQLSelectOne("SELECT * FROM devices WHERE ID='$id'");
// Подготовка данных для удаления устройства из HomeBridge
$payload = array();
$payload['name'] = $rec['LINKED_OBJECT'];
sg('HomeBridge.to_remove', json_encode($payload));
// Удаление связанных элементов
$elements = SQLSelect("SELECT * FROM elements WHERE `SYSTEM`='sdevice" . $rec['ID'] . "'");
$total = count($elements);
for ($i = 0; $i < $total; $i++) {
SQLExec("DELETE FROM elm_states WHERE ELEMENT_ID=" . $elements[$i]['ID']);
SQLExec("DELETE FROM elements WHERE ID=" . $elements[$i]['ID']);
}
// Удаление связанных объектов
$objects = SQLSelect("SELECT ID FROM objects WHERE `SYSTEM`='sdevice" . $rec['ID'] . "'");
$total = count($objects);
for ($i = 0; $i < $total; $i++) {
deleteObject($objects[$i]['ID']);
}
// Удаление связанных команд
$tables = array('commands');
$total = count($tables);
for ($i = 0; $i < $total; $i++) {
SQLExec("DELETE FROM " . $tables[$i] . " WHERE `SYSTEM`='sdevice" . $rec['ID'] . "'");
}
// Удаление связей устройств
SQLExec("DELETE FROM devices_linked WHERE DEVICE1_ID='" . $rec['ID'] . "' OR DEVICE2_ID='" . $rec['ID'] . "'");
// Удаление самого устройства
SQLExec("DELETE FROM devices WHERE ID='" . $rec['ID'] . "'");
}
/**
* addDevice
*
* Функция для добавления нового устройства.
* Она принимает тип устройства и опции для настройки устройства, такие как связанный объект, название, локация и другие параметры.
*
* @method int addDevice($device_type, $options = 0)
* @param string $device_type Тип устройства
* @param array $options Опции для настройки устройства
* @return int Идентификатор добавленного устройства или 0 в случае ошибки
* @see module
* @since 0.1
*/
function addDevice($device_type, $options = 0)
{
// Устанавливаем словарь устройств
$this->setDictionary();
// Получаем детали типа устройства
$type_details = $this->getTypeDetails($device_type);
// Если опции не являются массивом, инициализируем их как пустой массив
if (!is_array($options)) {
$options = array();
}
// Если тип устройства не определен в словаре устройств, возвращаем 0
if (!is_array($this->device_types[$device_type])) {
return 0;
}
// Если указаны параметры для связанной таблицы и идентификатор записи в таблице
if ($options['TABLE'] && $options['TABLE_ID']) {
// Получаем запись из указанной таблицы
$table_rec = SQLSelectOne("SELECT * FROM " . $options['TABLE'] . " WHERE ID=" . $options['TABLE_ID']);
// Если запись не найдена, возвращаем 0
if (!$table_rec['ID']) {
return 0;
}
}
// Если указано связанное устройство
if ($options['LINKED_OBJECT'] != '') {
// Проверяем, существует ли уже устройство с таким связанным объектом
$old_device = SQLSelectOne("SELECT ID FROM devices WHERE LINKED_OBJECT LIKE '" . DBSafe($options['LINKED_OBJECT']) . "'");
// Если устройство найдено, возвращаем его идентификатор
if ($old_device['ID']) return $old_device['ID'];
// Иначе, сохраняем связанный объект в записи
$rec['LINKED_OBJECT'] = $options['LINKED_OBJECT'];
}
// Инициализируем запись для нового устройства
$rec = array();
$rec['TYPE'] = $device_type;
// Если указано название, сохраняем его в записи
if ($options['TITLE']) {
$rec['TITLE'] = $options['TITLE'];
} else {
// Иначе, устанавливаем название по умолчанию
$rec['TITLE'] = 'New device ' . date('H:i');
}
// Если указана локация, сохраняем ее в записи
if ($options['LOCATION_ID']) {
$rec['LOCATION_ID'] = $options['LOCATION_ID'];
}
// Добавляем запись в базу данных и сохраняем идентификатор нового устройства
$rec['ID'] = SQLInsert('devices', $rec);
// Если указана локация, получаем название локации
if ($rec['LOCATION_ID']) {
$location_title = getRoomObjectByLocation($rec['LOCATION_ID'], 1);
}
// Если не указан связанный объект, создаем новый объект для устройства
if (!$rec['LINKED_OBJECT']) {
$prefix = ucfirst($rec['TYPE']);
$new_object_title = $prefix . $this->getNewObjectIndex($type_details['CLASS']);
$object_id = addClassObject($type_details['CLASS'], $new_object_title, 'sdevice' . $rec['ID']);
$rec['LINKED_OBJECT'] = $new_object_title;
// Если название устройства по умолчанию, обновляем его на название связанного объекта
if (preg_match('/New device .+/', $rec['TITLE'])) {
$rec['TITLE'] = $rec['LINKED_OBJECT'];
}
// Обновляем запись в базе данных
SQLUpdate('devices', $rec);
}
// Если указаны параметры для связанной таблицы и идентификатор записи в таблице
if ($table_rec['ID']) {
// Добавляем устройство в связанную таблицу
$this->addDeviceToSourceTable($options['TABLE'], $table_rec['ID'], $rec['ID']);
}
// Если указано добавление устройства в меню
if ($options['ADD_MENU']) {
// Добавляем устройство в меню
$this->addDeviceToMenu($rec['ID']);
}
// Если указано добавление устройства в сцену
if ($options['ADD_SCENE']) {
// Добавляем устройство в сцену
$this->addDeviceToScene($rec['ID']);
}
// Возвращаем 1, указывая на успешное добавление устройства
return 1;
}
/**
* addDeviceToSourceTable
*
* Функция для добавления устройства в связанную таблицу.
* Она принимает имя таблицы, идентификатор записи в таблице и идентификатор устройства.
* Функция определяет свойства и методы связанного объекта устройства в зависимости от его типа и обновляет запись в таблице.
*
* @method void addDeviceToSourceTable($table_name, $table_id, $device_id)
* @param string $table_name Имя таблицы
* @param int $table_id Идентификатор записи в таблице
* @param int $device_id Идентификатор устройства
* @return void
* @see module
* @since 0.1
*/
function addDeviceToSourceTable($table_name, $table_id, $device_id)
{
// Получаем запись об устройстве по идентификатору
$rec = SQLSelectOne("SELECT * FROM devices WHERE ID=" . (int)$device_id);
// Устанавливаем словарь устройств
$this->setDictionary();
// Получаем детали типа устройства
$type_details = $this->getTypeDetails($rec['TYPE']);
// Если у устройства нет связанного объекта, возвращаем 0
if (!$rec['LINKED_OBJECT']) {
return 0;
}
// Получаем запись из указанной таблицы
$table_rec = SQLSelectOne("SELECT * FROM $table_name WHERE ID=" . DBSafe($table_id));
// Если запись не найдена, возвращаем 0
if (!$table_rec['ID']) {
return 0;
}
// Инициализируем переменные для связанного объекта, свойства и метода
$linked_object = $rec['LINKED_OBJECT'];
$linked_property = '';
$linked_method = '';
// Определяем свойство и метод в зависимости от класса родителя устройства
if ($type_details['PARENT_CLASS'] == 'SSensors') {
$linked_property = 'value';
} elseif ($type_details['PARENT_CLASS'] == 'SControllers') {
$linked_property = 'status';
}
// Определяем свойство в зависимости от типа устройства
if ($rec['TYPE'] == 'dimmer') {
$linked_property = 'level';
}
if ($rec['TYPE'] == 'rgb') {
$linked_property = 'color';
}
if ($rec['TYPE'] == 'motion') {
$linked_property = 'status';
$linked_method = 'motionDetected';
}
if ($rec['TYPE'] == 'button') {
$linked_property = 'status';
$linked_method = 'pressed';
}
if ($rec['TYPE'] == 'switch' || $rec['TYPE'] == 'openclose') {
$linked_property = 'status';
}
// Если запись найдена, обновляем ее с новыми значениями связанного объекта, свойства и метода
if ($table_rec['ID']) {
$table_rec['LINKED_OBJECT'] = $linked_object;
$table_rec['LINKED_PROPERTY'] = $linked_property;
$table_rec['LINKED_METHOD'] = $linked_method;
SQLUpdate($table_name, $table_rec);
}
}
/**
* addDeviceToMenu
*
* Функция для добавления устройства в меню.
* Она принимает идентификатор устройства и идентификатор родительского элемента меню (необязательно).
* Функция определяет тип элемента меню в зависимости от типа устройства и обновляет или создает запись в таблице команд.
*
* @method void addDeviceToMenu($device_id, $parent_id = 0)
* @param int $device_id Идентификатор устройства
* @param int $parent_id Идентификатор родительского элемента меню (необязательно)
* @return void
* @see module
* @since 0.1
*/
function addDeviceToMenu($device_id, $add_menu_id = 0)
{
// Получаем запись об устройстве по идентификатору
$rec = SQLSelectOne("SELECT * FROM devices WHERE ID=" . (int)$device_id);
// Если запись не найдена, возвращаем 0
if (!$rec['ID']) {
return 0;
}
// Получаем запись из таблицы команд, связанную с устройством
$menu_rec = SQLSelectOne("SELECT * FROM commands WHERE `SYSTEM`='" . 'sdevice' . $rec['ID'] . "'");
// Если запись не найдена, инициализируем новую запись
if (!$menu_rec['ID']) {
$menu_rec = array();
}
// Если заголовок не указан, используем название устройства
if (!$menu_rec['TITLE']) {
$menu_rec['TITLE'] = $rec['TITLE'];
}
// Устанавливаем идентификатор родительского элемента меню
$menu_rec['PARENT_ID'] = (int)$add_menu_id;
// Устанавливаем системный идентификатор
$menu_rec['SYSTEM'] = 'sdevice' . $rec['ID'];
// Устанавливаем связанный объект
$menu_rec['LINKED_OBJECT'] = $rec['LINKED_OBJECT'];
// Определяем тип элемента меню и связанное свойство в зависимости от типа устройства
if ($rec['TYPE'] == 'relay' || $rec['TYPE'] == 'switch') {
$menu_rec['TYPE'] = 'switch';
$menu_rec['LINKED_PROPERTY'] = 'status';
$menu_rec['CUR_VALUE'] = getGlobal($menu_rec['LINKED_OBJECT'] . '.' . $menu_rec['LINKED_PROPERTY']);
} elseif ($rec['TYPE'] == 'button') {
$menu_rec['TYPE'] = 'button';
$menu_rec['LINKED_PROPERTY'] = '';
$menu_rec['ONCHANGE_METHOD'] = 'pressed';
} elseif ($rec['TYPE'] == 'dimmer') {
$menu_rec['TYPE'] = 'sliderbox';
$menu_rec['MIN_VALUE'] = '0';
$menu_rec['MAX_VALUE'] = '100';
$menu_rec['STEP_VALUE'] = '1';
$menu_rec['LINKED_PROPERTY'] = 'level';
$menu_rec['CUR_VALUE'] = getGlobal($menu_rec['LINKED_OBJECT'] . '.' . $menu_rec['LINKED_PROPERTY']);
} else {
$menu_rec['TYPE'] = 'object';
}
// Если запись уже существует, обновляем ее
if ($menu_rec['ID']) {
SQLUpdate('commands', $menu_rec);
} else {
// Иначе, создаем новую запись
$menu_rec['ID'] = SQLInsert('commands', $menu_rec);
}
// Возвращаем идентификатор созданного или обновленного элемента меню
return $menu_rec['ID'];
}
/**
* addDeviceToScene
*
* Функция для добавления устройства в сцену.
* Она принимает идентификатор устройства и идентификатор сцены (необязательно).
* Функция определяет тип элемента сцены в зависимости от типа устройства и обновляет или создает запись в таблице элементов.
*
* @method void addDeviceToScene($device_id, $scene_id = 0)
* @param int $device_id Идентификатор устройства
* @param int $scene_id Идентификатор сцены (необязательно)
* @return void
* @see module
* @since 0.1
*/
function addDeviceToScene($device_id, $add_scene_id = 0)
{
// Получаем запись об устройстве по идентификатору
$rec = SQLSelectOne("SELECT * FROM devices WHERE ID=" . (int)$device_id);
// Если запись не найдена, возвращаем 0
if (!$rec['ID']) {
return 0;
}
// Если идентификатор сцены не указан, получаем первую сцену из базы данных
if (!$add_scene_id) {
$scene_rec = SQLSelectOne("SELECT ID FROM scenes ORDER BY ID LIMIT 1");
// Если сцена найдена, используем ее идентификатор
if ($scene_rec['ID']) {
$add_scene_id = $scene_rec['ID'];
} else {
return 0;
}
}
// Получаем запись из таблицы элементов, связанную с устройством и сценой
$element_rec = SQLSelectOne("SELECT * FROM elements WHERE SCENE_ID=" . (int)$add_scene_id . " AND `SYSTEM`='" . 'sdevice' . $rec['ID'] . "'");
// Если запись не найдена, инициализируем новую запись и данные мастера
if (!$element_rec['ID']) {
$element_rec = array();
$wizard_data = array();
} else {
// Иначе, декодируем данные мастера из записи
$wizard_data = json_decode($element_rec['WIZARD_DATA'], true);
}
// Устанавливаем идентификатор сцены
$element_rec['SCENE_ID'] = (int)$add_scene_id;
// Устанавливаем системный идентификатор
$element_rec['SYSTEM'] = 'sdevice' . $rec['ID'];
// Если координаты не указаны, задаем случайные значения
if (!$element_rec['TOP'] && !$element_rec['LEFT']) {
$element_rec['TOP'] = 10 + rand(0, 300);
$element_rec['LEFT'] = 10 + rand(0, 300);
}
// Если стиль CSS не указан, используем стиль по умолчанию
if (!$element_rec['CSS_STYLE']) {
$element_rec['CSS_STYLE'] = 'default';
}
// Кодируем данные мастера обратно в JSON
$element_rec['WIZARD_DATA'] = json_encode($wizard_data) . '';
// Устанавливаем флаг фона
$element_rec['BACKGROUND'] = 0;
// Устанавливаем связанный объект
$element_rec['LINKED_OBJECT'] = $rec['LINKED_OBJECT'];
// Устанавливаем название
$element_rec['TITLE'] = $rec['TITLE'];
// Устанавливаем флаг легкой конфигурации
$element_rec['EASY_CONFIG'] = 1;
// Инициализируем единицу измерения связанного свойства
$linked_property_unit = '';
// Устанавливаем тип элемента сцены
$element_rec['TYPE'] = 'device';
// Устанавливаем идентификатор устройства
$element_rec['DEVICE_ID'] = $rec['ID'];
/*
// Закомментированный код для определения типа элемента сцены и связанного свойства в зависимости от типа устройства
if ($rec['TYPE']=='relay' || $rec['TYPE']=='dimmer' || $rec['TYPE']=='switch') {
$element_rec['TYPE'] = 'switch';
$element_rec['LINKED_PROPERTY'] = 'status';
} elseif ($rec['TYPE']=='button') {
$element_rec['TYPE'] = 'button';
} elseif ($rec['TYPE']=='motion') {
$element_rec['TYPE'] = 'warning';
$element_rec['LINKED_PROPERTY'] = 'status';
$element_rec['CSS_STYLE']='motion';
} elseif ($rec['TYPE']=='sensor_temp') {
$element_rec['CSS_STYLE']='temp';
$linked_property_unit='°C';
} elseif ($rec['TYPE']=='sensor_humidity') {
$element_rec['CSS_STYLE']='humidity';
$linked_property_unit='%';
} else {
$element_rec['TYPE']='object';
}
// Дополнительная логика для типов датчиков температуры и влажности
if ($rec['TYPE']=='sensor_temp' || $rec['TYPE']=='sensor_humidity') {
$element_rec['TYPE'] = 'informer';
$element_rec['LINKED_PROPERTY'] = 'value';
$wizard_data['STATE_HIGH']=1;
$wizard_data['STATE_HIGH_VALUE']='%'.$element_rec['LINKED_OBJECT'].'.maxValue%';
$wizard_data['STATE_LOW']=1;
$wizard_data['STATE_LOW_VALUE']='%'.$element_rec['LINKED_OBJECT'].'.maxValue%';
$wizard_data['UNIT']=$linked_property_unit;
}
*/
// Кодируем данные мастера обратно в JSON
$element_rec['WIZARD_DATA'] = json_encode($wizard_data);
// Если запись уже существует, обновляем ее
if ($element_rec['ID']) {
SQLUpdate('elements', $element_rec);
} else {
// Иначе, создаем новую запись
$element_rec['ID'] = SQLInsert('elements', $element_rec);
// Получаем связанный объект
$linked_object = $rec['LINKED_OBJECT'];
// Если тип элемента сцены - переключатель
if ($element_rec['TYPE'] == 'switch') {
// Создаем запись состояния для 'off'
$state_rec = array();
$state_rec['TITLE'] = 'off';
$state_rec['HTML'] = $element_rec['TITLE'];
$state_rec['ELEMENT_ID'] = $element_rec['ID'];
$state_rec['IS_DYNAMIC'] = 1;
$state_rec['LINKED_OBJECT'] = $rec['LINKED_OBJECT'] . '';
$state_rec['LINKED_PROPERTY'] = 'status';
$state_rec['CONDITION'] = 4;
$state_rec['CONDITION_VALUE'] = 1;
$state_rec['ACTION_OBJECT'] = $rec['LINKED_OBJECT'] . '';
$state_rec['ACTION_METHOD'] = 'turnOn';
$state_rec['ID'] = SQLInsert('elm_states', $state_rec);
// Создаем запись состояния для 'on'
$state_rec = array();
$state_rec['TITLE'] = 'on';
$state_rec['HTML'] = $element_rec['TITLE'];
$state_rec['ELEMENT_ID'] = $element_rec['ID'];
$state_rec['IS_DYNAMIC'] = 1;
$state_rec['LINKED_OBJECT'] = $rec['LINKED_OBJECT'] . '';
$state_rec['LINKED_PROPERTY'] = 'status';
$state_rec['CONDITION'] = 1;
$state_rec['CONDITION_VALUE'] = 1;
$state_rec['ACTION_OBJECT'] = $rec['LINKED_OBJECT'] . '';
$state_rec['ACTION_METHOD'] = 'turnOff';
$state_rec['ID'] = SQLInsert('elm_states', $state_rec);
} elseif ($element_rec['TYPE'] == 'warning') {
// Создаем запись состояния для 'default'
$state_rec = array();
$state_rec['TITLE'] = 'default';
$state_rec['ELEMENT_ID'] = $element_rec['ID'];
$state_rec['HTML'] = $element_rec['TITLE'] . '<br/>%' . $rec['LINKED_OBJECT'] . '.updatedText%';
$state_rec['LINKED_OBJECT'] = $rec['LINKED_OBJECT'] . '';
$state_rec['LINKED_PROPERTY'] = 'status';
$state_rec['IS_DYNAMIC'] = 1;
$state_rec['CONDITION'] = 1;
$state_rec['CONDITION_VALUE'] = 1;
$state_rec['ID'] = SQLInsert('elm_states', $state_rec);
} elseif ($element_rec['TYPE'] == 'informer') {
// Устанавливаем связанное свойство
$linked_property = 'value';
// Устанавливаем флаги для высокого и низкого состояний
$state_high = 1;
$state_high_value = '%' . $linked_object . '.maxValue%';
// Если флаг высокого состояния установлен
if ($state_high) {
// Создаем запись состояния для 'high'
$state_rec = array();
$state_rec['TITLE'] = 'high';
$state_rec['ELEMENT_ID'] = $element_rec['ID'];
$state_rec['HTML'] = '%' . $linked_object . '.' . $linked_property . '%';
// Если установлена единица измерения, добавляем ее к HTML
if ($linked_property_unit) {
$state_rec['HTML'] .= ' ' . $linked_property_unit;
}
$state_rec['LINKED_OBJECT'] = $linked_object . '';
$state_rec['LINKED_PROPERTY'] = $linked_property . '';
$state_rec['IS_DYNAMIC'] = 1;
// Если установлено значение высокого состояния, добавляем его к записи
if ($state_high_value) {
$state_rec['CONDITION'] = 2;
$state_rec['CONDITION_VALUE'] = $state_high_value;
}
$state_rec['ID'] = SQLInsert('elm_states', $state_rec);
}
// Устанавливаем флаги для низкого состояния
$state_low = 1;
$state_low_value = '%' . $linked_object . '.minValue%';
// Если флаг низкого состояния установлен
if ($state_low) {
// Создаем запись состояния для 'low'
$state_rec = array();
$state_rec['TITLE'] = 'low';
$state_rec['ELEMENT_ID'] = $element_rec['ID'];
$state_rec['HTML'] = '%' . $linked_object . '.' . $linked_property . '%';
// Если установлена единица измерения, добавляем ее к HTML
if ($linked_property_unit) {
$state_rec['HTML'] .= ' ' . $linked_property_unit;
}
$state_rec['LINKED_OBJECT'] = $linked_object . '';
$state_rec['LINKED_PROPERTY'] = $linked_property . '';
$state_rec['IS_DYNAMIC'] = 1;
// Если установлено значение низкого состояния, добавляем его к записи
if ($state_low_value) {
$state_rec['CONDITION'] = 3;
$state_rec['CONDITION_VALUE'] = $state_low_value;
}
$state_rec['ID'] = SQLInsert('elm_states', $state_rec);
}
// Создаем запись состояния для 'default'
$state_rec = array();
$state_rec['TITLE'] = 'default';
$state_rec['ELEMENT_ID'] = $element_rec['ID'];
$state_rec['HTML'] = '%' . $linked_object . '.' . $linked_property . '%';
// Если установлена единица измерения, добавляем ее к HTML
if ($linked_property_unit) {
$state_rec['HTML'] .= ' ' . $linked_property_unit;
}
// Если установлены флаги высокого или низкого состояния
if ($state_high || $state_low) {
$state_rec['IS_DYNAMIC'] = 1;
$state_rec['LINKED_OBJECT'] = $linked_object . '';
$state_rec['LINKED_PROPERTY'] = $linked_property . '';
// Если установлены оба флага, устанавливаем is_dynamic в 2 и добавляем условие
if ($state_high && $state_low) {
$state_rec['IS_DYNAMIC'] = 2;
$state_rec['CONDITION_ADVANCED'] = 'if (gg(\'' . $linked_object . '.' . $linked_property . '\')>=gg(\'' . $linked_object . '.minValue\') && gg(\'' . $linked_object . '.' . $linked_property . '\')<=gg(\'' . $linked_object . '.maxValue\')) {' . "\n " . '$display=1;' . "\n" . '} else {' . "\n " . '$display=0;' . "\n" . '}';
} elseif ($state_high) {
$state_rec['IS_DYNAMIC'] = 1;
$state_rec['CONDITION'] = 3;
$state_rec['CONDITION_VALUE'] = $state_high_value;
} elseif ($state_low) {
$state_rec['IS_DYNAMIC'] = 1;
$state_rec['CONDITION'] = 2;
$state_rec['CONDITION_VALUE'] = $state_low_value;
}
}
$state_rec['ID'] = SQLInsert('elm_states', $state_rec);
} elseif ($element_rec['TYPE'] == 'button') {
// Устанавливаем метод связанного объекта
$linked_method = 'pressed';
// Создаем запись состояния для 'default'
$state_rec = array();
$state_rec['TITLE'] = 'default';
$state_rec['ELEMENT_ID'] = $element_rec['ID'];
$state_rec['HTML'] = $element_rec['TITLE'];
// Если установлены связанный объект и метод, добавляем их к записи
if ($linked_object && $linked_method) {
$state_rec['ACTION_OBJECT'] = $linked_object;
$state_rec['ACTION_METHOD'] = $linked_method;
}
$state_rec['ID'] = SQLInsert('elm_states', $state_rec);
}
}
}
/**
* checkLinkedDevicesAction
*
* Функция для проверки действий связанных устройств.
* Она принимает название связанного объекта и значение (необязательно).
* Функция выполняет поиск устройств, связанных с указанным объектом, и включает файл с действиями связанных устройств.
*
* @method void checkLinkedDevicesAction($object_name, $value = '')
* @param string $object_name Название связанного объекта
* @param string $value Значение (необязательно)
* @return void
* @see module
* @since 0.1
*/
function checkLinkedDevicesAction($object_title, $value = 0)
{
// Начинаем измерение времени выполнения функции
startMeasure('checkLinkedDevicesAction');
// Получаем запись об устройстве, связанном с указанным объектом
$device1 = SQLSelectOne("SELECT * FROM devices WHERE LINKED_OBJECT LIKE '" . $object_title . "'");
// Если устройство не найдено, завершаем измерение времени и возвращаем 0
if (!$device1['ID']) {
endMeasure('checkLinkedDevicesAction');
return 0;
}
// Включаем файл с действиями связанных устройств
include(dirname(__FILE__) . '/devices_links_actions.inc.php');
// Завершаем измерение времени выполнения функции
endMeasure('checkLinkedDevicesAction');
// Возвращаем 1, указывая на успешное выполнение функции
return 1;
}
/**
* Install
*
* Маршрутина установки модуля.
*
* @method void Install()
* @return void
* @see module
* @since 0.1
*//
function install($data = '')
{
// Выполняем установку родительского класса
parent::install();
// Включаем файлы языка модуля для текущего языка сайта и по умолчанию
if (file_exists(ROOT . 'languages/' . $this->name . '_' . SETTINGS_SITE_LANGUAGE . '.php')) {
include_once(ROOT . 'languages/' . $this->name . '_' . SETTINGS_SITE_LANGUAGE . '.php');
}
if (file_exists(ROOT . 'languages/' . $this->name . '_default' . '.php')) {
include_once(ROOT . 'languages/' . $this->name . '_default' . '.php');
}
// Обновляем заголовок модуля в таблице проектных модулей
SQLExec("UPDATE project_modules SET TITLE='" . LANG_DEVICES_MODULE_TITLE . "' WHERE NAME='" . $this->name . "'");
// Устанавливаем словарь устройств
$this->setDictionary();
// Рендерим структуру модуля
$this->renderStructure();
// Синхронизируем с Homebridge
$this->homebridgeSync();
}
/**
* Uninstall
*
* Маршрутина удаления модуля.
*
* @method void Uninstall()
* @return void
* @see module
* @since 0.1
*/
function uninstall()
{
// Удаляем таблицу устройств
SQLDropTable('devices');
// Выполняем удаление родительского класса
parent::uninstall();
}
/**
* dbInstall
*
* Маршрутина установки базы данных.
*
* @method void dbInstall()
* @return void
* @see module
* @since 0.1
*/
function dbInstall($data = '')
{
/*
* Создание таблиц для устройств и связей между ними.
*/
$data = <<<EOD
devices: ID int(10) unsigned NOT NULL auto_increment
devices: TITLE varchar(100) NOT NULL DEFAULT ''
devices: ALT_TITLES varchar(255) NOT NULL DEFAULT ''
devices: TYPE varchar(100) NOT NULL DEFAULT ''
devices: LINKED_OBJECT varchar(100) NOT NULL DEFAULT ''
devices: LOCATION_ID int(10) unsigned NOT NULL DEFAULT 0
devices: FAVORITE int(3) unsigned NOT NULL DEFAULT 0
devices: SYSTEM_DEVICE int(3) unsigned NOT NULL DEFAULT 0
devices: CLICKED datetime DEFAULT NULL
devices: ARCHIVED int(3) unsigned NOT NULL DEFAULT 0
devices: SYSTEM varchar(255) NOT NULL DEFAULT ''
devices: SUBTYPE varchar(100) NOT NULL DEFAULT ''
devices: ENDPOINT_MODULE varchar(255) NOT NULL DEFAULT ''
devices: ENDPOINT_NAME varchar(255) NOT NULL DEFAULT ''
devices: ENDPOINT_TITLE varchar(255) NOT NULL DEFAULT ''
devices: ROLES varchar(100) NOT NULL DEFAULT ''
devices_linked: ID int(10) unsigned NOT NULL auto_increment
devices_linked: DEVICE1_ID int(10) unsigned NOT NULL DEFAULT 0
devices_linked: DEVICE2_ID int(10) unsigned NOT NULL DEFAULT 0
devices_linked: LINK_TYPE varchar(100) NOT NULL DEFAULT ''
devices_linked: LINK_SETTINGS text
devices_linked: COMMENT varchar(255) NOT NULL DEFAULT ''
devices_groups: ID int(10) unsigned NOT NULL auto_increment
devices_groups: SYS_NAME varchar(100) NOT NULL DEFAULT ''
devices_groups: TITLE varchar(255) NOT NULL DEFAULT ''
devices_groups: APPLY_TYPES text
devices_scheduler_points: ID int(10) unsigned NOT NULL auto_increment
devices_scheduler_points: LINKED_METHOD varchar(255) NOT NULL DEFAULT ''
devices_scheduler_points: VALUE varchar(255) NOT NULL DEFAULT ''
devices_scheduler_points: SET_TIME varchar(50) NOT NULL DEFAULT ''
devices_scheduler_points: SET_DAYS varchar(50) NOT NULL DEFAULT ''
devices_scheduler_points: DEVICE_ID int(10) NOT NULL DEFAULT '0'
devices_scheduler_points: ACTIVE int(3) NOT NULL DEFAULT '1'
devices_scheduler_points: LATEST_RUN datetime
EOD;
// Выполняем установку базы данных
parent::dbInstall($data);
}
// --------------------------------------------------------------------
}
/*
* Зачем эта строка с кодировкой? не понятно.
* TW9kdWxlIGNyZWF0ZWQgSnVsIDE5LCAyMDE2IHVzaW5nIFNlcmdlIEouIHdpemFyZCAoQWN0aXZlVW5pdCBJbmMgd3d3LmFjdGl2ZXVuaXQuY29tKQ==
*
*/