На мой взгляд, одним из главных минусов homebridge является отсутсвие возможности создавать продвинутые сценарии. Вся автоматизация возлагается на домашний центр, которым может быть Ipad (подключенный к зарядке), Apple TV или HomePod. Не у всех эти устройства есть, вдобавок у HomeKit очень скудная автоматизация. Исправить данную ситуацию можно с помощью Node-Red. Статья рассчитана на пользователей, у которых уже установлен и настроен homebridge.



Коротко: Node-RED — это инструмент для связи железа, API-интерфейсов и онлайн-сервисов с помощью выстраивания цепочек связей различных узлов (блоков).

Определение на официальном сайте:
Node-RED is a programming tool for wiring together hardware devices, APIs and online services in new and interesting ways.
It provides a browser-based editor that makes it easy to wire together flows using the wide range of nodes in the palette that can be deployed to its runtime in a single-click.


На Raspbian устанавливается так:

sudo apt-get install nodered
sudo systemctl enable nodered.service
sudo service nodered start

По умолчанию Node-Red работает на порту 1880.

Существует огромная библиотека модулей с наборами блоков различного функционала. Не обошли стороной и homebridge. Устанавливаем node-red-contrib-homebridge-automation:

cd ~/.node-red
npm install node-red-contrib-homebridge-automation
sudo service nodered restart

Попробуем включить лампочку. Для этого перетащим на рабочую область блок hb-control, function (этот блок будет посылать команду включиться) и inject (в рамках этой статьи нужен только для ручной активации сценария). Первый раз для hb-блоков необхоимо указать PIN и обновить список устройств. После чего можно добавить нужные блоки:



Теперь по нажатию на кнопку в блоке inject должна загореться лампочка. По мимо hb-contoll есть так же блоки hb-event, hb-status и hb-resume. Подробное описание блоков можно найти в официальном репозитории.

Код блока function
var ret_msg={};
ret_msg.payload = {};
ret_msg.payload.On = true;
return ret_msg;


Блок function создан для манипуляции данными с использованием возможностей языка JavaScript. Блок принимает на вход переменную msg вместе с параметром payload, по умолчанию большая часть блоков в Node-Red работает именно с параметром payload.

Стоит рассказать про блок Debug, с помощью него можно увидеть, выходные данные блоков, что бы понимать в чем ошибка, если ваша задумка не работает.

Теперь сделаем что нибудь интересное, например заставим свет менять состояние после поворота MagicCube на 90 градусов. В прошлой статье, я показывал как подружить zigbee устройства с homebridge. MagicCube, как и прочие zigbee устройства, после паринга появится в MQTT брокере.

Node-Red поддерживает MQTT протокол «из коробки». Добавляем блок MQTT, указываем адрес сервера и Topic кубика.



Кубик может передавать следующие состояния:
shake, wakeup, fall, tap, slide, flip180, flip90, rotate_left и rotate_right

Добавляем блок switch, чтобы отделить одно состояние от другого. Определим в switch условия flip90, shake и tap. Верхний выход соединим с hb-status, для получения текущего состояния лампочки. Блок hb-status соединим с блоком Invert On Value инвертирующим состояние, а его выход соединим с hb-controll и при повороте кубика лампочка будет менять состояние вкл/выкл. Должно получиться примерно так:



Код Invert On Value
var ret_msg=msg;
ret_msg.payload.On = !msg.payload.On;
return ret_msg;


Flow можно ипортировать от сюда:

Flow
[
    {
        "id": "f0f31eb6.22f16",
        "type": "tab",
        "label": "Flow 1",
        "disabled": false,
        "info": ""
    },
    {
        "id": "e0f72465.9e4fb8",
        "type": "mqtt in",
        "z": "f0f31eb6.22f16",
        "name": "",
        "topic": "zigbee2mqtt/0x00158d00010f0528",
        "qos": "2",
        "datatype": "auto",
        "broker": "8ec472b.e73e29",
        "x": 160,
        "y": 80,
        "wires": [
            [
                "43f74679.730588"
            ]
        ]
    },
    {
        "id": "8539109.d872ff",
        "type": "debug",
        "z": "f0f31eb6.22f16",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 670,
        "y": 60,
        "wires": []
    },
    {
        "id": "c5db7c5b.399f4",
        "type": "hb-status",
        "z": "f0f31eb6.22f16",
        "name": "Room1",
        "Homebridge": "HomeBridge",
        "Manufacturer": "YeeLight",
        "Service": "Lightbulb",
        "device": "HomeBridgeA1:23:AD:E3:CD:32YeeLightRoom100000043",
        "conf": "7948a496.505c2c",
        "x": 340,
        "y": 180,
        "wires": [
            [
                "9ef696d9.51a378"
            ]
        ]
    },
    {
        "id": "43f74679.730588",
        "type": "switch",
        "z": "f0f31eb6.22f16",
        "name": "CubeActions",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "cont",
                "v": "flip90",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "tap",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "shake",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 3,
        "x": 150,
        "y": 240,
        "wires": [
            [
                "c5db7c5b.399f4"
            ],
            [],
            []
        ]
    },
    {
        "id": "f476dcba.a6511",
        "type": "hb-control",
        "z": "f0f31eb6.22f16",
        "name": "Room1",
        "Homebridge": "HomeBridge",
        "Manufacturer": "YeeLight",
        "Service": "Lightbulb",
        "device": "HomeBridgeA1:23:AD:E3:CD:32YeeLightRoom100000043",
        "conf": "7948a496.505c2c",
        "x": 700,
        "y": 180,
        "wires": []
    },
    {
        "id": "9ef696d9.51a378",
        "type": "function",
        "z": "f0f31eb6.22f16",
        "name": "Invert On Value",
        "func": "var ret_msg=msg;\nret_msg.payload.On = !msg.payload.On;\nreturn ret_msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 520,
        "y": 180,
        "wires": [
            [
                "f476dcba.a6511"
            ]
        ]
    },
    {
        "id": "8ec472b.e73e29",
        "type": "mqtt-broker",
        "z": "",
        "name": "mosquitto",
        "broker": "127.0.0.1",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    },
    {
        "id": "7948a496.505c2c",
        "type": "hb-conf",
        "z": "",
        "username": "111-11-111"
    }
]


Таким образом можно «лепить» из блоков сложнейшие схемы автоматизации. В библиотеке можно найти модули с наборами блоков под совершенно разные задачи, например для записи с камер видео наблюдения или работы с файлами.

P.S. Мысли вслух:
Я начал увлекаться программированием в школе. Сначала это пыл Pascal, затем Delphi. Позже увлекся «олимпиадным» программированием и мне объяснили, что на Pascal далеко не уедешь. Начал изучать C++. Потом пошло-поехало и пришло осознание того, что я зык программирования особо не важен, его выбирают под конкретные задачи.
Конечно есть гуру которые «собаку съели» и могут на любимом языке написать что угодно

Мне не дает покоя мысль о том, что как бы не развивались технологии, по прежнему многие очень далеки от банальной автоматизации рабочих и жизненных процессов с помощью программирования. Я очень надеюсь, что с появлением таких инструментов как Node-Red или Blockly, порог вхождения сильно уменьшится. Научившись, в том же Node-Red строить систему из кубиков, люди, возможно, будут добираться до блока function и с интересом учить JS, а дальше все произойдет само собой.

Комментарии (2)


  1. yvm
    17.08.2019 11:00

    Кубик еще умеет fall


    1. guinmoon Автор
      17.08.2019 11:41

      Добавил.