Автоматизация квартиры с HomePod, Raspberry Pi и Node.js



    Перевели для вас статью Криса Хокинса, в которой он рассказывает о превращении своей квартиры в умный дом. В качестве базы используется HomePod от Apple, но, конечно, можно применять и другие системы.

    У меня дома работает Apple HomePod, который помогает контролировать определенные системы в доме (к примеру, умные лампы) при помощи обычного запроса к Siri. Работает система как из дома, так и вне его (умный помощник есть на телефоне).

    Skillbox рекомендует: двухлетний практический курс «Я — веб-разработчик PRO».

    Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».

    Изначально я скептически относился к управлению домом при помощи голосовых команд, ведь далеко не все распознается ассистентами (не только Siri) корректно. Но затем это вошло в привычку. Поскольку у ламп Hue нет физического выключателя, а в приложении нужно совершить несколько действий для управления освещением, я привлек к делу Siri.

    Затем мне захотелось начать при помощи голосового помощника управлять и другими системами в доме, например, телевизором или консолью. В случае с ТВ я, например, обнаружил Simple IP Control — метод управления моим Sony Bravia путем отправки команд по TCP.

    Кастомизируем Siri


    Во второй половине 2018 года Apple открыла приложение Shortcuts для всех пользователей iOS. Оно позволяет автоматизировать работу с телефоном (или умным домом) без необходимости писать код.

    У приложения много встроенных команд. Что ему недостает, так это возможности использовать TCP-команды, хотя там есть механизм работы с URL.

    Плюс ко всему, можно писать собственные модули на Objective-C или Swift. Этого решил не делать, поскольку в будущем я могу сменить мой HomePod на другого помощника. Вместо этого мне захотелось написать веб-приложение, которое сможет отвечать на команды Siri.

    Управление Sony Bravia TV


    Вооружившись мануалом с командами для моего ТВ, я написал приложение на Node.js Express (Github), которое научил отвечать на некоторые из общих команд. Начал я с включения и громкости.

    Команда setPowerStatus делает все, что нам нужно.



    Заголовок состоит из символов * и s, которые статичны и используются для всех команд. Затем третий байт (с) используется для Command. Есть четыре значения, которые могут занимать эту позицию. C для Command (отправка команды на ТВ), E — для Enquiry (проверка текущего значения определенного параметра, например, громкости), А — Answer (отправляется в ответ на Commands и Enquiries) и N для Notify (оповещение о событиях, вроде отключение громкости).

    Для достижения своей цели мне пришлось изучить документацию Sony’s JSON-RPC. Как оказалось, природа JSON-RPC over HTTP позволила упростить задачу и сократить количество кода.

    Работа с JSON-RPC API была простой. Возьмем, например, сервис (system), команду (getPowerStatus) плюс параметры (true или false) и сформируем HTTP-запрос, который затем отправляем на ТВ.

    let body = JSON.stringify({
      method: command,
      id: ++this.id,
      params: params,
      version: "1.0",
    });
    return new Promise((resolve, reject) => {
      fetch('http://' + this.ip + ':' + this.port + '/sony/' + service, {
        method: 'post',
        headers: { 'X-Auth-PSK': this.psk },
        body: body,
      }).then(response => {
        return response.json();
      }).then(response => {
        if (response.error && (!response.result || response.result.length === 0)) {
          reject({ code: response.error[0] });
        } else {
          resolve(response.result[0]);
        }
      }).catch(error => {
        reject(error);
      });
    });

    По умолчанию аутентификация осуществляется при помощи предварительного ключа, отправляемого в заголовке HTTP-запроса. Но есть более безопасный и удобный способ сделать это при помощи accessControl. В этом случае мы можем отправлять команду на телевизор и осуществлять безопасный обмен кода при базовой HTTP-аутентификации. После того, как аутентификация выполнена один раз, дальнейшая авторизация выполняется при помощи cookie.

    Но мой ТВ защищен файерволом, настроенным на роутере, так что я использовал предварительный ключ.

    Включение Xbox One


    Xbox, конечно, требовал иной настройки. Microsoft, похоже, приняла решение не использовать REST API, поэтому работа была выполнена при помощи UDP-пакетов.

    К счастью, у Node.js есть модуль dgram, который «из коробки» работает со всеми возможностями USP. Вот, что у меня получилось в итоге.

    turnOn() {
      let socket = dgram.createSocket('udp4');
      let powerPayload = new Buffer('\x00' + String.fromCharCode(this.liveId.length) + this.liveId.toUpperCase() + '\x00');
      let powerHeader = Buffer.concat([new Buffer('dd0200', 'hex'), new Buffer(String.fromCharCode(powerPayload.length)), new Buffer('\x00\x00')]);
      let powerPacket = Buffer.concat([powerHeader, powerPayload]);
     
      return this._sendPacket(socket, powerPacket);
    }
     
    _sendPacket(socket, buffer) {
      return new Promise((resolve, reject) => {
        socket.send(buffer, 0, buffer.length, Constants.xboxPort, this.ip, function(err) {
          socket.close();
          if (err) {
            return reject(err);
          }
          resolve();
        });
      });
    }

    Для настрйоки я использовал список ID-устройств, который можно найти здесь. Если вы хотите просто взять код из моего репозитория, то вам нужно заменить ID в файле config.json.

    Настройка Shortcuts для Siri


    Для того, чтобы Siri могла выполнять команды, которые я только что создал, ей нужен помощник. Его я создал из Raspberry Pi, поскольку «малинка» подходит по всем параметрам. Для этого я купил Pi 3 Model B+, поддерживающий Wi-Fi.

    У Raspbian есть GUI для настройки. Я подключился к Wi-Fi, затем отключил дисплей и продолжил работу по SSH. Для того, чтобы убедиться в постоянной активности веб-приложения, я настроил сокет активации сервиса в systemd, так что если бы процесс Node.js упал, система автоматически могла его перезапустить.

    Собственно, Shortcuts для Siri были самым простым этапом работы. Это интуитивное приложение с нативной поддержкой голосовых команд. Оно по умолчанию уже умело работать с HomePod, дополнительно настраивать ничего не понадобилось.



    Собираем все вместе


    Поскольку мой ТВ работает на Android, он поддерживает приложения вроде Netflix и YouTube. Помня об этом, я создал команды для запуска этих сервисов. Кроме того, я добавил команды для контроля громкости, режима работы ТВ, паузы и проигрывания контента.

    Вот примеры всего, что я создал. Я также постарался сделать проект модульным, так что добавлять другие модели SmartTV — не проблема.

    Вот пример модуля, который включает Xbox, ТВ и активизирует первый порт HDMI.

    router.post('/turnOnXboxAndTV', function(req, res, next) {
      Promise.all([
        xbox.turnOn(),
        tv.turnOn()
          .then(() => new Promise(resolve => setTimeout(resolve, 2000)))
          .then(() => tv.setInput(config.scripts.xboxInput)),
      ]).then(() => {
        res.sendStatus(200);
      }).catch((error) => {
        res.status(500).send(error);
      });
    });

    А вот как это все работает на практике.


    К сожалению, функциональность Siri не слишком хороша. У той же Alexa от Amazon гораздо более обширный спектр возможностей и весьма мощный API. Думаю, на основе Alexa можно создать куда более серьезные проекты.

    Skillbox рекомендует:

    Skillbox
    320,00
    Онлайн-университет профессий будущего
    Поделиться публикацией

    Комментарии 1

      +3
      Обалдеть, благодоря статье нашёл интерфейс TCP/IP у моего ящика — не думал, что всё так легко, а потому и не искал. Давно пользуюсь «ок, гуга» (с) моя дочь и chrome cast, но кроме как включать и выключать, каст контролировать телевизор не умеет.
      Может реализую hotkeys для Samsung'a, типа next channel, prev channel, next source, volume… Интересна будет такая статья?

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое