HomeKit, наконец, вышел в дикую природу, предоставив возможность голосового управления через Siri для нескольких потребительских умных домашних устройств.
К сожалению, я имею в виду буквальную горстку — все, что вы уже купили, вероятно, не совместимо. Тем не менее, протокол уже был переработан и доступен эмулятор с открытым исходным кодом для HomeKit API: или, говоря простым языком, теперь вы можете создавать «поддельные» устройства HomeKit, и Siri будет управлять ими, как и любой другой официальный аксессуар HomeKit.
Сегодня мы собираемся создать управляемый Wi-Fi источник света и управлять им с помощью Siri. Вот демо.
Вот что вам нужно:
- Raspberry Pi (я использовал RPi2, есть небольшая разница в версиях Node для установки, учитывая обновленную архитектуру ARM — см. Примечания позже).
- Брокер MQTT установлен на Raspberry Pi. См. Раздел «Установка Mosquitto на Pi» в моем Руководстве по OpenHAB, часть 2, Его не нужно устанавливать специально на Pi — вы даже можете использовать облачный сервер MQTT, но так как в любом случае нам нужен Pi для этого урока, это удобно.
- NodeMCU v2 (совместимый с Arduino)
- Неопиксельные светодиоды (я бы порекомендовал 4 пикселя для тестирования, затем вы можете добавить внешний источник питания и добавить столько, сколько хотите)
Установка моста HomeKit
Мы собираемся установить приложение NodeJS под названием HAP-NodeJS на Raspberry Pi: это сформирует мост между запросами HomeKit и устройствами Wi-Fi. Сейчас мы настроим этот мост с одним аксессуаром, но вы можете добавить столько, сколько захотите.
Я на самом деле устанавливаю это на свой существующий домашний сервер под управлением OpenHAB — я надеюсь соединить их вместе позже, но пока знаю, что они могут сосуществовать на одном Raspberry Pi. Если вы делаете то же самое, на всякий случай сделайте резервную копию своей текущей карты Pi SD. Если все пойдет не так, вы можете восстановить это.
Начните с полного обновления с терминала или сеанса SSH. .
sudo apt-get update sudo apt-get upgrade
Возможно, вам придется сделать это дважды, если это было какое-то время.
Теперь установите несколько основных пакетов, которые нам понадобятся:
sudo apt-get установить npm git-core libnss-mdns libavahi-compat-libdnssd-dev
Далее мы собираемся установить последнюю версию NodeJS. У вас может возникнуть соблазн сделать это с помощью apt-get , но не делайте этого — эта версия действительно старая и не будет работать. Вместо этого, посетите nodejs.org , перейдите в каталог download / release / latest-v5.x.0 / и проверьте, какая ссылка на последнюю версию. Вы ищете linux-armv7l для Raspberry Pi 2 или linuxarmv6l для оригинальных моделей RPi. Затем, при необходимости изменив URL-адреса и имена каталогов, загрузите и установите с помощью следующих команд.
wget https://nodejs.org/download/release/latest-v5.x.0/node-v5.5.0-linux-armv7l.tar.gz tar -xvf node-v5.5.0-linux-armv7l.tar.gz cd node-v5.5.0-linux-armv7l sudo cp -R * / usr / local
Подтвердите, набрав
версия узла
И вы должны увидеть v5.5 (или что-то последнее, что вы скачали).
Далее у нас есть несколько модулей Node для установки.
sudo npm install -g npm sudo npm install -g node-gyp
В этой первой команде мы на самом деле используем Node Package Manager (npm), чтобы установить более новую версию. Умная!
Теперь, чтобы загрузить эмулятор HomeKit под названием HAP-NodeJS :
git clone https://github.com/KhaosT/HAP-NodeJS.git cd HAP-NodeJS нпм перестроить sudo npm install node-persist sudo npm установить srp
В этот момент я запустил эту ошибку: « #error Эта версия узла / NAN / v8 требует компилятора C ++ 11 ». Если это произойдет с вами, установите более свежий компилятор C ++ с помощью команд:
sudo apt-get установить gcc-4.8 g ++ - 4.8 Возможности обновления sudo --install / usr / bin / gccgcc / usr / bin / gcc-4.6 20 Возможности обновления sudo --install / usr / bin / gcc gcc /usr/bin/gcc-4.8 50 Возможности обновления sudo --install / usr / bin / g ++ g ++ /usr/bin/g++-4.6 20 Возможности обновления sudo --install / usr / bin / g ++ g ++ /usr/bin/g++-4.8 50
Теперь у вас не должно быть проблем. Продолжайте выполнять эти команды, одну за другой:
sudo npm установить srp sudo npm install mdns --unsafe-perm sudo npm install debug sudo npm install ed25519 --unsafe-perm sudo npm install curve25519 --unsafe-perm
Это должно быть все. Попробуйте запустить эмулятор с:
узел Core.js
Если вы получаете сообщения о том, что он не может найти такой-то и такой-то модуль, просто снова введите команду sudo npm install и добавьте имя того модуля, который отсутствовал. Предполагая, что все хорошо, вы должны увидеть несколько предупреждений, и ваш мост HomeKit будет работать. Вот как выглядит успех:
Сразу видно, что уже создан набор из 6 поддельных устройств. Мы будем использовать их в качестве отправной точки для нашего собственного индикатора Wi-Fi позже, но пока будем использовать их только для тестирования. Вы также можете увидеть больше информации отладки, если вы запустите сервер с:
DEBUG = * узел Core.js
Теперь перейдите к устройству Apple, способному работать с Siri. Любопытно, что Apple не предоставляет стандартное приложение HomeKit, кроме зарегистрированных разработчиков, поэтому загрузите бесплатное приложение Elgato Eve, приложение для управления HomeKit, которое позволяет добавлять (даже не Elgato) устройства в сеть HomeKit.
При первом запуске приложения вам нужно будет назвать свой дом, пройтись по нему и пройтись по нему. Затем выберите «Добавить аксессуар». Проигнорируйте сообщение о том, чтобы быть близко к этому!
Далее вам будет предложено найти уникальный «Код установки HomeKit». Игнорируйте это и нажмите «Добавить в [название вашего дома]».
Он также скажет вам, что устройство не сертифицировано. На самом деле это не так. Иди вперед в любом случае. Когда вы попадаете на экран, спрашивая код доступа …
Выберите, чтобы ввести код вручную, и введите следующее:
031-45-154
Это можно найти / изменить в файле Light_accessory.js , но об этом позже. Добавьте этот аксессуар в свою комнату по умолчанию, назовите его Fake Light и продолжайте идти по диалоговым окнам, чтобы выбрать значок и т. Д.
Наконец, вернитесь к сеансу SSH, где у вас работает HAP-NodeJS. Возможно, вы уже видели сообщение «Мы на связи?» — это приложение Elgato, опрашивающее светлый статус. Откройте Siri и скажите ей: «Включите поддельный свет», затем попробуйте снова его выключить. Надеюсь, вы увидите несколько отладочных сообщений от HAP-NodeJS, чтобы показать, что он получил команды.
Мы находимся? Нет. Включение света! Выключить свет!
Фантастика, это первый шаг закончен. Теперь нам нужен настоящий свет, прежде чем вернуться, чтобы снова настроить мост.
Создание Wi-Fi Light
Аппаратная сторона этого шага на удивление проста, если мы начнем с четырех неопикселей, поскольку мы можем питать их непосредственно от платы разработчика NodeMCU и ее USB-соединения. Если у вас более длинная полоса, не беспокойтесь — мы определили это в программном обеспечении, так что остальные просто не включатся.
Подключите красный кабель питания от жилы Neopixel к выводу VIN, синее заземление к GND, а зеленый сигнальный кабель к контакту с маркировкой D2 на NodeMCU. Будьте очень осторожны с полярностью: если вы перепутаете землю и VIN, вы отправите мощный импульс через вашу доску и уничтожите ее в процессе.
Если ваша среда Arduino еще не настроена для работы с ESP8266, продолжайте и следуйте руководству в моем ESP8266: Убийца Arduino руководства, а затем вернитесь после того, как вы подтвердили, что это работает. Установите эти дополнительные библиотеки:
Код, который мы используем, является модификацией Aditya Tannu пользователя Github — я удалил ненужные функции обновления по беспроводной сети, добавил некоторые отсутствующие функции HSV и упростил создание большего количества источников света, просто изменив одна переменная Если вы не видите код, встроенный ниже, вы найдете его в этом списке .
#include <ESP8266WiFi.h> | |
#include <WiFiClient.h> | |
#include <ESP8266mDNS.h> | |
#include <WiFiUdp.h> | |
#include <PubSubClient.h> | |
#include <Adafruit_NeoPixel.h> | |
#define PIN 4 | |
Adafruit_NeoPixel strip = Adafruit_NeoPixel(4, PIN, NEO_GRB + NEO_KHZ800); | |
const char* ssid = "...."; | |
const char* password = "..."; | |
const char* host = "officelight"; // the name of your fixture, and the base channel to listen to | |
IPAddress MQTTserver(192, 168, 1, 99); | |
/* NO NEED TO CHANGE BENEATH THIS LINE */ | |
int hue = 0; | |
float brightness = 0.0; | |
float saturation = 0.0; | |
#define BUFFER_SIZE 100 | |
WiFiClient wclient; | |
PubSubClient client(wclient, MQTTserver); | |
void callback(const MQTT::Publish& pub) { | |
uint16_t i, j; | |
currentValues(); | |
String myMessage = String(pub.payload_string()); | |
// handle message arrived | |
Serial.print(pub.topic()); | |
Serial.print(" => "); | |
String myTopic = String(pub.topic()); | |
if(myTopic == host) | |
{ | |
Serial.println(pub.payload_string()); | |
if(pub.payload_string() == "on") | |
{ | |
// use this to reset parameters if you want them to always come on bright white. | |
//hue = 0; | |
brightness = 1.0; | |
//saturation = 0.0; | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, HSVColor(hue,saturation,brightness)); | |
} | |
strip.show(); | |
} | |
else | |
{ | |
//hue = 0; | |
brightness = 0.0; | |
//saturation = 0.0; | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, HSVColor(hue,saturation,brightness)); | |
} | |
strip.show(); | |
} | |
} | |
else if(myTopic == host+(String)"/brightness") | |
{ // Brightness up to 100 | |
Serial.println(pub.payload_string()); | |
brightness = (myMessage.toFloat())/100; | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, HSVColor(hue,saturation,brightness)); | |
} | |
strip.show(); | |
} | |
else if(myTopic == host+(String)"/hue") | |
{ // Hue value 0-360 | |
Serial.println(pub.payload_string()); | |
hue = myMessage.toInt(); | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, HSVColor(hue,saturation,brightness)); | |
} | |
strip.show(); | |
} | |
else if(myTopic == host+(String)"/saturation") | |
{ // Saturation value at 0-100 | |
Serial.println(pub.payload_string()); | |
saturation = (myMessage.toFloat())/100; | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, HSVColor(hue,saturation,brightness)); | |
} | |
strip.show(); | |
} | |
currentValues(); | |
} | |
void setup() { | |
Serial.begin(115200); | |
Serial.println("Booting"); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
while (WiFi.waitForConnectResult() != WL_CONNECTED) { | |
Serial.println("Connection Failed! Rebooting..."); | |
delay(5000); | |
ESP.restart(); | |
} | |
Serial.println("Ready"); | |
Serial.print("IP address: "); | |
Serial.println(WiFi.localIP()); | |
// MQTT callback | |
client.set_callback(callback); | |
strip.begin(); | |
strip.show(); // Initialize all pixels to 'off' | |
} | |
void loop() { | |
if (WiFi.status() == WL_CONNECTED) { | |
if (!client.connected()) { | |
if (client.connect("ESP8266: Fountain")) { | |
client.publish("outTopic",(String)"hello world, I'm "+host); | |
client.subscribe(host+(String)"/#"); | |
} | |
} | |
if (client.connected()) | |
client.loop(); | |
} | |
} | |
// Convert Hue/Saturation/Brightness values to a packed 32-bit RBG color. | |
// hue must be a float value between 0 and 360 | |
// saturation must be a float value between 0 and 1 | |
// brightness must be a float value between 0 and 1 | |
uint32_t HSVColor(float h, float s, float v) { | |
h = constrain(h, 0, 360); | |
s = constrain(s, 0, 1); | |
v = constrain(v, 0, 1); | |
int i, b, p, q, t; | |
float f; | |
h /= 60.0; // sector 0 to 5 | |
i = floor( h ); | |
f = h - i; // factorial part of h | |
b = v * 255; | |
p = v * ( 1 - s ) * 255; | |
q = v * ( 1 - s * f ) * 255; | |
t = v * ( 1 - s * ( 1 - f ) ) * 255; | |
switch( i ) { | |
case 0: | |
return strip.Color(b, t, p); | |
case 1: | |
return strip.Color(q, b, p); | |
case 2: | |
return strip.Color(p, b, t); | |
case 3: | |
return strip.Color(p, q, b); | |
case 4: | |
return strip.Color(t, p, b); | |
default: | |
return strip.Color(b, p, q); | |
} | |
} | |
void currentValues(){ | |
Serial.println(""); | |
Serial.println("Current State"); | |
Serial.print("Hue (0-360):"); | |
Serial.println(hue); | |
Serial.print("Saturation (0-100 in, 0-1):"); | |
Serial.println(saturation*100); | |
Serial.print("Brightness (0-100):"); | |
Serial.println(brightness*100); | |
Serial.println(""); | |
} | |
Обновите следующие строки, указав собственную сетевую информацию и уникальное имя для каждого создаваемого вами прибора (хоста).
const char * ssid = "...."; const char * password = "..."; const char * host = "officelight"; IP-адрес MQTTserver (192, 168, 1, 99);
IP-адрес этого устройства автоматически получается через DHCP - не имеет значения, меняется ли он, поскольку мы подключаемся к одному и тому же серверу MQTT каждый раз.
На данный момент мы используем только 4 Неопикселя, но вы можете увеличить число позже, если будете питать их от внешнего источника. Загрузите код, и давайте проверим - используйте ваш любимый клиент MQTT для отправки команд (измените имя хоста в следующих инструкциях, если вы его изменили) .
- Вы можете отправить его в корневой офисный канал, чтобы включить его. Отправьте любое другое значение этому каналу, чтобы отключить его.
- Вы можете отправить число от 0 до 360 на офисный свет / оттенок, чтобы изменить цвет. Мы используем цветовое пространство HSV , поэтому 0 и 360 - красные, 120 - зеленые, а 240 - синие.
- Вы отправляете процентное значение для яркости (0-100, не включая символ%).
- То же самое для насыщения. Значение 100 будет полностью насыщенным (т. Е. Сплошным цветом), а ноль будет чисто белым, независимо от указанного оттенка.
Убедившись, что осветительный прибор с приводом от MQTT работает, продолжайте.
Настройка нового аксессуара HomeKit
Вернитесь к Raspberry Pi и закройте приложение HAP-NodeJS, если вы еще этого не сделали. Перейдите в каталог / accessories . Чтобы упростить эту задачу, вы можете напрямую загрузить код, уже связанный с прибором «officelight», введя следующее:
wget https://gist.githubusercontent.com/jamesabruce/a6607fa9d93e41042fee/raw/12e4fd1d1c2624e7540ba5e17c3e79bc6bdec5fd/Officelight_accessory.js
По сути, это дубликат стандартного светового аксессуара с измененными именами переменных (опять же, адаптировано из работы Адисана, упрощено для простоты использования). Вот что вы должны знать для создания своих собственных аксессуаров на основе этого.
- Все аксессуары должны быть названы * _accessory.js
- Измените IP-адрес в переменной options вверху на ваш сервер MQTT
- Если у вас другое имя прибора, найдите / замените все экземпляры « officelight » на свое уникальное имя прибора. Вы можете выполнить поиск / замену в Nano, нажав клавиши CTRL и \ , введя термин для поиска, термин для замены, а затем нажмите A (имеется в виду все экземпляры). Пройдите через каждый из них, чтобы точно узнать, какие переменные обновляются.
- Создайте уникальное шестнадцатеричное имя пользователя для аксессуара ( light.username = «1B: 2B: 3C: 5D: 6E: FF»; )
- Не меняйте PIN-код. Он соответствует определенному формату, и если вы не знаете, что делаете, он не сможет выполнить сопряжение. Нет проблем с тем, чтобы они оставались одинаковыми между огнями.
- При добавлении их в приложение Elgato Eve вы можете присвоить своему устройству другое «имя Siri» и редактировать их в любое время, чтобы не потерять первоначальный выбор. Нет необходимости редактировать файлы конфигурации или перезагружать сервер.
- Получив несколько приборов, вы можете использовать приложение Elgato Eve, чтобы сгруппировать их по комнатам или создать конкретные сцены, состоящие из нескольких сложных действий. Сцены могут состоять из нескольких действий, таких как: включить офисный свет, уменьшить его до 25%, сделать его красным и активировать кофемашину.
Вам нужно будет снова добавить новый аксессуар через приложение HomeKit.
Наконец, мы хотим запускать наше приложение HAP-NodeJS при каждом перезапуске Pi. Добавьте следующее в ваш файл etc / rc.local , прямо перед выходом 0 .
узел sudo /home/pi/HAP-NodeJS/Core.js </ dev / null &
Вы можете видеть, что я объединил это с некоторыми другими командами, которые я уже настроил для запуска при загрузке.
Если вы используете rc.local впервые, вам может потребоваться установить его в качестве исполняемого файла:
sudo chmod 755 /etc/rc.local
Если по какой-то причине вам нужно снова запустить его в режиме отладки, вы можете убить работающее приложение Node с помощью:
узел killall
Последний шаг: перейдите в каталог аксессуаров и удалите GarageDoorOpener_accessory.js . На момент написания, это ошибка, и через некоторое время сервер может сломаться.
Что вы будете контролировать с Siri?
Теперь, когда вы освоили основы, на самом деле нет предела тому, что вы можете контролировать - если вы можете кодировать его в Javascript, вы можете создать свой собственный вспомогательный файл. Здесь так много возможностей, я думаю, вам будет очень весело. Дайте мне знать в комментариях, что вы придумали!