Таймеры, несколько команд устройству, TTS (NodeJS)

Материал из База знаний
Перейти к навигации Перейти к поиску



Прямые руки 

 
Мы не несём никакой ответственности за правильное или неправильное применение, или неприменение, и/или неспособность применить данное руководство.
Телефон вызова экстренных служб - 112.
13.10.2020 Появилась частичная поддержка таймеров "из коробки". Яндекс реализовал таймеры для включения/выключения устройств.

Соответствующая новость была размещена в телеграм канале "Около Яндекс.станции". Таймеры для сценариев пока отсутствуют и нет поддержки расписания.

Постановка задачи

По мотивам статьи Алиса, таймеры, TTS и Node-RED, идея работы навыка взята здесь.

Необходима возможность выполнения нескольких сценариев за одну команду для Алисы, а так же возможность указать время выполнения сценария (таймер), не требуя Node-RED.

Выполнять составные команды. Примеры:

  • Включи люстру и телевизор
  • Выключи люстру и включи телевизор
  • Включи аквариум и телевизор и выключи люстру

Выполнять сценарии в определенное время. Примеры:

  • Добавить таймер включи ночную громкость в 23 часа
  • Добавить таймер включи утреннюю громкость в 8 часов
  • Выключи телевизор через 15 минут

Нам понадобятся:

  • Сервер/хостинг с поддержкой NodeJS (из бесплатных вариантов Yandex Cloud Functions, но с ограничением по функционалу (без таймеров) или Oracle Cloud Free Tier (в чате писали что поднимали там nodejs)), и
  • Этот полезный скрипт, который является навыком для Алисы.

Наши действия:

  • Создаём обычный приватный диалог (навык);
  • Устанавливаем и запускаем скрипт alice-command-skill (код навыка) на сервере/хостинге;
  • Создаём нужные нам сценарии умного дома в приложении Яндекс;
  • Наслаждаемся новым, недоступным пока в Умном Доме Яндекс, функционалом.

Установка скрипта

На сервере/хостинге выполняем три простых команды (в каждую из строк можно кликнуть мышью и скопировать нужный текст)
  • git clone https://github.com/subnetsRU/alice-command-skill.git
  • cd alice-command-skill
  • npm install


Можно переходить к настройке. Правке файла с настройками - config.js.

После чего запустите навык:

# npm start

Настройка

Создаём навык
Консоль браузера и куки
ID Яндекс.Станции (пример)
User ID (пример)
Если вы пользуетесь браузером Chrome, то для удобства чтения JSON (вам это понадобится, будет присутствовать ниже) на страницах можно использовать плагин
JSON Formatter. Если у вас другой браузер, то вы можете найти похожий плагин и для него.

Создаём свой навык в dialogs.yandex.ru (документация):

  1. Задаём имя навыка (как будем к нему обращаться, в моём примере навык называется "дом вируса", у вас будет своё название);
  2. В Webhook URL - имя домена или IP-адрес, где расположен скрипт alice-command-skill, и порт (указан в config.js, по умолчанию 8443);
  3. Указываем, что навык приватный!
  4. Заполняем остальные обязательные поля;
  5. Отправляем навык на модерацию, ждём размещения в каталоге (вам придёт письмо-оповещение).
  • Добавляем необходимую информацию в config.js:
  • Куда логировать:

log: {
  type: 'cli', //cli - логировать только в консоль; log - логировать только в файл; all - логировать в консоль и файл;
  file: 'acs.log', //название файла с логами, по умолчанию acs.log
},

  • Указываем путь до SSL сертификата и его ключа:

ssl: {
  crt: '/path/to/ssl.crt', //путь до файла с SSL сертификатом
  key: '/path/to/ssl.key', //путь до файла с ключом от SSL сертификата
},

Допускается самоподписанный сертификат (на момент написания статьи проверка валидности SSL сертификата со стороны Яндекса производится только для навыков Умного Дома, или если навык использует авторизацию).
Валидный сертификат можно бесплатно получить на sslforfree или letsencrypt.
  • Указываем порт, на котором будут ожидаться запросы от яндекс диалогов и который мы указали в Webhook URL, например: port: 8443,
  • Для авторизации в Яндекс необходимо задать параметры или login и pass или cookie.
    • Для того, чтобы ваш логин и пароль от вашего Яндекс аккаунта не был указан в config.js в явном виде, необходимо выполнить:
# npm start auth

После чего вам будет предложено ввести логин и пароль от вашего Яндекс аккаунта:

Yandex login ? my-Yandex-login
Yandex password ? my-secret-password

