Skip to content

Commit

Permalink
Add new event yandex_scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexxIT committed Jan 16, 2024
1 parent 49bef01 commit 0b2c903
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 12 deletions.
61 changes: 54 additions & 7 deletions custom_components/yandex_station/core/yandex_quasar.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import asyncio
import json
import logging
from datetime import datetime
from typing import Optional

from aiohttp import WSMsgType
Expand Down Expand Up @@ -423,14 +424,60 @@ async def connect(self):
break
resp = msg.json()
# "ping", "update_scenario_list"
if resp.get("operation") != "update_states":
continue
try:
resp = json.loads(resp["message"])
for device in resp["updated_devices"]:
operation = resp.get("operation")
if operation == "update_states":
try:
resp = json.loads(resp["message"])
for device in resp["updated_devices"]:
self.dispatch_update(device["id"], device)
except Exception as e:
_LOGGER.debug(f"Parse quasar update error: {msg.data}", exc_info=e)

elif operation == "update_scenario_list":
if '"source":"create_scenario_launch"' in resp["message"]:
asyncio.create_task(self.get_voice_trigger(1))

async def get_voice_trigger(self, retries: int = 0):
try:
# 1. Get all scenarios history
r = await self.session.get(
"https://iot.quasar.yandex.ru/m/user/scenarios/history"
)
raw = await r.json()

# 2. Search latest scenario with voice trigger
scenario = next(
s
for s in raw["scenarios"]
if s["trigger_type"] == "scenario.trigger.voice"
)

# 3. Check if scenario too old
d1 = datetime.strptime(r.headers["Date"], "%a, %d %b %Y %H:%M:%S %Z")
d2 = datetime.strptime(scenario["launch_time"], "%Y-%m-%dT%H:%M:%SZ")
dt = (d1 - d2).total_seconds()
if dt > 5:
# try to get history once more
if retries:
await self.get_voice_trigger(retries - 1)
return

# 4. Get speakers from launch devices
r = await self.session.get(
f"https://iot.quasar.yandex.ru/m/v3/user/launches/{scenario['id']}/edit"
)
raw = await r.json()

for step in raw["launch"]["steps"]:
for device in step["parameters"]["launch_devices"]:
# 5. Check if speaker device
if "quasar_info" not in device:
continue
device["scenario_name"] = raw["launch"]["name"]
self.dispatch_update(device["id"], device)
except Exception as e:
_LOGGER.debug(f"Parse quasar update error: {msg.data}", exc_info=e)

except Exception as e:
_LOGGER.debug("Can't get voice scenario", exc_info=e)

async def run_forever(self):
while not self.session.session.closed:
Expand Down
15 changes: 10 additions & 5 deletions custom_components/yandex_station/core/yandex_station.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,19 @@ def on_update(self, device: dict):
return

for item in device["capabilities"]:
if item["type"] != "devices.capabilities.quasar.server_action":
continue
event_data = item["state"]
if not event_data:
if not (event_data := item["state"]):
continue

event_data["entity_id"] = self.entity_id
event_data["name"] = self.name
self.hass.bus.async_fire("yandex_speaker", event_data)

if "scenario_name" in device:
event_data["scenario_name"] = device["scenario_name"]
self.debug(f"yandex_scenario: {event_data}")
self.hass.bus.async_fire("yandex_scenario", event_data)
else:
self.debug(f"yandex_speaker: {event_data}")
self.hass.bus.async_fire("yandex_speaker", event_data)

# ADDITIONAL CLASS FUNCTION

Expand Down
11 changes: 11 additions & 0 deletions tests/test_misc.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from datetime import datetime

from homeassistant.components import media_source

from custom_components.yandex_station.core import utils
Expand All @@ -23,3 +25,12 @@ def test_media_source():

media_id = media_source.generate_media_source_id("tts", id1 + id2)
assert utils.decode_media_source(media_id) == query1 | query2


def test_parse_date():
s1 = "Tue, 16 Jan 2024 04:57:06 GMT" # RFC 822
s2 = "2024-01-16T04:57:05Z" # RFC 3339
d1 = datetime.strptime(s1, "%a, %d %b %Y %H:%M:%S %Z")
d2 = datetime.strptime(s2, "%Y-%m-%dT%H:%M:%SZ")
dt = (d1 - d2).total_seconds()
assert dt < 5

0 comments on commit 0b2c903

Please sign in to comment.