1
1
from __future__ import annotations
2
2
3
+ from abc import ABC , abstractmethod
3
4
from dataclasses import dataclass
4
5
import json
5
6
import logging
21
22
22
23
URL_USER = "https://iot.quasar.yandex.ru/m/user"
23
24
URL_V3_USER = "https://iot.quasar.yandex.ru/m/v3/user"
25
+ URL_V4_USER = "https://iot.quasar.yandex.ru/m/v4/user"
24
26
DEFAULT_RECONNECTION_DELAY = 2
25
27
MAX_RECONNECTION_DELAY = 180
26
28
@@ -44,76 +46,124 @@ def from_dict(cls, data: ConfigType) -> Device:
44
46
)
45
47
46
48
47
- class ScenarioStep :
48
- def __init__ (self , value : str | None = None , launch_devices : list [Any ] | None = None ) -> None :
49
- self ._value = value
50
- self ._launch_devices = launch_devices or []
51
- self ._request_speaker_capabilities : list [dict [Any , Any ]] = []
49
+ class ScenarioStepItem (ABC ):
50
+ """
51
+ Действие в сценариях.
52
+ """
53
+
54
+ @property
55
+ @abstractmethod
56
+ def as_dict (self ) -> ConfigType :
57
+ pass
58
+
59
+
60
+ class ScenarioStepItemDeviceChannel (ScenarioStepItem ):
61
+ """
62
+ Действие "Канал X" для служебного плеера.
63
+ """
64
+
65
+ def __init__ (self , device : Device , channel : int ):
66
+ self ._device = device
67
+ self ._channel = channel
52
68
53
69
@property
54
70
def as_dict (self ) -> ConfigType :
55
71
return {
56
- "type" : "scenarios.steps.actions" ,
57
- "parameters" : {
58
- "launch_devices" : self ._launch_devices ,
59
- "requested_speaker_capabilities" : self ._request_speaker_capabilities ,
72
+ "id" : self ._device .id ,
73
+ "type" : "step.action.item.device" ,
74
+ "value" : {
75
+ "id" : self ._device .id ,
76
+ # "item_type": "device",
77
+ "capabilities" : [
78
+ {
79
+ "type" : "devices.capabilities.range" ,
80
+ "state" : {
81
+ "instance" : "channel" ,
82
+ "value" : self ._channel ,
83
+ },
84
+ }
85
+ ],
60
86
},
61
87
}
62
88
63
89
64
- class ScenarioStepTTS ( ScenarioStep ):
90
+ class ScenarioStepItemRequestedDevice ( ScenarioStepItem , ABC ):
65
91
"""
66
- Проговаривает текст полностью и только потом выполняет следующий шаг.
67
- В интерфейсе: "Прочитать текст вслух"
68
- В список событий не попадает.
92
+ Действия из раздела "Любое умное устройство, которое активирует сценарий"
69
93
"""
70
94
71
- def __init__ (self , value : str , launch_devices : list [Any ] | None = None ) -> None :
72
- super ().__init__ (value , launch_devices )
95
+ @property
96
+ def as_dict (self ) -> ConfigType :
97
+ return {
98
+ "id" : "requested-device" ,
99
+ "type" : "step.action.item.requested_device_with_assistant" ,
100
+ "value" : self ._value ,
101
+ }
73
102
74
- self ._request_speaker_capabilities .append (
75
- {
76
- "parameters" : {"instance" : "tts" },
77
- "retrievable" : False ,
78
- "state" : {"instance" : "tts" , "value" : {"text" : self ._value }},
79
- "type" : "devices.capabilities.quasar" ,
80
- }
81
- )
103
+ @property
104
+ @abstractmethod
105
+ def _value (self ) -> ConfigType :
106
+ pass
82
107
83
108
84
- class ScenarioStepTextAction ( ScenarioStep ):
109
+ class ScenarioStepItemRequestedDeviceTTS ( ScenarioStepItemRequestedDevice ):
85
110
"""
86
- Выполняет команду на колонке.
87
- В интерфейсе: "Ответить на вопрос или выполнить команду "
111
+ Проговаривает текст на колонке, действие не попадает в список событий .
112
+ В интерфейсе: "Прочитать текст вслух "
88
113
"""
89
114
90
- def __init__ (self , value : str , launch_devices : list [ Any ] | None = None ) -> None :
91
- super (). __init__ ( value , launch_devices )
115
+ def __init__ (self , text : str ) :
116
+ self . _text = text
92
117
93
- self ._request_speaker_capabilities .append (
94
- {
95
- "parameters" : {"instance" : "text_action" },
96
- "state" : {"instance" : "text_action" , "value" : self ._value },
97
- "type" : "devices.capabilities.quasar.server_action" ,
98
- }
99
- )
118
+ @property
119
+ def _value (self ) -> ConfigType :
120
+ return {
121
+ "type" : "devices.capabilities.quasar" ,
122
+ "state" : {
123
+ "instance" : "tts" ,
124
+ "value" : {"text" : self ._text },
125
+ },
126
+ }
100
127
101
128
102
- class ScenarioStepPhraseAction ( ScenarioStep ):
129
+ class ScenarioStepItemRequestedDeviceTTSPA ( ScenarioStepItemRequestedDevice ):
103
130
"""
104
- Проговаривает текст и сразу выполняет следующую команду .
131
+ Проговаривает текст на колонке, действие попадает в список событий .
105
132
В интерфейсе: отсутствует
106
133
"""
107
134
108
- def __init__ (self , value : str , launch_devices : list [ Any ] | None = None ) -> None :
109
- super (). __init__ ( value , launch_devices )
135
+ def __init__ (self , text : str ) :
136
+ self . _text = text
110
137
111
- self ._request_speaker_capabilities .append (
112
- {
113
- "state" : {"instance" : "phrase_action" , "value" : self ._value },
114
- "type" : "devices.capabilities.quasar.server_action" ,
115
- }
116
- )
138
+ @property
139
+ def _value (self ) -> ConfigType :
140
+ return {
141
+ "type" : "devices.capabilities.quasar.server_action" ,
142
+ "state" : {
143
+ "instance" : "phrase_action" ,
144
+ "value" : self ._text ,
145
+ },
146
+ }
147
+
148
+
149
+ class ScenarioStepItemRequestedDeviceTextAction (ScenarioStepItemRequestedDevice ):
150
+ """
151
+ Выполняет команду на колонке.
152
+ В интерфейсе: "Ответить на вопрос или выполнить команду"
153
+ """
154
+
155
+ def __init__ (self , command : str ):
156
+ self ._command = command
157
+
158
+ @property
159
+ def _value (self ) -> ConfigType :
160
+ return {
161
+ "type" : "devices.capabilities.quasar.server_action" ,
162
+ "state" : {
163
+ "instance" : "text_action" ,
164
+ "value" : self ._command ,
165
+ },
166
+ }
117
167
118
168
119
169
class YandexQuasar :
@@ -160,48 +210,41 @@ async def async_get_intents(self) -> dict[str, str]:
160
210
return rv
161
211
162
212
async def async_add_or_update_intent (
163
- self , intent : Intent , intent_quasar_id : str | None , target_device : Device | None
213
+ self , intent : Intent , intent_quasar_id : str | None , intent_player_device : Device | None
164
214
) -> None :
165
- steps : list [ScenarioStep ] = []
166
-
167
- if target_device :
168
- steps .append (
169
- ScenarioStep (
170
- launch_devices = [
171
- {
172
- "id" : target_device .id ,
173
- "capabilities" : [
174
- {
175
- "type" : "devices.capabilities.range" ,
176
- "state" : {"instance" : "channel" , "relative" : False , "value" : intent .id },
177
- }
178
- ],
179
- }
180
- ]
181
- )
182
- )
183
-
184
- if intent .say_phrase and intent .execute_command :
185
- steps .append (ScenarioStepTTS (intent .say_phrase ))
186
- steps .append (ScenarioStepTextAction (intent .scenario_step_value ))
187
- elif intent .say_phrase :
188
- steps .append (ScenarioStepPhraseAction (intent .scenario_step_value ))
215
+ step_items : list [ScenarioStepItem ] = []
216
+
217
+ if intent_player_device :
218
+ if intent .say_phrase :
219
+ step_items .append (ScenarioStepItemRequestedDeviceTTS (intent .say_phrase ))
220
+ step_items .append (ScenarioStepItemDeviceChannel (intent_player_device , intent .id ))
189
221
else :
190
- steps .append (ScenarioStepTextAction (intent .scenario_step_value ))
222
+ if intent .say_phrase and intent .execute_command :
223
+ step_items .append (ScenarioStepItemRequestedDeviceTTS (intent .say_phrase ))
224
+ step_items .append (ScenarioStepItemRequestedDeviceTextAction (intent .scenario_text_command ))
225
+ elif intent .say_phrase :
226
+ step_items .append (ScenarioStepItemRequestedDeviceTTSPA (intent .scenario_text_command ))
227
+ else :
228
+ step_items .append (ScenarioStepItemRequestedDeviceTextAction (intent .scenario_text_command ))
191
229
192
230
payload = {
193
231
"name" : intent .scenario_name ,
194
232
"icon" : "home" ,
195
233
"triggers" : [{"type" : "scenario.trigger.voice" , "value" : v } for v in intent .trigger_phrases ],
196
- "steps" : [s .as_dict for s in steps ],
234
+ "steps" : [
235
+ {
236
+ "type" : "scenarios.steps.actions.v2" ,
237
+ "parameters" : {"items" : [si .as_dict for si in step_items ]},
238
+ }
239
+ ],
197
240
}
198
241
199
242
if intent_quasar_id :
200
243
_LOGGER .debug (f"Обновление сценария { intent .scenario_name !r} : { payload } " )
201
- r = await self ._session .put (f"{ URL_USER } /scenarios/{ intent_quasar_id } " , json = payload )
244
+ r = await self ._session .put (f"{ URL_V4_USER } /scenarios/{ intent_quasar_id } " , json = payload )
202
245
else :
203
246
_LOGGER .debug (f"Создание сценария { intent .scenario_name !r} : { payload } " )
204
- r = await self ._session .post (f"{ URL_USER } /scenarios" , json = payload )
247
+ r = await self ._session .post (f"{ URL_V4_USER } /scenarios" , json = payload )
205
248
206
249
resp = await r .json ()
207
250
assert resp ["status" ] == "ok" , resp
0 commit comments