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

    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 Files\nooLite\nooLiteCMD.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. В профиле не публикуется информация о значениях свойств объектов и, разумеется, нет возможности управлять оборудованием — вся информация предоставляется только в ознакомительных целях.

    Удачной автоматизации!
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 14

      0
      А как работает nooLiteCMD.exe? Какие протоколы связи с оборудованием? Какое оборудование поддерживает? Какой функционал у этой программы?
        0
        Это проприетарное ПО от производителя nooLite и здесь приведено лишь для примера. Само по себе оно поддерживает только отправку команд на устройства nooLite по радио-каналу.
        0
        мне одному хостинг вспомнился?
          0
          То есть я должен сидеть и выискивать среди хостинговых предложений внезапно вот это smartliving.ru/
          Я зашёл почитать посмотреть понять что это. Три раза прочитал пока не решил в профиль перейти.
            +1
            добавил ссылку в начало статьи на сам проект
              0
              Большое спасибо, так намного лучше :)
          0
          Если нужно только ручное управление светом через браузер, то проще сделать вот так (там тоже noolite).
            0
            Как вариант :-) Но статья не совсем об этом.
              0
              Ну да, не об этом. Просто немного похоже на Вашу систему. Возможно, кому-нибудь окажется полезным.

              ЗЫ. Рад, что Вас разбанили на хабре!
                0
                Конечно, может пригодиться. Спасибо :-)
            0
            Ни слова о архитектуре. Контролер домашнеей автоматизации, єто не ООП изучить, а связать воедино устройстав в доме, получать, обрабатывать, анализироавть и реагировать на события в системе. UI же возникает как следствие.
              +1
              Архитектуре самого проекта? Об этом написано на сайте самого проекта в разделе «Азбука», здесь же я хотел показать, как применяется ООП для интеграции устройств. События, реакции, UI и прочее так же есть, но, как вы правильно заметили, они следствие и статья как раз не про UI, а про возможности внутренней организации собственных объектов на этой системе.
                0
                Спасибо посмотрел. К сожалению главной задачи домашней автоматизации вы не решаете. Вы взялись то что ближе вам UI.
                С тех задач что я зараз рассматриваю:
                — Device discovery
                — Multiprotocol processing
                — Extending network
                — Network topology
                Не решается никакая. Возможно для вашей топологии это и подходит, но мне нет.
                Вот сравните ваше решение например с github.com/stianeikeland/homeautomation
                Уже четко видно что event-based архитектура, я могу предвидеть точки расширения.
                В самом примитивном виде home automation контролер должен существовать вообще без UI.
                По прерыванию от внешнего события будится демон, который принимает или отправляет сообщение, кладет его в service bus и все его работа на этом окончена. Другие модули в том числе и UI просто подписчики на события шины. ZeroMQ/Crosroads + возможно redis как слой сохранения данных как будто для таких систем созданы. В результате части системы не завязаны один на другой и могут быть взаимозаменяемыми и опциональными. По сути из обязательных, слушающий демон, service bus, и накопитель данных, дальше добавляем обработчик который будет тригерится по определенным событиям.
                Для работы с топологией уже есть некоторые задумки, но пока еще не оформились в окончательное решение. Пока едет BBB гуглю альтернативы, чтобы не изобретать велосипед.

                  0
                  Я не буду спорить с тем, что с точки зрения красоты архитектурного решения всё можно сделать лучше. У меня очень практичный подход и система развивается по мере роста потребностей. Я бы не сказал, что в текущем виде она не решает задачи автоматизации хотя бы потому, что она работает у пользователей, которые как раз для автоматизации её выбрали. Система вполне хорошо работает без UI и так же имеет событийную модель для обработки входящих запросов (веб-сервер как один из протоколов принятия событий). Мульти-протокольность поддерживается засчёт различных модулей, каждый из которых отвечает за взаимодействие с «железным» протоколом, будь-то ZWave, MQTT-брокер, 1-wire или тот же HTTP. В конкретно этой системе UI очень важная составляющая, но далеко не единственная. Да и не может она быть таковой в системе, основная задача которой обеспечивать адаптацию среды без участия пользователя.

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

            Only users with full accounts can post comments. Log in, please.