如何利用米家实现回家靠近自动打开空调等

举报
Rolle 发表于 2024/07/30 19:50:36 2024/07/30
【摘要】 夏天到了、每次从炎热的室外到达室内的时候,比如下个班骑车回家,又或者跟朋友出去玩,然后再回到家。都会觉得很热,第一件事,那肯定是想打开空调。自动打开空调的必要性如何打开空调 ? 我能想到的有以下几种方式刚到家,呼叫 小爱同学 打开空调优点:不浪费一点电 ?缺点:燥热的天气恨不得立马凉快下来。所以我通常都是直接先开17度,然后等感觉到冷了再慢慢调上去在即将快到家得时候,在米家上手动操作空调,远...

夏天到了、每次从炎热的室外到达室内的时候,比如下个班骑车回家,又或者跟朋友出去玩,然后再回到家。都会觉得很热,第一件事,那肯定是想打开空调。

自动打开空调的必要性

如何打开空调 ? 我能想到的有以下几种方式

  1. 刚到家,呼叫 小爱同学 打开空调
    1. 优点:不浪费一点电 ?
    2. 缺点:燥热的天气恨不得立马凉快下来。所以我通常都是直接先开17度,然后等感觉到冷了再慢慢调上去
  2. 在即将快到家得时候,在米家上手动操作空调,远程打开
    1. 优点: 想不到有什么优点
    2. 缺点: 几乎不能想起,对,是几乎

除了以上这2种方式还有其他的方式吗?

利用实时距离探测来实现对空调的打开

我想是有的。如何在后台自动的检测到我离家比如400米的时候,就提前打开空调。这样也就根本不用担心是否忘记在手机上操作,或者是等到家了才想起立马开空调了

首先要解决多个设备之间的传感互通问题。

针对米家。基本上也有这3种方式

  1. 语音操控,这种得在家控制
  2. App操作,这种起码也得在后台操作
  3. api操作,这不就是工程师打开的方式了
首先利用苹果的快捷指令

自动化–>新建–>到达–>位置–>选取想要选取的位置(比如 西二旗地铁站)–>当前日期–>后置到iCloud的文件夹里面–保存在比如a.txt文件里

在当前位置这里可以选择精度

这样就完成了第一步,位置上报了。

第二步 米家api接入

登录 先利用账号密码登录

代码语言:javascript
复制
import requests
import json
from hashlib import md5
import random


def login(sid: str, user: str, pwd: str) -> dict:
    msgUrl = "https://account.xiaomi.com/pass/serviceLogin?sid=" + sid + "&_json=true"
    loginUrl = "https://account.xiaomi.com/pass/serviceLoginAuth2"
    tempStr = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    deviceId = ''
    for i in range(16):
        deviceId += tempStr[random.randint(0, len(tempStr) - 1)]
    authorize = {}
    userAgent = 'APP/com.xiaomi.mihome APPV/6.0.103 iosPassportSDK/3.9.0 iOS/14.4 miHSTS'
    request = requests.session()
    request.cookies = requests.cookies.RequestsCookieJar()
    request.headers['User-Agent'] = userAgent
    request.headers['Accept'] = '*/*'
    request.headers['Accept-Language'] = 'zh-tw'
    request.headers['Cookie'] = 'deviceId=' + deviceId + '; sdkVersion=3.4.1'
    msg = request.get(msgUrl)
    result = json.loads(msg.text[11:])
    body = {}
    body['qs'] = result['qs']
    body['sid'] = result['sid']
    body['_sign'] = result['_sign']
    body['callback'] = result['callback']
    body['user'] = user
    pwd = md5(pwd.encode()).hexdigest().upper()
    pwd += '0' * (32 - len(pwd))
    body['hash'] = pwd
    body['_json'] = 'true'
    msg = request.post(loginUrl, data=body)
    result = json.loads(msg.text[11:])
    if result['code'] != 0:
        authorize['code'] = result['code']
        authorize['message'] = result['desc']
        return authorize
    msg = request.get(result['location'])
    for item in msg.headers['Set-Cookie'].split(', '):
        item = item.split('; ')[0]
        item = item.split('=', maxsplit=1)
        authorize[item[0]] = item[1]
    authorize['code'] = 0
    authorize['sid'] = sid
    authorize['userId'] = result['userId']
    authorize['securityToken'] = result['ssecurity']
    authorize['deviceId'] = deviceId
    authorize['message'] = '成功'
    return authorize


def read_mem(src):
    F = open(src, 'r', encoding='utf-8')
    content = F.read()
    F.close()
    return json.loads(content)


def login_config():
    config = read_mem('config.json')
    config_user = config['user']
    config_pwd = config['password']
    authorize = login("xiaomiio", config_user, config_pwd)
    print(authorize['message'])
    if authorize['code'] == 0:
        with open("./json/authorize.json", "w", encoding='utf-8') as f:
            f.write(json.dumps(authorize, indent=4, ensure_ascii=False))


