From 1126e8875598b1bbafc4bed732526af245d5685e Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Mon, 13 Jul 2020 15:06:13 +0300 Subject: [PATCH] Fix external_url --- README.md | 6 +- custom_components/yandex_dialogs/utils.py | 138 +++++++++++++--------- 2 files changed, 82 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index dd98e28..f34222f 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Платформа Яндекс.Диалогов позволяет гибко обрабатывать сказанные фразы через [Natural Language Processing](https://yandex.ru/dev/dialogs/alice/doc/nlu-docpage/) (NLU) от Яндекса. -Фраза, которую нужно распознать, называется Интентом. ID интента и все составляющие разобранной фразы прилетят в Home Assistant. И их можно использовать в автоматизация. +Фраза, которую нужно распознать, называется Интентом. ID интента и все составляющие разобранной фразы прилетят в Home Assistant. И их можно использовать в автоматизациях. При желании вы можете не пользоваться Интентами, а анализовать фразы в автоматизациях Home Assistant или Node-RED. @@ -83,7 +83,7 @@ yandex_dialogs: intent_script: yandex_default: # это скрипт по умолчанию - action: # действие опционально и должно уложится в пару секунд + action: # действие опционально и должно уложиться в пару секунд - service: persistent_notification.create data: title: Команда из Яндекса @@ -177,7 +177,7 @@ automation: - `$room` - слово с долларом это переменная - `[...]` - квадрытные скобки означают, что слова могут идти в любом порядке - `(какая)?` - вопрос означает, что слова может не быть -- `%lemma` - означает режим сравнение без учёта формы слова (например "*включай свет*" приравнивается "*включи свет*") +- `%lemma` - означает режим сравнение без учёта формы слова (например "*включай свет*" приравнивается к "*включи свет*") Полная [документация](https://yandex.ru/dev/dialogs/alice/doc/nlu-docpage/). diff --git a/custom_components/yandex_dialogs/utils.py b/custom_components/yandex_dialogs/utils.py index 5919dbb..0b205c0 100644 --- a/custom_components/yandex_dialogs/utils.py +++ b/custom_components/yandex_dialogs/utils.py @@ -6,6 +6,7 @@ from os import path from homeassistant.helpers.aiohttp_client import async_create_clientsession +from homeassistant.helpers.network import get_url, NoURLAvailableError from homeassistant.helpers.typing import HomeAssistantType _LOGGER = logging.getLogger(__name__) @@ -14,11 +15,15 @@ async def create_dialog(hass: HomeAssistantType, name: str): + # check external HTTPS URL try: - if not hass.config.external_url: - _LOGGER.error("Empty Home Assistant External URL") - return + hass_url = get_url(hass, require_ssl=True, allow_internal=False) + _LOGGER.debug(f"External hass URL: {hass_url}") + except NoURLAvailableError: + _LOGGER.error("Can't get external HTTPS URL") + return + try: cachefile = hass.config.path(f".yandex_station.json") if not path.isfile(cachefile): @@ -33,90 +38,105 @@ async def create_dialog(hass: HomeAssistantType, name: str): session = async_create_clientsession(hass) session.cookie_jar._cookies = pickle.loads(raw) + # check if skill exists r = await session.get(INDEX) - assert r.status == 200, "Get Index" + assert r.status == 200, await r.read() data = await r.text() m = re.search(r'"secretkey":"(.+?)"', data) headers = {'x-csrf-token': m[1]} r = await session.get(f"{INDEX}/api/snapshot", headers=headers) - assert r.status == 200, "Get Skills" + assert r.status == 200, await r.read() data = await r.json() for skill in data['result']['skills']: - if skill['name'] == name: + if skill['name'] == name or skill['draft']['name'] == name: url = f"{INDEX}/skills/{skill['id']}" - hass.components.persistent_notification.async_create( - f"[Ссылка]({url}) на диалог", - title="Yandex Dialogs") + _LOGGER.debug(f"Skill alreay exists: {url}") return + # create new skill r = await session.post(f"{INDEX}/api/skills", headers=headers, json={'channel': 'aliceSkill'}) - assert r.status == 201, "Create Skill" + assert r.status == 201, await r.read() data = await r.json() skill_id = data['result']['id'] + skill_url = f"{INDEX}/skills/{data['result']['id']}" filename = path.join(path.dirname(path.abspath(__file__)), 'logo.png') r = await session.post( f"{INDEX}/api/skills/{skill_id}/logo", headers=headers, data={'file': open(filename, 'rb')}) - assert r.status == 201, "Upload Logo" + assert r.status == 201, await r.read() data = await r.json() logo_id = data['result']['id'] - hass_uri = f"{hass.config.external_url}api/yandex_dialogs" - r = await session.patch( - f"{INDEX}/api/skills/{skill_id}/draft", - headers=headers, json={ - "activationPhrases": [ - name - ], - "appMetricaApiKey": "", - "backendSettings": { - "backendType": "webhook", - "functionId": "", - "uri": hass_uri - }, - "exactSurfaces": [], - "hideInStore": False, - "logo2": None, - "logoId": logo_id, - "name": name, - "noteForModerator": "", - "oauthAppId": None, - "publishingSettings": { - "brandVerificationWebsite": "", - "category": "utilities", - "description": "Home Assistant", - "developerName": "Home Assistant", - "email": "", - "explicitContent": None, - "structuredExamples": [ - { - "activationPhrase": name, - "marker": "запусти навык", - "request": "" - } - ] - }, - "requiredInterfaces": [], - "rsyPlatformId": "", - "skillAccess": "private", - "surfaceBlacklist": [], - "surfaceWhitelist": [], - "useStateStorage": False, - "voice": "shitova.us", - "yaCloudGrant": False - }) - assert r.status == 200, "Patch Draft" + payload = { + "activationPhrases": [name], + "appMetricaApiKey": "", + "backendSettings": { + "backendType": "webhook", + "functionId": "", + "uri": hass_url + '/api/yandex_dialogs' + }, + "exactSurfaces": [], + "hideInStore": False, + "logo2": None, + "logoId": logo_id, + "name": name, + "noteForModerator": "", + "oauthAppId": None, + "publishingSettings": { + "brandVerificationWebsite": "", + "category": "utilities", + "description": "Home Assistant", + "developerName": "Home Assistant", + "email": "", + "explicitContent": None, + "structuredExamples": [{ + "activationPhrase": name, + "marker": "запусти навык", + "request": "" + }] + }, + "requiredInterfaces": [], + "rsyPlatformId": "", + "skillAccess": "private", + "surfaceBlacklist": [], + "surfaceWhitelist": [], + "useStateStorage": False, + "voice": "shitova.us", + "yaCloudGrant": False + } + r = await session.patch(f"{INDEX}/api/skills/{skill_id}/draft", + headers=headers, json=payload) + assert r.status == 200, await r.read() + + # check if webhook works + payload = {"text": "", "isDraft": True, "sessionId": "", + "sessionSeq": 0, "surface": "mobile", + "isAnonymousUser": False} + r = await session.post(f"{INDEX}/api/skills/{skill_id}/message", + headers=headers, json=payload) + assert r.status == 201, await r.read() + data = await r.json() + error = data['result'].get('error') + if error: + _LOGGER.debug(f"Ошибка при создании навыка: {error}") + hass.components.persistent_notification.async_create( + f"При создании навыка: [ссыка]({skill_url})\n" + f"возникла ошибка: `{error}`\n" + f"Проверьте внешний доступ: {hass_url}", + title="Yandex Dialogs") + return + # publish skill r = await session.post(f"{INDEX}/api/skills/{skill_id}/release", headers=headers) - assert r.status == 201, "Release Skill" + assert r.status == 201, await r.read() - url = f"{INDEX}/skills/{skill_id}" + _LOGGER.debug("Навык успешно создан") hass.components.persistent_notification.async_create( - f"Диалог успешно создан: [ссылка]({url})", + f"Навык успешно создан: [ссылка]({skill_url})", title="Yandex Dialogs") except Exception: