├── README.md ├── custom_components └── hello_miai │ ├── __init__.py │ ├── __pycache__ │ └── __init__.cpython-37.pyc │ ├── manifest.json │ └── services.yaml ├── hacs.json └── info.md /README.md: -------------------------------------------------------------------------------- 1 | # 本人不是作者,再此处放置是为了HACS安装方便,在此感谢作者。 2 | 3 | 配置例子,填写绑定小爱音箱的用户账号信息: 4 | 5 | ``` 6 | hello_miai: 7 | miid: '13123456789' 8 | password: 'password' 9 | ``` 10 | 11 | 调用服务,如果你有多个音箱,miai_num代表你的音箱id。 12 | ``` 13 | wait_time: 0 14 | miai_num: 0 15 | message: 你好天睿tera,我不是小爱。 16 | ``` 17 | 18 | 19 | 更多教程 :https://sumju.net 20 | 电报 群 :https://t.me/joinchat/J26zVFGMhWWB1sBTFvcjaA 21 | 电报频道 :https://t.me/itcommander 22 | Twitter :https://twitter.com/itcommander2 23 | Facebook. :https://www.facebook.com/itcommander.itcommander.1 24 | 25 | -------------------------------------------------------------------------------- /custom_components/hello_miai/__init__.py: -------------------------------------------------------------------------------- 1 | import voluptuous as vol 2 | import homeassistant.helpers.config_validation as cv 3 | import json 4 | import requests 5 | import os 6 | import re 7 | import random 8 | import string 9 | import hashlib 10 | import time 11 | import base64 12 | import hass_frontend 13 | from urllib import parse 14 | from threading import Thread, Event 15 | 16 | 17 | import logging 18 | _LOGGER = logging.getLogger(__name__) 19 | 20 | 21 | class xiaomi_tts: 22 | 23 | def __init__(self, hass, config, user=None, password=None): 24 | requests.packages.urllib3.disable_warnings() 25 | self.login_resutl = False 26 | self.config = config 27 | self.hass = hass 28 | self._CONFIGURING = {} 29 | self._user = user 30 | self._password = password 31 | self.Service_Token = None 32 | self.deviceIds = None 33 | self.userId = None 34 | self._cookies = {} 35 | self._request = requests.session() 36 | self._headers = {'Host': 'account.xiaomi.com', 37 | 'Connection': 'keep-alive', 38 | 'Upgrade-Insecure-Requests': '1', 39 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36', 40 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 41 | 'Accept-Encoding': 'gzip, deflate, br', 42 | 'Accept-Language': 'zh-CN,zh;q=0.9'} 43 | 44 | self._LoginByPassord() 45 | # else: 46 | # self._LoginByPassord()#No write permission 47 | 48 | @property 49 | def Service_Token_Cookie(self): 50 | return self.Service_Token 51 | 52 | @property 53 | def Login_resutl(self): 54 | return self.login_resutl 55 | 56 | @property 57 | def deviceIds_miai(self): 58 | return self.deviceIds 59 | 60 | def request_app_setup(self, image_name): 61 | """Assist user with configuring the Fitbit dev application.""" 62 | configurator = self.hass.components.configurator 63 | try: 64 | self.hass.components.configurator.request_done( 65 | self._CONFIGURING.pop("MIAI")) 66 | except: 67 | pass 68 | 69 | def fitbit_configuration_callback(callback_data): 70 | self._serviceLoginAuth2(callback_data.get('code')) 71 | if self._serviceLoginAuth2_json['code'] == 0: 72 | if not self._login_miai(): 73 | _LOGGER.warning('login miai Failed') 74 | else: 75 | if not self._get_deviceId(): 76 | _LOGGER.warning('get_deviceId Failed') 77 | elif self._serviceLoginAuth2_json['code'] == 70016: 78 | _LOGGER.warning('incorrect password') 79 | elif self._serviceLoginAuth2_json['code'] == 87001: 80 | _LOGGER.warning('incorrect codes') 81 | self._LoginByPassord() 82 | else: 83 | _LOGGER.error(self._serviceLoginAuth2_json) 84 | if self.Service_Token != None and self.deviceIds != None: 85 | self.hass.components.configurator.request_done( 86 | self._CONFIGURING.pop("MIAI")) 87 | self.login_resutl = True 88 | 89 | description = """请输入验证码""" 90 | 91 | submit = "登录" 92 | 93 | self._CONFIGURING['MIAI'] = configurator.request_config( 94 | 'MIAI', fitbit_configuration_callback, 95 | description=description, submit_caption=submit, 96 | description_image="/static/images/miai{}.jpg".format(image_name), 97 | fields=[{'id': 'code', 'name': '验证码', 'type': ''}] 98 | ) 99 | 100 | def _LoginByPassord(self): 101 | if not self._get_sign(): 102 | _LOGGER.warning("get_sign Failed") 103 | else: 104 | if not self._serviceLoginAuth2(): 105 | _LOGGER.warning('Request Login_url Failed') 106 | else: 107 | if self._serviceLoginAuth2_json['code'] == 0: 108 | # logon success,run self._login_miai() 109 | if not self._login_miai(): 110 | _LOGGER.warning('login miai Failed') 111 | else: 112 | if not self._get_deviceId(): 113 | _LOGGER.warning('get_deviceId Failed') 114 | if self.Service_Token != None and self.deviceIds != None: 115 | self.login_resutl = True 116 | elif self._serviceLoginAuth2_json['code'] == 87001: 117 | self._headers['Cookie'] = self._headers['Cookie'] + \ 118 | '; pwdToken={}'.format(self._cookies['pwdToken']) 119 | path = os.path.dirname(hass_frontend.__file__) 120 | try: 121 | current_time = int(round(time.time() * 1000)) 122 | r = self._request.get('https://account.xiaomi.com/pass/getCode?icodeType=login&{}'.format( 123 | current_time), headers=self._headers, timeout=3, cookies=self._cookies, verify=False) 124 | self._cookies['ick'] = self._request.cookies.get_dict()[ 125 | 'ick'] 126 | if os.access(path+'/images', os.W_OK): 127 | with open(path+'/images'+'/miai{}.jpg'.format(current_time), 'wb') as f: 128 | f.write(r.content) 129 | f.close() 130 | self.request_app_setup(current_time) 131 | except IOError as e: 132 | _LOGGER.warning(e) 133 | except BaseException as e: 134 | _LOGGER.warning(e) 135 | 136 | elif self._serviceLoginAuth2_json['code'] == 70016: 137 | _LOGGER.error('incorrect password') 138 | 139 | def _get_sign(self): 140 | url = 'https://account.xiaomi.com/pass/serviceLogin?callback=https%3A%2F%2Faccount.xiaomi.com%2Fsts%2Foauth%3Fsign%3Dt1ErD4mAHg8WlXXrbezQT8%252F6%252BjI%253D%26followup%3Dhttps%253A%252F%252Faccount.xiaomi.com%252Foauth2%252Fauthorize%253Fclient_id%253D2882303761517851828%2526response_type%253Dtoken%2526state%253Dproduction%2526skip_confirm%253Dfalse%2526redirect_uri%253Dhttp%25253A%25252F%25252Fdebugger.iot.mi.com%25252Fcallback%25252Fxiaomi%2526nonce%253DVD0oCEj1vGkBmdjF%2526sign%253DobppTRajlpAdGoqWYXJSMNllIS4%25253D%2526scope%253D1%2525203%2525206000%2526_sas%253Dtrue%26sid%3Doauth2.0&sid=oauth2.0&lsrp_appName=%E4%BD%BF%E7%94%A8%E5%B0%8F%E7%B1%B3%E5%B8%90%E5%8F%B7%E7%99%BB%E5%BD%95%24%7B%E8%AE%BE%E5%A4%87%E8%B0%83%E8%AF%95%E5%99%A8%7D%24&_customDisplay=20&scope=1%206000&client_id=2882303761517851828&_locale=zh_CN&_ssign=2%26V1_oauth2.0%26LwRoUMFKzmTZC3WY%2BEa2KA7EZDY%3D' 141 | pattern = re.compile(r'_sign":"(.*?)",') 142 | try: 143 | r = self._request.get( 144 | url, headers=self._headers, timeout=3, verify=False) 145 | # self._cookies['pass_trace'] = self._request.cookies.get_dict()[ 146 | # 'pass_trace'] 147 | self._sign = pattern.findall(r.text)[0] 148 | return True 149 | except BaseException as e: 150 | _LOGGER.warning(e) 151 | return False 152 | 153 | def _serviceLoginAuth2(self, captCode=None): 154 | url = 'https://account.xiaomi.com/pass/serviceLoginAuth2' 155 | self._headers['Content-Type'] = 'application/x-www-form-urlencoded' 156 | self._headers['Accept'] = '*/*' 157 | self._headers['Origin'] = 'https://account.xiaomi.com' 158 | self._headers['Referer'] = 'https://account.xiaomi.com/pass/serviceLogin?sid=micoapi' 159 | # self._headers['Cookie']='pass_ua={}; deviceId={}; pass_trace={}; uLocale={}; JSESSIONID={}'.format(self._cookies['pass_ua'],self._cookies['deviceId'],self._cookies['pass_trace'],self._cookies['uLocale'],self._cookies['JSESSIONID']) 160 | # self._headers['Cookie'] = 'pass_trace={};'.format( 161 | # self._cookies['pass_trace']) 162 | 163 | auth_post_data = {'_json': 'true', 164 | '_sign': self._sign, 165 | 'callback': 'https://api.mina.mi.com/sts', 166 | 'hash': hashlib.md5(self._password.encode('utf-8')).hexdigest().upper(), 167 | 'qs': '%3Fsid%3Dmicoapi', 168 | 'serviceParam': '{"checkSafePhone":false}', 169 | 'sid': 'micoapi', 170 | 'user': self._user} 171 | 172 | try: 173 | if captCode != None: 174 | url = 'https://account.xiaomi.com/pass/serviceLoginAuth2?_dc={}'.format( 175 | int(round(time.time() * 1000))) 176 | auth_post_data['captCode'] = captCode 177 | self._headers['Cookie'] = self._headers['Cookie'] + \ 178 | '; ick={}'.format(self._cookies['ick']) 179 | r = self._request.post(url, headers=self._headers, data=auth_post_data, 180 | timeout=3, cookies=self._cookies, verify=False) 181 | self._cookies['pwdToken'] = self._request.cookies.get_dict()[ 182 | 'passToken'] 183 | self._serviceLoginAuth2_json = json.loads(r.text[11:]) 184 | return True 185 | except BaseException as e: 186 | return False 187 | _LOGGER.warning(e) 188 | 189 | def _login_miai(self): 190 | serviceToken = "nonce={}&{}".format( 191 | self._serviceLoginAuth2_json['nonce'], self._serviceLoginAuth2_json['ssecurity']) 192 | serviceToken_sha1 = hashlib.sha1(serviceToken.encode('utf-8')).digest() 193 | base64_serviceToken = base64.b64encode(serviceToken_sha1) 194 | loginmiai_header = {'User-Agent': 'MISoundBox/1.4.0,iosPassportSDK/iOS-3.2.7 iOS/11.2.5', 195 | 'Accept-Language': 'zh-cn', 'Connection': 'keep-alive'} 196 | url = self._serviceLoginAuth2_json['location'] + \ 197 | "&clientSign="+parse.quote(base64_serviceToken.decode()) 198 | try: 199 | r = self._request.get( 200 | url, headers=loginmiai_header, timeout=3, verify=False) 201 | if r.status_code == 200: 202 | self._Service_Token = self._request.cookies.get_dict()[ 203 | 'serviceToken'] 204 | self.userId = self._request.cookies.get_dict()['userId'] 205 | return True 206 | else: 207 | return False 208 | except BaseException as e: 209 | _LOGGER.warning(e) 210 | return False 211 | 212 | def _get_deviceId(self): 213 | url = 'https://api.mina.mi.com/admin/v2/device_list?master=1&requestId=CdPhDBJMUwAhgxiUvOsKt0kwXThAvY' 214 | get_deviceId_header = {'Cookie': 'userId={};serviceToken={}'.format( 215 | self.userId, self._Service_Token)} 216 | try: 217 | r = self._request.get( 218 | url, headers=get_deviceId_header, timeout=3, verify=False) 219 | model = {"Cookie": "userId={};serviceToken={}".format( 220 | self.userId, self._Service_Token), "deviceId": json.loads(r.text)['data']} 221 | self.Service_Token = model['Cookie'] 222 | self.deviceIds = model['deviceId'] 223 | return True 224 | except BaseException as e: 225 | _LOGGER.warning(e) 226 | return False 227 | 228 | def _text_to_speech(self, text, tts_cookie, deviceIds_miai, num=0): 229 | try: 230 | url = "https://api.mina.mi.com/remote/ubus?deviceId={}&message=%7B%22text%22%3A%22{}%22%7D&method=text_to_speech&path=mibrain&requestId={}".format( 231 | self.deviceIds_miai[num]['deviceID'], parse.quote(text), ''.join(random.sample(string.ascii_letters + string.digits, 30))) 232 | r = self._request.post( 233 | url, headers={'Cookie': tts_cookie}, timeout=10, verify=False) 234 | if json.loads(r.text)['message'] == 'Success': 235 | return True 236 | elif json.loads(r.text)['error'] == 'ubus error': 237 | _LOGGER.error(json.loads(r.text)) 238 | elif json.loads(r.text)['error'] == 'Unauthorized': 239 | _LOGGER.error(json.loads(r.text)) 240 | self.login_resutl = False 241 | return False 242 | else: 243 | _LOGGER.error(json.loads(r.text)) 244 | # self.login_resutl = False 245 | return True 246 | except IndexError as e: 247 | _LOGGER.error('你没有那个音箱!') 248 | except AttributeError as e: 249 | _LOGGER.warning(e) 250 | except BaseException as e: 251 | _LOGGER.warning(e) 252 | return True 253 | 254 | def player_set_volume(self, volume, tts_cookie, deviceIds_miai, num=0): 255 | if volume > 100: 256 | volume = 100 257 | elif volume < 0: 258 | volume = 0 259 | try: 260 | url = "https://api.mina.mi.com/remote/ubus?deviceId={}&message=%7b%22volume%22%3a{}%2c%22media%22%3a%22app_ios%22%7d&method=player_set_volume&path=mediaplayer&requestId={}".format( 261 | self.deviceIds_miai[num]['deviceID'], int(volume), ''.join(random.sample(string.ascii_letters + string.digits, 30))) 262 | r = self._request.post( 263 | url, headers={'Cookie': tts_cookie}, timeout=10, verify=False) 264 | if json.loads(r.text)['message'] == 'Success': 265 | return True 266 | elif json.loads(r.text)['error'] == 'ubus error': 267 | _LOGGER.error(json.loads(r.text)) 268 | elif json.loads(r.text)['error'] == 'Unauthorized': 269 | _LOGGER.error(json.loads(r.text)) 270 | self.login_resutl = False 271 | return False 272 | else: 273 | return False 274 | except IndexError as e: 275 | _LOGGER.error('你没有那个音箱!') 276 | return True 277 | except AttributeError as e: 278 | _LOGGER.warning(e) 279 | except BaseException as e: 280 | _LOGGER.warning(e) 281 | return True 282 | 283 | def player_play_operation(self, operation, tts_cookie, deviceIds_miai, num=0): 284 | 285 | try: 286 | url = "https://api.mina.mi.com/remote/ubus?deviceId={}&message=%7b%22action%22%3a%22{}%22%2c%22media%22%3a%22app_ios%22%7d&method=player_play_operation&path=mediaplayer&requestId={}".format( 287 | self.deviceIds_miai[num]['deviceID'], operation, ''.join(random.sample(string.ascii_letters + string.digits, 30))) 288 | r = self._request.post( 289 | url, headers={'Cookie': tts_cookie}, timeout=10, verify=False) 290 | if json.loads(r.text)['message'] == 'Success': 291 | return True 292 | elif json.loads(r.text)['error'] == 'ubus error': 293 | _LOGGER.error(json.loads(r.text)) 294 | elif json.loads(r.text)['error'] == 'Unauthorized': 295 | _LOGGER.error(json.loads(r.text)) 296 | self.login_resutl = False 297 | return False 298 | else: 299 | return False 300 | except IndexError as e: 301 | _LOGGER.error('你没有那个音箱!') 302 | except AttributeError as e: 303 | _LOGGER.warning(e) 304 | except BaseException as e: 305 | _LOGGER.warning(e) 306 | return True 307 | 308 | 309 | CONF_USER = 'miid' 310 | CONF_PASSWORD = 'password' 311 | 312 | CONF_TO_NUM = 'miai_num' 313 | WAIT_TIME = 'wait_time' 314 | ATTR_MESSAGE = 'message' 315 | ATTR_VOLUME = 'vol' 316 | 317 | DEFAULT_MIAI_NUM = '0' 318 | DEFAULT_MIAI_SPEED = 0.27 319 | DEFAULT_WAIT_TIME = 0 320 | 321 | DOMAIN = 'hello_miai' 322 | 323 | SERVICE_SCHEMA = vol.Schema({ 324 | vol.Required(ATTR_MESSAGE): cv.string, 325 | vol.Optional(CONF_TO_NUM): cv.string, 326 | }) 327 | 328 | SERVICE_SCHEMA_FOR_QUEUE = vol.Schema({ 329 | vol.Required(ATTR_MESSAGE): cv.string, 330 | vol.Optional(CONF_TO_NUM): cv.string, 331 | vol.Optional(WAIT_TIME): cv.string, 332 | }) 333 | 334 | SERVICE_SCHEMA_FOR_SET_VOLUME = vol.Schema({ 335 | vol.Required(ATTR_VOLUME): cv.string, 336 | vol.Optional(CONF_TO_NUM): cv.string, 337 | }) 338 | 339 | SERVICE_SCHEMA_FOR_PLAY_OPERATION = vol.Schema({ 340 | vol.Optional(CONF_TO_NUM): cv.string, 341 | }) 342 | 343 | 344 | CONFIG_SCHEMA = vol.Schema({ 345 | DOMAIN: vol.Schema({ 346 | vol.Required(CONF_USER): cv.string, 347 | vol.Required(CONF_PASSWORD): cv.string, 348 | }), 349 | }, extra=vol.ALLOW_EXTRA) 350 | 351 | 352 | def setup(hass, config): 353 | conf = config.get(DOMAIN, {}) 354 | miid = conf.get(CONF_USER) 355 | password = conf.get(CONF_PASSWORD) 356 | client = xiaomi_tts(hass, config, miid, password) 357 | msg_queue = [] 358 | 359 | def listen_to_msg(): 360 | while not Event().isSet(): 361 | if client.Login_resutl: 362 | if len(msg_queue) > 0: 363 | send_finish = client._text_to_speech(msg_queue[0]['msg'], client.Service_Token_Cookie, 364 | client.deviceIds_miai, int(msg_queue[0]['to_num'])) 365 | if send_finish == True: 366 | try: 367 | time.sleep( 368 | len(msg_queue[0]['msg'])*DEFAULT_MIAI_SPEED+int(msg_queue[0]['wait_time'])) 369 | except: 370 | time.sleep( 371 | len(msg_queue[0]['msg'])*DEFAULT_MIAI_SPEED) 372 | msg_queue.pop(0) 373 | 374 | else: 375 | client._LoginByPassord() 376 | time.sleep(1) 377 | else: 378 | time.sleep(1) 379 | else: 380 | time.sleep(1) 381 | 382 | def send_message(call): 383 | msg_queue = [] 384 | to_num = call.data.get(CONF_TO_NUM, DEFAULT_MIAI_NUM) 385 | message = call.data.get(ATTR_MESSAGE) 386 | 387 | if client.Service_Token_Cookie == None or client.deviceIds_miai == None: 388 | _LOGGER.error("还未登录") 389 | else: 390 | if not client._text_to_speech(message, client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)): 391 | client._LoginByPassord() 392 | client._text_to_speech( 393 | message, client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)) 394 | 395 | def add_msg2queue(call): 396 | to_num = call.data.get(CONF_TO_NUM, DEFAULT_MIAI_NUM) 397 | wait_time = call.data.get(WAIT_TIME, DEFAULT_WAIT_TIME) 398 | message = call.data.get(ATTR_MESSAGE) 399 | if client.Service_Token_Cookie == None or client.deviceIds_miai == None: 400 | _LOGGER.error("还未登录") 401 | else: 402 | to_num = call.data.get(CONF_TO_NUM, DEFAULT_MIAI_NUM) 403 | message = call.data.get(ATTR_MESSAGE) 404 | msg_queue.append( 405 | {'msg': message, 'to_num': to_num, 'wait_time': wait_time}) 406 | 407 | def player_set_volume(call): 408 | 409 | to_num = call.data.get(CONF_TO_NUM, DEFAULT_MIAI_NUM) 410 | vol = call.data.get(ATTR_VOLUME) 411 | 412 | if client.Service_Token_Cookie == None or client.deviceIds_miai == None: 413 | _LOGGER.error("还未登录") 414 | else: 415 | if not client.player_set_volume(int(vol), client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)): 416 | client._LoginByPassord() 417 | client.player_set_volume( 418 | int(vol), client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)) 419 | 420 | def play_operation(call): 421 | 422 | to_num = call.data.get(CONF_TO_NUM, DEFAULT_MIAI_NUM) 423 | 424 | if client.Service_Token_Cookie == None or client.deviceIds_miai == None: 425 | _LOGGER.error("还未登录") 426 | else: 427 | if not client.player_play_operation('play', client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)): 428 | client._LoginByPassord() 429 | client.player_play_operation( 430 | 'play', client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)) 431 | 432 | def pause_operation(call): 433 | 434 | to_num = call.data.get(CONF_TO_NUM, DEFAULT_MIAI_NUM) 435 | 436 | if client.Service_Token_Cookie == None or client.deviceIds_miai == None: 437 | _LOGGER.error("还未登录") 438 | else: 439 | if not client.player_play_operation('pause', client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)): 440 | client._LoginByPassord() 441 | client.player_play_operation( 442 | 'pause', client.Service_Token_Cookie, client.deviceIds_miai, int(to_num)) 443 | 444 | def listen(): 445 | """Start listening.""" 446 | thread = Thread(target=listen_to_msg, args=()) 447 | thread.daemon = True 448 | thread.start() 449 | 450 | listen() 451 | 452 | def _stop_listener(_event): 453 | Event.set() 454 | 455 | hass.bus.listen_once( 456 | "homeassistant_stop", 457 | _stop_listener 458 | ) 459 | 460 | hass.services.register(DOMAIN, 'force_send', send_message, 461 | schema=SERVICE_SCHEMA) 462 | hass.services.register(DOMAIN, 'add2MsgQueue', add_msg2queue, 463 | schema=SERVICE_SCHEMA_FOR_QUEUE) 464 | hass.services.register(DOMAIN, 'set_vol', player_set_volume, 465 | schema=SERVICE_SCHEMA_FOR_SET_VOLUME) 466 | hass.services.register(DOMAIN, 'play', play_operation, 467 | schema=SERVICE_SCHEMA_FOR_PLAY_OPERATION) 468 | hass.services.register(DOMAIN, 'pause', pause_operation, 469 | schema=SERVICE_SCHEMA_FOR_PLAY_OPERATION) 470 | 471 | return True 472 | -------------------------------------------------------------------------------- /custom_components/hello_miai/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5high/mi_tts/7cdbcf39174d36102bb488f8c3a30bcd97a746c0/custom_components/hello_miai/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /custom_components/hello_miai/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "hello_miai", 3 | "name": "小米网络tts", 4 | "documentation": "https://github.com/5high/mi_tts", 5 | "dependencies": [], 6 | "codeowners": [], 7 | "requirements": [], 8 | "version": "1.0.0" 9 | } 10 | -------------------------------------------------------------------------------- /custom_components/hello_miai/services.yaml: -------------------------------------------------------------------------------- 1 | force_send: 2 | description: 小爱音箱直接播放.{"message":"hello","miai_num":"0"} 3 | fields: 4 | miai_num: 5 | description: 指定播放声音的音箱,从0开始(可选参数,默认为0). 6 | example: '0' 7 | message: 8 | description: TTS播放的文本内容. 9 | example: '你好天睿tera,我不是小爱。' 10 | set_vol: 11 | description: 小爱音箱音量调节0-100.{"vol":50} 12 | fields: 13 | miai_num: 14 | description: 指定调节音量的音箱,从0开始(可选参数,默认为0). 15 | example: '0' 16 | vol: 17 | description: 指定音量. 18 | example: '50' 19 | play: 20 | description: 小爱音箱播放. 21 | fields: 22 | miai_num: 23 | description: 指定播放的音箱,从0开始(可选参数,默认为0). 24 | example: '0' 25 | pause: 26 | description: 小爱音箱暂停. 27 | fields: 28 | miai_num: 29 | description: 指定暂停的音箱,从0开始(可选参数,默认为0). 30 | example: '0' 31 | add2msgqueue: 32 | description: 小爱音箱队列播放.{"message":"hello","miai_num":"0","wait_time":"3"} 33 | fields: 34 | wait_time: 35 | description: 指定该语句播报完毕之后的等待时间,单位为秒(可选参数,默认为0). 36 | example: '0' 37 | miai_num: 38 | description: 指定播放声音的音箱,从0开始(可选参数,默认为0). 39 | example: '0' 40 | message: 41 | description: TTS播放的文本内容. 42 | example: '你好天睿tera,我不是小爱。' 43 | -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_miai", 3 | "country": "CN", 4 | "render_readme": false, 5 | "domains": ["tts"] 6 | } 7 | -------------------------------------------------------------------------------- /info.md: -------------------------------------------------------------------------------- 1 | 2 | # 本人不是作者,再此处放置是为了HACS安装方便,在此感谢作者。 3 | 配置例子,填写绑定小爱音箱的用户账号信息: 4 | 5 | ``` 6 | hello_miai: 7 | miid: '13123456789' 8 | password: 'password' 9 | ``` 10 | 11 | 调用服务,如果你有多个音箱,miai_num代表你的音箱id。 12 | ``` 13 | wait_time: 0 14 | miai_num: 0 15 | message: 你好天睿tera,我不是小爱。 16 | ``` 17 | 18 | 更多教程 :https://sumju.net 19 | 电报 群 :https://t.me/joinchat/J26zVFGMhWWB1sBTFvcjaA 20 | 电报频道 :https://t.me/itcommander 21 | Twitter :https://twitter.com/itcommander2 22 | Facebook. :https://www.facebook.com/itcommander.itcommander.1 23 | 24 | --------------------------------------------------------------------------------