Основы программирования объектов Умного Дома в MajorDoMo

в 7:32, , рубрики: diy или сделай сам, majordomo, php, ооп, Программирование, умный дом, метки: , , , ,

image

Система MajorDoMo объединяет в себе различные компоненты, действие многих из которых сопряжено с чтением либо изменением данных. Для организации эффективного обмена данными между частями системы была создана объектная модель. Данная модель во многом соответствует парадигме Объектно Ориентированного Программирования (ООП) и людям, знакомых с данной парадигмой, не составит труда разобраться в имеющейся модели. Однако, знание принципов ООП совсем не обязательно, т.к. встроенная в систему модель достаточно упрощённая и может применяться без глубокого знания какого-либо языка программирования или же в качестве первого шага обучения этой концепции. В статье описаны основные составляющие этой модели.

Часть 1. Теория.

Классы

Класс это описание основных свойств, которыми должны обладать все объекты, относящиеся к данному классу. Класс не является объектом и не может сам по себе содержать значения этих свойств, он лишь описывает признаки и варианты поведения объектов. Физическую аналогию можно представить на примере простой классификации — например, к классу «Двери» может принадлежать объект «Дверь в ванную комнату», при этом, «Двери» могут иметь описание свойства «Статус» (открыта дверь или закрыта), но непосредственное значение может быть установлено только для конкретного объекта, но не для класса.

Важная особенность классов это возможность создания подклассов, наследующих все свойства и методы «родительского» класса, но при этом способные обладать собственными свойствами и методами. Либо имеющие свои особенные реализации «родительских» методов.

Пример:
image

Объекты

Объект представляет собой состояние реального (или виртуального) объекта. Свойства объекта могут иметь конкретные значения (например «статус» ,«температура» и т.п.). Кроме того, в самом объекте могут быть заданы свойства, которые дополняют набор свойств класса, к которому объект относится. Так же, для объекта может быть задана собственная реализация методов, описанных в классе.

Пример:
image

Объект, относящийся к классу, который, в свою очередь, является подклассом, наследует свойства и методы всех родительских классов.

Свойства

Свойство – это конкретный параметр, описывающий состояние объекта. Как уже было написано выше, классы могут лишь описывать свойства (название, описание и т.п.), но значение свойства может быть установлено только для какого-то конкретного объекта.

Пример (описание свойств класса объектов):
image

Пример (установка/чтение свойства объекта):

setGlobal('myObject.myProperty',12345);
$value=getGlobal('myObject.myProperty');
Методы

Методы представляют собой описание возможных действий объекта (или действий над объектом). Возвращаясь к физической аналогии, можно указать, что класс «Двери» может иметь методы «Открыть» и «Закрыть», т.е. все объекты класса так же будут иметь этот метод и мы можем открыть дверь вызвав метод «Дверь в ванную комнату.Открыть». Сама реализация метода представляет собой сценарий на языке программирования PHP. В данном случае частью сценария может быть установка свойства «Статус» в состояние «Открыта».

Пример (метод объекта):
image

Пример (код метода):

if ($this->getProperty('status')) {
 say("Движение в гараже");
}

Пример (вызов метода):

callMethod('myObject.myMethod',$params); // $params не обязательный массив параметров

Часть 2. Практика.

Во второй части статьи я приведу пример «встраивания» реального оборудования в объектную систему MajorDoMo. В качестве примера оборудования я буду использовать компоненты системы nooLite, которая уже неоднократно была представлена на Хабре, поэтому в целом о возможностях этих компонентов многие знают. Все нижеописанные действия производятся в панели управления MajorDoMo в разделе Объекты без внесения изменений в исходный код или файлы конфигурации системы.

Итак, для примеров мы будем использовать:

  • Несколько исполнительных силовых модулей (обычный + регулируемый/диммируемый)
  • USB-передатчик для отправки сигналов

План по пунктам:

  1. Создаём абстрактные классы для наших задач
  2. Создаём более специфические классы для поддерживаемого оборудования
  3. Добавляем объекты
  4. Управляем!

Пункт 1

Будем отталкиваться от того, что в нашем Умном Доме часто будет возникать задача включения/выключения какого-либо оборудования, поэтому заведём на самом верхнем уровне класс Relays (Реле) со свойством status (1/0 — включено/выключено), а так же с методами turnOff, turnOn, switch и refresh.

Код метода turnOff (выключение устройства):

$this->setProperty("status",0);

Код метода turnOn (включение устройства):

$this->setProperty("status",1);

Код метода switch (переключение устройства):

$status=$this->getProperty("status");
if ($status) {
 $this->callMethod('turnOff');
} else {
 $this->callMethod('turnOn');
}

Код метода refresh (обновление состояния устройства):

$status=$this->getProperty("status");
if ($status) {
 $this->callMethod('turnOn');
} else {
 $this->callMethod('turnOff');
}

Будем считать, что это необходимый минимум, который будет присущ всем управляемым объектам.