Login for config.js: bXktWWFuZGV4LWxvZ2lu
Pass for config.js: bXktc2VjcmV0LXBhc3N3b3Jk

После чего полученные значения можно внести в config.js:

    login: 'bXktWWFuZGV4LWxvZ2lu',
    pass: 'bXktc2VjcmV0LXBhc3N3b3Jk',

Отвечаю на немые вопросы:

  • введенные вами логин и пароль никуда не отправляются и разработчику данного скрипта они и даром не нужны, даже если будете просить взять - не возьму;
  • да, такой способ защиты ваших данных является защитой, как говорят, от дурака и не сокроют эти данные от опытных пользователей, если вы покажете config.js кому-то. В любом случае одним только взглядом в config.js логина и пароля не узнать и именно этого я пытался достичь;
  • Значение параметра "cookie" (если не указаны параметры login и pass) можно взять так:
    • Открываем консоль браузера (F12, вкладка "Network")
    • Заходим, к примеру, в квазар
    • Щёлкаем на запрос в консоли
    • Копируем из Request Headers часть строки после "Cookie":
cookie: 'yandexuid=XXXXXXXXXXXXXXXXXX;uniqueuid=YYYYYYYYYYYYYYYYYYY;ну и так далее...',

Учтите, что cookie могут устареть и вам придется повторить операцию и обновить значение параметра "cookie".

Если заданы логин и пароль, то параметр "cookie", при успешной авторизации в Яндекс, будет заполнен автоматически.

  • Находим идентификатор Яндекс.Станции, которая будет отвечать на команды. Этот ID можно увидеть на странице с устройствами.
  • Укажем ID яндекс.станции в config (это только пример! У вас будет другое значение):
speaker: '2077cfa6-2365-4ed4-97d5-4b46895762af',
  • Задаём каким устройствам/пользователям разрешено использовать наш навык:
    auth:{
         user_id: ['BBD3793D182F7C1842F0F1B99B9FE39DFA3E26557C99B7CDE2CAE116A3170301'],
         application: ['BBD3793D182F7C1842F0F1B99B9FE39DFA3E26557C99B7CDE2CAE116A3170301'],
    },

Их вы сможете узнать когда выполните своё первое обращение к навыку. Будет отображено в консоли (где вы запустили навык) в incoming JSON, который отображает весь пришедший в навык запрос от Яндекс.Диалогов, где:

  • user_id это user.user_id из запроса к навыку - идентификатор пользователя Яндекса, единый для всех приложений и устройств пользователя. Присутствует только, когда пользователь выполнил вход в аккаунт Яндекс на устройстве. Никогда не изменяется.
  • application это application.application_id из запроса к навыку - идентификатор экземпляра приложения (браузер или мобильное приложение), в котором пользователь общается с Алисой. Присутствует всегда, но может изменяться (например, если переустановите приложение).

Поясню по user_id и application.

Ситуация 1:

  • берём смартфон
  • открываем приложение/браузер яндекс
  • обращаемся к Алисе: "Алиса, попроси <НАЗВАНИЕ НАВЫКА> помощь"

В этой ситуации в incoming JSON вы увидите наличие только application.application_id, а user.user_id будет отсутствовать

Ситуация 2:

  • берём смартфон
  • открываем приложение/браузер яндекс
  • авторизуемся в приложении/браузере яндекс -> passport.yandex.ru
  • обращаемся к Алисе: "Алиса, попроси <НАЗВАНИЕ НАВЫКА> помощь"
  • в incoming JSON вы увидите наличие application.application_id и user.user_id

Если в "ситуация 2" использовать ещё один смартфон, то вы увидите, что application.application_id будет отличаться, а user.user_id нет.

Если вы хотите дать возможность управления нескольким устройствам/пользователям, то их можно перечислить через запятую. Пример:

    auth:{
         user_id: ['BBD3793D182F7C1842F0F1B99B9FE39DFA3E26557C99B7CDE2CAE116A3170301','28D27CB412CAA0AB39DDBD9A6974BE2BCD75362DEFC9C7DE92799D8825EA5399'],
         application: ['BBD3793D182F7C1842F0F1B99B9FE39DFA3E26557C99B7CDE2CAE116A3170301','8E73021EA84D8432C264A6D75C30F2A654C22D3FCEB22D8BAAD30A807110FD0E'],
    },

