В инструкции мы расскажем, как подключиться к Apple HomeKit с помощью Node-RED и модуля node-red-contrib-homekit-bridged.
Разработкой и поддержкой модуля занимается открытое сообщество пользователей Node-RED.
Подготовка
Для настройки моста Apple HomeKit на контроллере Wiren Board с помощью Node-RED нам понадобится:
- установленный Node-RED и настроенный модуль WB Nodes,
- модуль node-red-contrib-homekit-bridged — его мы установим ниже и для этого нам понадобится доступ в интернет,
- аккаунт iCloud и устройство Apple с приложением Home.
Настройка делается через встроенный в Node-Red веб-интерфейс, который доступен по адресу http://wb-ip-address:1880, например, http://192.168.42.1:1880.
В примерах мы будем создавать флоу (flows) — это блок-схемы процесса.
Установка модуля
(Updated) Adding Apple TV to HomeKit
Установка модуля node-red-contrib-homekit-bridged
Чтобы Node-RED мог работать с HomeKit, установите модуль node-red-contrib-homekit-bridged :
- Зайдите в веб-интерфейс Node-RED.
- В правом верхнем углу вызовите меню.
- В открывшемся окне выберите вкладку Управление палитрой (Manager palette).
- Перейдите на вкладку Установка (Install), введите в поле поиска homekit-bridged и нажмите на клавиатуре Enter .
- Установите пакет с названием node-red-contrib-homekit-bridged.
- Закройте окно с настройками. Установка модуля завершена.
После установки, в левой панели появится группа Apple HomeKit.
Добавление устройства
Как это работает
Добавление новых устройств в общем случае выглядит так:
- Описываем на контроллере виртуальное устройство HomeKit.
- Прописываем логику, которое это устройство реализует, например, включение зуммера.
- Публикуем флоу кнопкой Deploy.
- Если мост уже добавлен в приложение Home, то устройство появится в нём автоматически.
В примерах ниже мы настроим мост, а также добавим сенсор температуры процессора и переключатель, который будет управлять зуммером контроллера.
Настройка моста
Мост настраивается один раз и потом используется во всех устройствах:
- Перетяните в рабочую область ноду Service, которая находится слева в группе Apple HomeKit.
- Дважды кликните на ней — откроется окно Edit service node, где нажмите на карандашик в поле Bridge.
- Откроется окно Add new homekit-bridge config node, где:
- укажите имя в поле Name, например, wb-demo
- и запомните пин-код из поля Pin Code.
- Чтобы сохранить настройки, нажмите кнопку Add.
- В окне Edit service node нажмите кнопку Cancel и удалите ноду с рабочей области.
Мост настроен, дальше можно добавлять устройства. В процессе нужно учесть два момента:
- устройство HomeKit на вход принимает и отдаёт объект, который содержит имя характеристики и значение;
- WB ноды in и out отдают и принимают значения в виде строки.
Чтобы синхронизировать разные типы данных, мы будем создавать конвертеры значений.
Окно Edit service node
Настройка моста
Сенсор
В примере мы настроим сенсор температуры HomeKit, который будет выводить температуру процессора.
Нода wb-in, окно Edit in node
Добавим ноду WB, которая будет выдавать CPU Temperature:
- Перетяните в рабочую область ноду in, которая находится слева в группе Wiren Board.
- Дважды кликните по ней — откроется окно Edit in node, где укажите:
- Name — имя, например, CPU Temp.
- Server — MQTT-сервер, связь с которым настраивается при установке модуля WB Nodes.
- Channel — выберите в открывшемся списке mqtt-топик hwmon/CPU Temperature. Если список пуст, нажмите кнопку Refresh Device List.
- Чтобы сохранить, нажмите кнопку Done.
Конвертер to Float
Настроим конвертер, который преобразует значение CPU Temperature в объект HomeKit:
- Перетяните в рабочую область ноду function, которая находится слева в группе function.
- Дважды кликните по ней — откроется окно Edit function node и впишите в поле On Message код:
msg.payload = ‘CurrentTemperature’: parseFloat(msg.payload)>; return msg;
CurrentTemperature — это имя характеристики, взято из документации Apple HomeKit.
Настройка устройства HomeKit
Добавим ноду HomeKit, которая создаст виртуальное устройство:
- Перетяните в рабочую область ноду service, которая находится слева в группе Apple HomeKit.
- Дважды кликните по ней — откроется окно Edit service node, где:
- в поле Service выберите TemperatureSensor,
- в поле Bridge выберите мост, который мы создавали ранее — wb-demo.
- укажите имя в поле Name, например, CPU Temp.
- Нажмите кнопку Done.
У нас получилось три ноды, соедините их между собой: CPU Temp (wb-in) → to Float → CPU Temp (HK).
Чтобы изменения вступили в силу, нажмите справа вверху страницы кнопку Deploy.
Устройство с управлением
Теперь настроим переключатель HomeKit, который будет управлять устройством Buzzer.
Нода wb-in, окно Edit in node
Добавим ноду WB, которая будет выдавать состояние Buzzer:
- Перетяните в рабочую область ноду in, которая находится слева в группе Wiren Board.
- Дважды кликните по ней — откроется окно Edit in node, где укажите:
- Name — имя, например, Buzzer.
- Server — MQTT-сервер, связь с которым настраивается при установке модуля WB Nodes.
- Channel — выберите в открывшемся списке mqtt-топик buzzer/enabled. Если список пуст, нажмите кнопку Refresh Device List.
- Чтобы сохранить, нажмите кнопку Done.
Конвертер true/false
Настроим конвертер, который преобразует состояние Buzzer в объект HomeKit:
- Перетяните в рабочую область ноду function, которая находится слева в группе function.
- Дважды кликните по ней — откроется окно Edit function node и впишите в поле On Message код:
msg.payload = (msg.payload == ‘1’) ? ‘On’:true> : ‘On’:false>; return msg
Настройка устройства HomeKit
Добавим ноду HomeKit, которая создаст виртуальное устройство:
- Перетяните в рабочую область ноду service, которая находится слева в группе Apple HomeKit.
- Дважды кликните по ней — откроется окно Edit service node, где:
- в поле Service выберите Switch,
- в поле Bridge выберите мост, который мы создавали ранее — wb-demo.
- укажите имя в поле Name, например, Buzzer.
- Нажмите кнопку Done.
Конвертер 1/0
Настроим конвертер, который преобразует объект HomeKit в состояние Buzzer:
- Перетяните в рабочую область ноду function, которая находится слева в группе function.
- Дважды кликните по ней — откроется окно Edit function node и впишите в поле On Message код:
msg.payload = (msg.payload.On) ? ‘1’ : ‘0’; return msg
Нода wb-out
Добавим ещё одну ноду WB, которая будет устанавливать состояние Buzzer:
- Перетяните в рабочую область ноду out, которая находится слева в группе Wiren Board.
- Дважды кликните по ней — откроется окно Edit out node, где укажите:
- Name — имя, например, Buzzer.
- Server — MQTT-сервер, связь с которым настраивается при установке модуля WB Nodes.
- Channel — выберите в открывшемся списке mqtt-топик buzzer/enabled. Если список пуст, нажмите кнопку Refresh Device List.
- Command — выберите /on.
- Payload — должно быть выбрано msg.payload
- Чтобы сохранить, нажмите кнопку Done.
У нас получилось пять нод, соедините их между собой: Buzzer (wb-in) → true/false → Buzzer (HK) → 1/0 → Buzzer (wb-out).
Чтобы изменения вступили в силу, нажмите справа вверху страницы кнопку Deploy.
Настройка в устройстве Apple
Теперь нам нужно добавить созданный выше мост в экосистему Apple HomeKit и распределить созданные устройства по комнатам. В будущем, при добавлении устройств, они будут автоматически появляться в приложении Home.
Перед началом настройки подключите контроллер Wiren Board и ваше устройство Apple к одной локальной сети, например, по Wi-Fi.
«Привет, Siri. Включи обогреватели» — Интеграция умного дома на базе NooLite с Apple HomeKit
2016-10-18 в 15:54, admin , рубрики: python, Python RaspberryPi NooLite HomeKit, Программирование, программирование микроконтроллеров, метки: Python RaspberryPi NooLite HomeKit
В своей первой статье я описал предысторию появления системы удаленного управления отоплением в загородном доме через Telegram-бота, которым я и моя семья пользовались долгое время.
С выходом iOS 10, Apple представила пользователям приложение Дом — свою реализацию интерфейса управления умным домом через HomeKit. Меня весьма заинтересовала данная тема и, потратив несколько вечеров на изучение доступного материала, я решил реализовать интеграцию данного продукта с моей системой. В статье я подробно изложу процесс ее установки и настройки, а также поделюсь видео с результатами того, что получилось в итоге.
Введение
Для понимания исходных данных и начальной конфигурации умного дома, советую ознакомится с первой статьей.
Первой задачей был поиск готовых свободных решений в автоматизации домашнего оборудования с поддержкой HomeKit. Тут я сразу вспомнил несколько статей об open source продукте OpenHab. Почитав документацию и немного погуглив, действительно нашел аддон поддержки протокола HomeKit. На данный момент готовится к выходу вторая версия OpenHab и проводится активное бета тестирование. Последней доступной версией на тот момент была beta4, которую и решил использовать.
Процесс интеграции можно разделить на 4 этапа:
- Установка и настройка OpenHab
- Подключение NooLite к OpenHab
- Установка и настройка HomeKit для OpenHab
- Настройка приложения «Дом»
В итоге должна была получится следующая схема:
Установка и настройка OpenHab
У OpenHab 2 есть довольно подробная документация, где помимо основных платформ есть и туториал по установке на Raspberry Pi. Не буду копировать сюда все шаги, так как никаких проблем с установкой не возникло.
После установки web-интерфейс OpenHab был доступен в браузере по адресу: http://:8080.
Сразу были доступны:
- Basic UI, Classic UI — панели управления устройствами подключенными к OpenHab
- Rest API — собственно rest API
- Paper UI — интерфейс администирования OpenHab, через который его можно настроить
Пока Basic UI был пустой:
Подключение NooLite к OpenHab
Исходя из документации, для подключения нового устройства к OpenHab нужно было:
- Добавить его в items
- Добавить в sitemap, чтобы оно отображалось в OpenHab панели управления умным домом (Basic UI, Classic UI). Данный шаг можно пропустить, к работе с HomeKit он не относится, но с его помощью можно проверить, что OpenHab видит NooLite и правильно с ним работает.
- Добавить правила в rules, если нужна автоматизация или дополнительная логика обработки событий
Items
В items мы описываем конечные управляемые устройства, к примеру силовой блок NooLite и «учим» OpenHab работать с ним:
itemtype itemname [«labeltext»] [] [(group1, group2, . )] []
- itemtype — тип устройства (Switch, Dimmer и т.д.)
- itemname — имя устройства
- labeltext — текстовое отображение. К примеру для датчика: «Температура [%.1f °C]», для блока просто «Обогреватели»
- iconname — отображаемая иконка
- group1 — группы
- bindingconfig — то, как управлять этим устройством
Самое интересное здесь — это биндинг. То, каким образом будет осуществляться взаимодействие с управляемым устройством. Немного поискав информацию по работе OpenHab с NooLite, нашел готовый вариант. Но он был написан для работы с NooLite USB адаптерами PC и RX серий. В моей же системе управление силовыми блоками работало через ethernet-шлюз PR1132, поэтому нужно было искать другие варианты работы.
Посмотрев на доступные биндинги, нашел универсальные Http binding и Exec binding, с помощью которых можно было реализовать общение с NooLite:
- Http binding позволяет выполнять сетевой запрос при возникновении какого-либо события (включение/выключение, получение информации с датчика). Используя API в PR1132, можно было реализовать прямое общение OpenHab с NooLite.
- Exec binding — на событие выполняется какая-либо команда.
На тот момент я думал, что будет необходима дополнительная логика пре/пост обработки запросов к NooLite, поэтому выбрал второй вариант.
NooLite CLI
При разработке Telegram-бота, предыдущей реализации интерфейса общения с умным домом, я уже написал простенький класс-обертку над API вызовами к NooLite:
noolite_api.py
«»» NooLite API wrapper «»» import requests from requests.auth import HTTPBasicAuth from requests.exceptions import ConnectTimeout, ConnectionError import xml.etree.ElementTree as ET class NooLiteSens: «»»Класс хранения и обработки информации, полученной с датчиков Пока как таковой обработки нет «»» def __init__(self, temperature, humidity, state): self.temperature = float(temperature.replace(‘,’, ‘.’)) if temperature != ‘-‘ else None self.humidity = int(humidity) if humidity != ‘-‘ else None self.state = state class NooLiteApi: «»»Базовый враппер для общения с NooLite»»» def __init__(self, login, password, base_api_url, request_timeout=10): self.login = login self.password = password self.base_api_url = base_api_url self.request_timeout = request_timeout def get_sens_data(self): «»»Получение и прасинг xml данных с датчиков :return: список NooLiteSens объектов для каждого датчика :rtype: list «»» response = self._send_request(‘<>/sens.xml’.format(self.base_api_url)) sens_states = < 0: ‘Датчик привязан, ожидается обновление информации’, 1: ‘Датчик не привязан’, 2: ‘Нет сигнала с датчика’, 3: ‘Необходимо заменить элемент питания в датчике’ >response_xml_root = ET.fromstring(response.text) sens_list = [] for sens_number in range(4): sens_list.append(NooLiteSens( response_xml_root.find(‘snst<>’.format(sens_number)).text, response_xml_root.find(‘snsh<>’.format(sens_number)).text, sens_states.get(int(response_xml_root.find(‘snt<>’.format(sens_number)).text)) )) return sens_list def send_command_to_channel(self, data): «»»Отправка запроса к NooLite Отправляем запрос к NooLite с url параметрами из data :param data: url параметры :type data: dict :return: response «»» return self._send_request(‘<>/api.htm’.format(self.base_api_url), params=data) def _send_request(self, url, **kwargs): «»»Отправка запроса к NooLite и обработка возвращаемого ответа Отправка запроса к url с параметрами из kwargs :param url: url для запроса :type url: str :return: response от NooLite или исключение «»» try: response = requests.get(url, auth=HTTPBasicAuth(self.login, self.password), timeout=self.request_timeout, **kwargs) except ConnectTimeout as e: print(e) raise NooLiteConnectionTimeout(‘Connection timeout: <>’.format(self.request_timeout)) except ConnectionError as e: print(e) raise NooLiteConnectionError(‘Connection timeout: <>’.format(self.request_timeout)) if response.status_code != 200: raise NooLiteBadResponse(‘Bad response: <>’.format(response)) else: return response # Кастомные исключения NooLiteConnectionTimeout = type(‘NooLiteConnectionTimeout’, (Exception,), <>) NooLiteConnectionError = type(‘NooLiteConnectionError’, (Exception,), <>) NooLiteBadResponse = type(‘NooLiteBadResponse’, (Exception,), <>) NooLiteBadRequestMethod = type(‘NooLiteBadRequestMethod’, (Exception,), <>)
Используя его, в несколько строк python кода я набросал NooLite CLI, с помощью которого появилась возможность управлять NooLite из командной строки:
noolite_cli.py
«»» NooLite PR1132 command line interface «»» import os import json import logging import argparse import yaml from noolite_api import NooLiteApi SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__)) # Logging config logger = logging.getLogger() formatter = logging.Formatter( ‘%(asctime)s — %(filename)s:%(lineno)s — %(levelname)s — %(message)s’ ) stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) logger.addHandler(stream_handler) def get_args(): «»»Получение аргументов запуска :return: словарь вида для переданных аргументов. :rtype: dict «»» parser = argparse.ArgumentParser() parser.add_argument(‘-sns’, type=int, help=’Получить данные с указанного датчика’) parser.add_argument(‘-ch’, type=int, help=’Адрес канала’) parser.add_argument(‘-cmd’, type=int, help=’Команда’) parser.add_argument(‘-br’, type=int, help=’Абсолютная яркость’) parser.add_argument(‘-fmt’, type=int, help=’Формат’) parser.add_argument(‘-d0′, type=int, help=’Байт данных 0’) parser.add_argument(‘-d1′, type=int, help=’Байт данных 1’) parser.add_argument(‘-d2′, type=int, help=’Байт данных 2’) parser.add_argument(‘-d3′, type=int, help=’Байт данных 3’) return if __name__ == ‘__main__’: # Получаем конфиг из файла config = yaml.load(open(os.path.join(SCRIPT_PATH, ‘conf_cli.yaml’))) # Создаем объект для работы с NooLite noolite_api = NooLiteApi( config[‘noolite’][‘login’], config[‘noolite’][‘password’], config[‘noolite’][‘api_url’] ) # Получаем аргументы запуска args = get_args() logger.debug(‘Args: <>’.format(args)) # Если есть аргумент sns, то возвращаем информацию с датчиков if ‘sns’ in args: sens_list = noolite_api.get_sens_data() send_data = sens_list[args[‘sns’]] print(json.dumps(< ‘temperature’: send_data.temperature, ‘humidity’: send_data.humidity, ‘state’: send_data.state, >)) else: logger.info(‘Send command to noolite: <>’.format(args)) print(noolite_api.send_command_to_channel(args))
Аргументы имеют такие же названия, как и в API ethernet-шлюза PR1132, единственное, что добавил — аргумент sns для получения информации с датчиков.
# Помощь $ python noolite_cli.py -h usage: noolite_cli.py [-h] [-sns SNS] [-ch CH] [-cmd CMD] [-br BR] [-fmt FMT] [-d0 D0] [-d1 D1] [-d2 D2] [-d3 D3] optional arguments: -h, —help show this help message and exit -sns SNS Получить данные с указанного датчика -ch CH Адрес канала -cmd CMD Команда -br BR Абсолютная яркость -fmt FMT Формат -d0 D0 Байт данных 0 -d1 D1 Байт данных 1 -d2 D2 Байт данных 2 -d3 D3 Байт данных 3 # Включение силового блока, привязанного к 0 каналу $ python noolite_cli.py -ch 0 -cmd 2 OK # Выключение силового блока, привязанного к 0 каналу $ python noolite_cli.py -ch 0 -cmd 0 OK # Получение информации с датчика, привязанного к 0 каналу $ python noolite_cli.py -sns 0 # Посложнее — задать RGB-контроллеру SD111-180 (3 канал) соответствующую яркость # на каждый из цветовых каналов: d0 — красный, d1 — зеленый, d2 — синий $ python noolite_cli.py -ch 3 -cmd 6 -fmt 3 -d0 247 -d1 255 -d2 247
Теперь я мог описать все силовые блоки NooLite в items:
# /etc/openhab2/items/noolite.items Number FFTemperature «Температура [%.1f °C]» Number FFHumidity «Влажность [%d %%]» Switch Heaters1 «Обогреватели» < exec=»>[OFF:python noolite_cli.py -ch 0 -cmd 0] >[ON:python noolite_cli.py -ch 0 -cmd 2]»> Switch Light1 «Освещение» < exec=»>[OFF:python noolite_cli.py -ch 2 -cmd 0] >[ON:python noolite_cli.py -ch 2 -cmd 2]»> Color RGBLight «Светодиодная лента»
- FFTemperature, FFHumidity — температура и влажность датчика первого этажа. OpenHab для получения информации каждые 5 секунд выполняет python noolite_cli.py с параметром -sns 0 и извлекает значения temperature из json ответа. Аналогично для влажности
- Heaters1 — линия обогревателей первого этажа. Для включения (команда «ON») OpenHab должен выполнить python noolite_cli.py -ch 0 -cmd 2 , для выключения (команда «OFF») — python noolite_cli.py -ch 0 -cmd 0 .
- Light1 — уличный прожектор, команды аналогичные обогревателям, только на втором канале -ch 2
- RGBLight — светодиодная лента.
Rules
Управление светодиодной лентой уже не умещалось в одну команду, так как нужна была дополнительная логика для получения значений яркости каждого из RGB каналов. Поэтому обработку изменения состояния я описал в rules:
# /etc/openhab2/rules/noolite.rules import org.openhab.core.library.types.* var HSBType hsbValue var String redValue var String greenValue var String blueValue rule «Set RGB value» when Item RGBLight changed then val hsbValue = RGBLight.state as HSBType val brightness = hsbValue.brightness.intValue val redValue = ((((hsbValue.red.intValue * 255) / 100) * brightness) / 100).toString val greenValue = ((((hsbValue.green.intValue * 255) / 100) * brightness) / 100).toString val blueValue = ((((hsbValue.blue.intValue *255) / 100) * brightness) / 100).toString var String cmd = «python noolite_cli.py -ch 3 -cmd 6 -fmt 3 -d0 » + redValue + » -d1 » + greenValue + » -d2 » + blueValue executeCommandLine(cmd) end
Я описал одно правило, которое срабатывало при изменении состояния RGBLight, где получал значения каждого канала (0-255), формировал строку python noolite_cli.py -ch 3 -cmd 6 -fmt 3 -d0 redValue -d1 greenValue -d2 blueValue и выполнял ее.
Sitemap
Теперь, когда OpenHab «видел» все мои силовые блоки и умел ими управлять, оставалось описать, как нужно их отображать в панели управления OpenHab (Basic UI, Classic UI). Делается это в sitemap:
# /etc/openhab2/sitemap/noolite.sitemap sitemap noolite label=»Дача» < Frame label=»Первый этаж» < Text item=FFTemperature Text item=FFHumidity Switch item=Heaters1 Switch item=Light1 >Frame label=»Второй этаж» < Colorpicker item=RGBLight icon=»colorwheel» label=»Светодиодная лента» >>
После сохранения этого файла в Basic UI появились все устройства:
Также протестировал работу с умным домом через приложение OpenHab для iOS устройств, где тоже все отлично работало:
Установка и настройка HomeKit для OpenHab
Установку HomeKit аддона для OpenHab я произвел в пару кликов через Paper UI (интерфейс администрирования):
Для его корректной работы, следуя документации, для каждого элемента items прописал тип (Lighting, Switchable, CurrentTemperature, CurrentHumidity, Thermostat). После этого файл noolite.items имел следующий вид:
Number FFTemperature «Температура [%.1f °C]» [ «CurrentTemperature» ] Number FFHumidity «Влажность [%d %%]» [ «CurrentHumidity» ] Switch Heaters1 «Обогреватели» [ «Switchable» ] < exec=»>[OFF:python noolite_cli.py -ch 0 -cmd 0] >[ON:python noolite_cli.py -ch 0 -cmd 2]»> Switch Light1 «Освещение» [ «Switchable» ] < exec=»>[OFF:python noolite_cli.py -ch 2 -cmd 0] >[ON:python noolite_cli.py -ch 2 -cmd 2]»> Color RGBLight «Светодиодная лента» [ «Lighting» ]
Затем в настройках аддона прописал локальный адрес устройства c OpenHab (в моем случае Raspberry Pi) и посмотрел pin-код сопряжения:
После этого с настройками OpenHab было закончено, и я приступил к конфигурированию умного дома на iphone в приложении «Дом».
Настройка приложения «Дом»
Первый запуск приложения «Дом»
Нажал «Добавить аксессуар»
iPhone увидел в локальной сети устройство с поддерждок HomeKit
Ввести код вручную
При добавлении указал pin-код из настроек HomeKit аддона
Все устройства
iPhone увидел все мои устройства, описанные в items. Далее я переименовал некоторые устройства, создал «комнаты» (первый этаж, второй этаж, улица) и раскидал все устройства по ним.
Здесь я хочу пояснить один момент. На скриншоте выше виден элемент «Температура на улице» (первый элемент с показателем 2 градуса), находящийся в комнате «Улица». Этот элемент реализован с использованием биндинга YahooWeather Binding — по сути просто прогноз погоды от yahoo для конкретного места.
К NooLite он не относится, поэтому я не затронул подробности его установки и настройки. Сделать это можно опять же через Paper UI, все подробно изложено в документации.
Удаленный доступ и автоматизация
В моей локальной сети находился Apple TV, который без дополнительных настроек сам определился как «Домашний центр». Как я позже выяснил, домашний центр необходим для удаленного доступа к умному дому и настройки автоматизации (действия по расписанию, действия на основе вашей геопозиции и т.д.). В качестве домашнего центра может выступать Apple TV 3 или 4 поколения (в 3 поколении работает только удаленный доступ, для автоматизации нужно 4 поколение) или iPad с iOS 10. Это устройство должно быть постоянно включено и находится в локальной сети умного дома.
Приятно порадовало то, что никаких дополнительных настроек с Apple TV я не делал. Все, что нужно — это войти в iCloud под своей учетной записью.
Результат
Нагляднее всего процесс работы можно показать с помощью видео. Ниже приведу несколько примеров работы приложения «Дом» и голосового управления через Siri:
Источник: www.pvsm.ru