Пункт 2

Далее, будем добавлять поддержку нужного нам оборудования nooLite через создание дочернего класса nooLite. Отличаться от родительского он будет специфическим свойством channel (канал управления исполнительным модулем). Кроме того, будет добавлен новый метод sendCommand (отправка команды) и переопределён код методов turnOff и turnOn.

Код нового метода sendCommand (отправка команды устройству Noolite):

$cmdline='"c:Program FilesnooLitenooLiteCMD.exe" -api '.$params['command'];
safe_exec($cmdline);

Код переопределённого метода turnOff:

$this->setProperty("status",0);
$this->callMethod("sendCommand",array('command'=>'-off_ch'.$this->getProperty("channel")));

Код переопределённого метода turnOn:

$this->setProperty("status",1);
$this->callMethod("sendCommand",array('command'=>'-on_ch'.$this->getProperty("channel")));

Остальные методы мы не трогаем — они остаются без изменений и работают, как положено с новым классом (спасибо ООП!).

Собственно, теперь мы можем добавлять сколь угодно много объектов заданного класса без дополнительных затрат на программирование поведения каждого из них.

Пункт 3

Добавим объект noo1, указав в описании объекта, что это «Подсветка потолка в гостиной», перейдём в настройку его свойств и укажем значение свойства noo1.channel = 1, т.е. этот силовой модуль находится на первом канале управления.

Пункт 4

Теперь мы можем включать/выключать этот модуль из любого сценария следующим кодом:

callMethod('noo1.turnOn'); // включаем
callMethod('noo1.turnOff'); // выключаем

Либо же прописать управление этим модулем из меню в таком виде:
image

Получив в результате вот такой элемент управления:
image

Закрепим усвоенное прохождением пунктов 2-4 для добавления ещё одного устройства — силовой блок nooLite с поддержкой диммирования.

Пункт 2.

От созданного выше класса nooLite создадим дочерний класс nooLiteDimmer, добавив в него дополнительное свойство brightness. Так же добавим новый метод dim и перепишем код методов refresh, turnOn, turnOff

Код нового метода dim:

if ($params['value']) {
 $this->setProperty("brightness",$params['value']);
 $this->callMethod("refresh");
}

Код переопределённого метода refresh:

$value=$this->getProperty("brightness");
$this->callMethod("sendCommand",array('command'=>'-set_ch'.$this->getProperty("channel").' -'.$value));
if ($value>0) {
 $this->setProperty('status',1);
} else {
 $this->setProperty('status',0);
}

Код переопределённого метода turnOff:

$this->setProperty("status",0);
$this->setProperty("brightness",0);
$this->callMethod("refresh");

Код переопределённого метода turnOn:

$this->setProperty("status",1);
$this->setProperty("brightness",100);
$this->callMethod("refresh");

Пункт 3.

Практически аналогичен предыдущему варианту — добавляем объект noo2, прописываем в свойствах канал управления (2). Объект готов.

Пункт 4.

Объектом noo2 можно управлять точно так же как и noo1, но кроме этого мы можем использовать метод dim для установки яркости:

callMethod('noo2.dim',array('value'=>50)); // устанавливаем яркость в 50%

Для управления светильником в меню создадим следующий элемент:
image

Вид элемента управления для пользователя уже приведён выше в примере управления обычным силовым блоком.

В Ноотехнике имеется ещё вот такой трёхканальный диммер для управления RGB-подсветкой:

Его интеграцию я оставлю за кадром (или в качестве «домашнего задания», если угодно), но в результате несложных манипуляций, подобным описанным выше, можно получить вот такой интерфейс:
image

Вместо послесловия

Объектную систему особенно удобно использовать в том случае, когда у нас есть ряд однотипных объектов (например, датчиков или исполнительных механизмов), обладающих одинаковыми свойствами и вариантами поведения. При этом мы можем задать один класс и добавить лишь объекты, отличающиеся названиями или какими-то отдельными особенностями, но при этом иметь всего одну реализацию сценария поведения, описанную в методе класса.

Кроме того, все имеющиеся модули, обеспечивающие связь системы с конкретными «железными» (и не очень) протоколами позволяют указывать «привязку» параметров поддерживаемого оборудования к свойствам либо методам определённых объектов, что позволяет на уровне объектов иметь актуальное состояние всех подключенных систем (SNMP, ZWave, 1-wire и прочее).

Ну и в самом конце мне хотелось бы сказать, что изучать многие вещи проще всего на примерах конкретных реализаций, для чего был запущен специальный проект CONNECT, с помощью которого можно обмениваться готовыми конфигурациями своего Умного Дома. На примере своего профиля я показываю используемые компоненты, конфигурацию меню управления, созданные сценарии, классы и объекты MajorDoMo. В профиле не публикуется информация о значениях свойств объектов и, разумеется, нет возможности управлять оборудованием — вся информация предоставляется только в ознакомительных целях.

Удачной автоматизации!

Автор: Jey

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js