Навык производит аутентификацию по любому из этих параметров. Требуется хотя бы одно совпадение.

  • Задайте интенты (слова на которые будет реагировать навык).
    • help - фразы для воспроизведения фраз команды "помощь".
    • enable - слова, которые будут означать команду для сценариев включения
    • disable - слова, которые будут означать команду для сценариев выключения
    • timers - слова, которые будут означать команду для работы с таймерами
    • action_add - слова, которые будут означать команду для добавления (например таймера)
    • action_del - слова, которые будут означать команду для удаления (например таймера)
    intents: {
        help: ['справка', 'помощь', 'что ты умеешь'],
        enable: ['включи','включить'],
        disable: ['выключи','выключить']
        timers: ['таймер'],
        action_add: ['добавить','добавь'],
        action_del: ['удалить','удали'],
    },

  • Задаём с какой периодичностью обрабатывать таймеры:
    timer_period: 5,

Значение указывается в минутах. По умолчанию 5 минут.

Выполнение нескольких сценариев за одну команду

Создадим сценарии, которые мы и собираемся выполнять. Сделать это можно как в приложении Яндекса (Android, IOS), так и в web-интерфейсе квазара.

Покажу на примере. Создаем сценарий на включение люстры:

Сценарий включения люстры

По образу и подобию люстры создаём такой же сценарий, но для лампы.

Создаем сценарий для выполнения двух сценариев:

Результирующий сценарий, который выполнит два сценария

Открываем страницу с JSON по сценариям находим ID созданных сценариев "Включи люстру" и "Включи лампу" (включением лампы и люстры).

В вносим их в config.js в scenarios -> enable.

Где искать ID у сценария показано на скриншоте:

Scenarion json id.png

Аналогично вы можете поступить и со сценариями для выключения, создав сценарии "Выключи люстру" и "Выключи лампу", а затем добавить их в config.js в scenarios -> disable.

    scenarios: {
        enable: {       //сценарии на включение
            'люстру': '49c84e35-d1f3-4f8b-bc26-fe1ddd383d3f',   //сценарий: включи люстру
            'лампу': '0f70f28e-6b09-4876-8846-d34449dddc9e',    //сценарий: включи лампу
        },
        disable:{       //сценарии на выключение
            'люстру': '1e3d27e6-1731-4461-bbe0-e3ed75e41ed5',   //сценарий: выключи люстру
            'лампу': '212bc2b7-57db-4f79-a896-aff933b0e433',    //сценарий: выключи лампу
        }
    },

Исходя из примера когда вы скажете Алисе "Включай люстру и лампу" навык запустит два сценария "Включи люстру" и "Включи лампу", что, в свою очередь, приведет к включению устройств "люстра" и "лампа" в вашем Умном Доме.

Далее Вы можете комбинировать, создав сценарии, например:

  1. Выключи люстру и включи лампу
  2. Включи люстру и выключи лампу

Таймеры

Рассмотрим на примере самой частой хотелки - автоматическое понижение/повышение уровня громкости станции в зависимости от времени. Для достижения этой цели потребуется:

1. Создать сценарий для понижения громкости:

Сценарий для понижения громкости

2. Создать сценарий для повышения громкости:

Сценарий для повышения громкости

3. Открыть страницу с JSON по сценариям и найти ID созданных сценариев:

  • "Включи ночную громкость"
  • "Включи утреннюю громкость"

Копируем ID и вносим их в config.js в scenarios -> enable.

    scenarios: {
        enable: {       //сценарии на включение
            'ночную громкость': 'd9c96931-03d5-41a3-90d0-e930ff9c0994',
            'утреннюю громкость': '39094cf9-9040-4cb9-ba07-b2a669225fa5',
        },
    },

4. Перезапустить навык, т.к. вносились изменения в config.js.

Теперь говорим Алисе, например:

  • "попроси <НАЗВАНИЕ НАВЫКА> добавить таймер включи ночную громкость в 23 часа" - навык добавит таймер для ежедневного выполнения сценария "Включи ночную громкость" в 23 часа, что, в свою очередь, приведет к ежедневной автоматической установке громкости станции на 2 в 23 часа.
  • "попроси <НАЗВАНИЕ НАВЫКА> добавить таймер включи утреннюю громкость в 8 часов" - навык добавит таймер для ежедневного выполнения сценария "Включи утреннюю громкость" в 8 часов, что, в свою очередь, приведет к ежедневной автоматической установке громкости станции на 5 в 8-мь утра.

Созданные вами таймеры навык будет сохранять в файле timers.json. Пример содержимого файла:

[
  {
    "name":"ночную громкость",
    "action":"enable",
    "id":"d9c96931-03d5-41a3-90d0-e930ff9c0994",
    "days":[0,1,2,3,4,5,6],
    "hour":"23"
  },
  {
    "name":"утреннюю громкость",
    "action":"enable",
    "id":"39094cf9-9040-4cb9-ba07-b2a669225fa5",
    "days":[0,1,2,3,4,5,6],
    "hour":"8",
    "min":"15",
  },
  {
    "name":"телевизор",
    "action":"disable",
    "id":"3a5550951-c640-468b-a0cc-db5d81dbbe7c",
    "once":"1594561800",
  }
]

Где:

  • "name" и "action" - для понимания, что это за таймер
  • "id" - ID выполняемого сценария
  • "days" - дни, по которым будет выполняться сценарий. В Javascript воскресенье это нулевой день, а суббота 6.
  • "hour" - час, в который будет выполняться сценарий.
  • "min" - минуты, когда будет выполняться сценарий. Если минуты не указаны, то это означает ноль минут.
  • "once" - признак одноразового сценария, который будет выполнен в указанное в параметре время (unixtime).

Шаблоны команд, которые нужно использовать для добавления таймера:

  • попроси <НАЗВАНИЕ НАВЫКА> добавить таймер <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> в X часов - запуск ежедневно в X часов ровно.
  • попроси <НАЗВАНИЕ НАВЫКА> добавить таймер <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> в X часов Y минут - запуск ежедневно в X часов Y минут.
  • попроси <НАЗВАНИЕ НАВЫКА> добавить таймер <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> по будням в X часов - запуск по будням в X часов ровно.
  • попроси <НАЗВАНИЕ НАВЫКА> добавить таймер <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> по выходным в X часов Y минут - запуск по выходным в X часов Y минут.
  • попроси <НАЗВАНИЕ НАВЫКА> добавить таймер <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> в <НАЗВАНИЕ ДНЯ (или дней) НЕДЕЛИ> в X часов - запуск по перечисленным дням в X часов ровно.
  • попроси <НАЗВАНИЕ НАВЫКА> добавить таймер <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> через Y минут - одноразовый запуск через Y минут.
  • попроси <НАЗВАНИЕ НАВЫКА> добавить таймер <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> через X часов Y минут - одноразовый запуск через X часов Y минут.
  • попроси <НАЗВАНИЕ НАВЫКА> <ДЕЙСТВИЕ> <НАЗВАНИЕ СЦЕНАРИЯ> через Y минут - одноразовый запуск Y минут.

Примеры установки таймеров согласно шаблонам:

  • попроси дом вируса добавить таймер включи лампу в 21 час
  • попроси дом вируса добавить таймер выключи люстру в 21 час 10 минут
  • попроси дом вируса добавить таймер включи коридор по будням в 8 часов
  • попроси дом вируса добавить таймер выключи коридор по будням в 8 часов 10 минут
  • попроси дом вируса добавить таймер выключи телевизор по понедельникам средам пятницам в 22 часа
  • попроси дом вируса добавить таймер включи аквариум в субботу в 9 часов 15 минут
  • попроси дом вируса добавить таймер выключи аквариум через 4 часа 30 минут
  • попроси дом вируса добавить таймер выключи телевизор через 15 минут
  • попроси дом вируса выключить телевизор через 5 минут

Команда для удаления таймера аналогична его добавлению, но вместо "добавить" нужно произнести "удалить". Ну или просто удалить таймер вручную - отредактировав файл timers.json.

Одноразовый таймер удаляется сразу после его исполнения.

Узнать какие таймеры установлены можно командами:

  • попроси <НАЗВАНИЕ НАВЫКА> список таймеров
  • попроси <НАЗВАНИЕ НАВЫКА> какие установлены таймеры
После правки timers.json навык перезапускать НЕ надо. Файл timers.json будет перечитан автоматически при следующей обработке таймеров, которая производится каждые X минут (где X это значение указанное вами в timer_period в config.js).

Послесловие

Если возникают проблемы с выполнением сценария, то необходимо включить логи и смотреть, что происходит при выполнении сценария, по ним. Для быстрого понимания можно воспользоваться командой:

  • попроси <НАЗВАНИЕ НАВЫКА> отчёт

Навык зачитает статус крайнего выполненного сценария. Так статус "200" - все ОК. Статус "403" или "302" - проблема с авторизацией.


Видеодемонстрация работы навыка:

Внимание: После внесения изменений в файл config.js (настройки навыка) необходимо перезапускать скрипт навыка.

С автором статьи можно связаться в телеграм: @VirusNet.

Источник — https://wiki.yaboard.com/index.php?title=Таймеры,_несколько_команд_устройству,_TTS_(NodeJS)&oldid=4347 // MOD ext links // End MOD