if __name__ == '__main__':
    config = read_mem('config.json')
    config_user = config['user']
    config_pwd = config['password']
    authorize = login("xiaomiio", config_user, config_pwd)
    print(authorize['message'])
    if authorize['code'] == 0:
        with open("./json/authorize.json", "w", encoding='utf-8') as f:
            f.write(json.dumps(authorize, indent=4, ensure_ascii=False))

然后获取其设备列表

代码语言:javascript
复制
def post_data(uri: str, data: dict, authorize: dict) -> None:
    data = str(data).replace("'", '"').replace('True', 'true').replace('False', 'false')
    try:
        serviceToken = authorize['serviceToken']
        securityToken = authorize['securityToken']
    except KeyError:
        print('serviceToken not found, Unauthorized')
        return
    tempStr = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    nonce = ''
    for i in range(16):
        nonce += tempStr[random.randint(0, len(tempStr) - 1)]
    signedNonce = generateSignedNonce(securityToken, nonce)
    signature = generateSignature(uri, signedNonce, nonce, data)
    body = {'_nonce': nonce, 'data': data, 'signature': signature}
    userAgent = 'APP/com.xiaomi.mihome APPV/6.0.103 iosPassportSDK/3.9.0 iOS/14.4 miHSTS'
    request = requests.session()
    request.cookies = requests.cookies.RequestsCookieJar()
    request.headers['User-Agent'] = userAgent
    request.headers['x-xiaomi-protocal-flag-cli'] = 'PROTOCAL-HTTP2'
    request.headers['Cookie'] = 'PassportDeviceId=' + authorize['deviceId'] + ';userId=' + str(
        authorize['userId']) + ';serviceToken=' + serviceToken + ';'
    msg = request.post('https://api.io.mi.com/app' + uri, data=body)
    return msg.text


def get_devices(save: bool) -> dict:
    """
    获取设备列表
    :param save:
    :return:
    """
    authorize = json.load(open('./json/authorize.json', 'r', encoding='utf-8'))
    data = {"getVirtualModel": False, "getHuamiDevices": 0}
    msg = post_data('/home/device_list', data, authorize)
    devs = json.loads(msg)
    if save:
        with open('./json/devices.json', 'w', encoding='utf-8') as f:
            f.write(json.dumps(devs, indent=4, ensure_ascii=False))
    return devs

在米家里有这样的一些自己添加的场景

然后获取场景代码

代码语言:javascript
复制
def get_scenes(save: bool, room_idx=0) -> dict:
    """
    获取场景列表
    :param save:
    :param roomIdx:
    :return:
    """
    authorize = json.load(open('./json/authorize.json', 'r', encoding='utf-8'))
    if os.path.exists('./json/rooms.json'):
        rooms = json.load(open('./json/rooms.json', 'r', encoding='utf-8'))
    else:
        rooms = get_rooms(save)
    try:
        homeId = rooms['result']['homelist'][room_idx]['id']
    except IndexError:
        print('房间号超出范围')
        return
    data = {"home_id": homeId}
    msg = post_data('/appgateway/miot/appsceneservice/AppSceneService/GetSceneList', data, authorize)
    scenes = json.loads(msg)
    if save:
        with open('./json/scenes.json', 'w', encoding='utf-8') as f:
            f.write(json.dumps(scenes, indent=4, ensure_ascii=False))
    return scenes

运行场景代码

代码语言:javascript
复制
def run_scene(name: str) -> int:
    """
    运行场景
    :param name:
    :return:
    """
    global scene_id
    authorize = json.load(open('./json/authorize.json', 'r', encoding='utf-8'))
    if os.path.exists('./json/scenes.json'):
        scenes = json.load(open('./json/scenes.json', 'r', encoding='utf-8'))
    else:
        scenes = get_scenes(True)

    scenesList = scenes['result']['scene_info_list']
    for scene in scenesList:
        if scene['name'] == name:
            scene_id = scene['scene_id']
            break
    try:
        data = {"scene_id": scene_id, "trigger_key": "user.click"}
    except NameError:
        print("场景名称不存在")
        return -1
    msg = post_data('/appgateway/miot/appsceneservice/AppSceneService/RunScene', data, authorize)
    msg = json.loads(msg)
    if msg['result']:
        return 0
    else:
        print(msg)
        return -1

完整代码

运行

这样就可以在自己家里的电脑上对其一些文件的监控操作api来完成这个事情了。

最终效果

当我在下班时间范围内的时候。如果我离家只有几百米了。而且判定一下当前的天气,如果适合开空调就自动打开空调了。

一些其他的思考

  • 对于一些没有编程基础的人群来说,有其他方式吗?
    • 我想是有的,同样去利用快捷指令,当满足xxx条件,然后就对其米家里的App进行一些指令的操作。不过这个点我是刚好写这点思考的时候才想到的
  • 除了米家api是否还有其他方式来完成操作对小爱同学的操作
    • 去探索了一下,GitHub上有这个开源的库也可以,地址,这样也能在云端进行操作,不过账号安全问题。大家记得对账号的密码保存好
  • 苹果的快捷指令,这玩意我之前是几乎不用的,今天这个位置这个事情,如果想对一些人行踪的掌握。或者揭露谎言的。那真是interesting。慎用!

工程师理应该学会利用现有工具,最大程度的偷懒

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。