关于小爱同学自定义指令执行

查看 42|回复 1
作者:wshuo   
1.前言
之前买了小爱同学音响,一直想让其让我的生活变得更智能,编写一些程序来完成一些自动化任务,但是经过搜索发现,官方开发者平台不能用了,寻找api阶段浪费了我很长时间。最后在github 开源项目发现了俩个比较关键的项目:
https://github.com/Yonsm/MiService
https://github.com/yihong0618/xiaogpt
其实关键点在于,我需要俩个接口:
[ol]
  • 我说了什么
  • 让音响答复我说了什么  
    [/ol]
    只需要这俩个接口
    2. 实现
    对于第一个接口我找了很久,最后在xiaogpt这个项目中找到了这个api 的实现,xiaogpt也是miservice 这个项目实现的。  
    这里我简单做了个demo,相信能帮助大家节约很长时间:
    #!/usr/bin/python3
    from miservice.miaccount   import   MiAccount
    from miservice.minaservice import   MiNAService
    from aiohttp import ClientSession
    from requests.utils import cookiejar_from_dict
    import time
    import os
    import json
    import asyncio
    COMMAND = {
    "打开主机":["wakeonlan xx:xx:xx:xx:xx:xx","已开启主机"],
    "关闭主机":["ssh -o ConnectTimeout=1 [email protected] shutdown -h now","已关闭主机"],
    "打开桌面":["/root/tools/switch/switch.py on","已打开桌面电脑"],
    "关闭桌面":["ssh -o ConnectTimeout=1 [email protected] shutdown -h now; sleep 30; /root/tools/switch/switch.py off","已关闭桌面电脑"]
    }
    async def main():
        user_id = "小米账号"
        password = "密码"
        hardware = "LX06" # 音响型号
        polling_event = asyncio.Event()
        misession = ClientSession()
        account = MiAccount(misession, user_id,password,"mi.token")
        await account.login("micoapi")
        service = MiNAService(account)
        device_list = await service.device_list()
        deviceID = device_list[0]['deviceID']
        LATEST_ASK_API=  "https://userprofile.mina.mi.com/device_profile/v2/conversation?source=dialogu&hardware={hardware}×tamp={timestamp}&limit=1"
        async with ClientSession() as session:
            cookies = dict(
                deviceId=deviceID,
            )
            misession.cookie_jar.update_cookies(cookiejar_from_dict(cookies))
            session._cookie_jar = misession.cookie_jar
            # print(session._cookie_jar._cookies)
            while True:
                try:
                    r = await session.get(LATEST_ASK_API.format(hardware=hardware, timestamp=str(int(time.time()* 1000))))
                    data = await r.json()
                    query = json.loads(data["data"])['records'][0]['query']
                    qtime = int(json.loads(data["data"])['records'][0]['time']/1000)
                    # print(qtime,int(time.time()))
                    if abs(qtime - int(time.time()))
    要使用上述代码,首先要满足几个条件:
    [ol]
  • python支持异步(忘记是几点几版本开始支持了)
  • 安装miservice
    pip install miservice
    [/ol]
    其他把账号、密码、音响型号 配置进去 就可以在COMMAND 字典中自定义shell 命令了
    这里简单介绍一些 COMMAND 字典,键 为语控命令,值 为一个列表,列表中第一个值 为 要执行的shell 命令,第二个值 为 音响答复。  
    后面要增加命令可以直接修改 COMMAND字典。这里可以看到我对俩个电脑开关机进行控制:
    对于桌面电脑,我是先 执行shutdown -h now,  等待30s后,再对电源进行关闭操作(switch为我写的控制电源的一个脚本),因为我总觉得直接下电对 电脑不好。  
    对于主机电脑,我直接使用 网络唤醒实现的开机(连接网线),对于桌面电脑由于我没有网线接口了,所有用上电自动开机实现的开机控制。  
    3.其他一些细节
    3.1 让小爱知道这个指令
    由于自定义的一些指令,直接问小爱,小爱会回答不知道这个指令,那么我们可以在 小爱训练中加入这些自定义指令:  


    photo_2024-07-07_03-01-50.jpg (50.33 KB, 下载次数: 0)
    下载附件
    2024-7-7 03:01 上传

    这里小爱,会先回答“好的”, 然后我们api响应的话语会打断说话,紧接着说“已开启主机”  
    3.2 回答内容为自定义查询的内容
    在COMMAND 里,我们可以用这种方式进行定义列表中的第二个字段:  
    f"查询的信息是 {data}"
    可以注意到,这里我执行shell, 使用 os.popen 来执行的(非阻塞),一方面也是为了可以读取返回内容,然后给与相应的赋值
    data 直接赋值为 os.popen 返回的read() 即可
    当然os.popen不是一种良好的执行 命令的方式,有更官方的写法,懒得优化了。  
    4.效果展示
    https://7.z.wiki/autoupload/20240707/Yfx4/1.mp4
    终于可以在床上控制电脑开关机了

    自定义, 小爱

  • jslyj   

    厉害啊 谢谢
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部