一.背景:

家人关电视时,经常误操作成熄屏,为了省电,需要统计电视的耗电情况,如果电视不在工作状态或其它条件,则断电

二.购买带用电统计的智能插座:

小米米家智能插座2 蓝牙网关版 APP远程控制 定时开关 过载保护 米家智能插座2 蓝牙网关版 白色【图片 价格 品牌 评论】-京东

三.注册小米帐号 ( https://account.xiaomi.com/ ):

四.安装“米家”App

安装"米家"app --> 用上一步注册的帐号登录 --> 添加设备 --> 验证是否正常 --> 通过App查看设备IP

五.获取设备Token:

GitHub - PiotrMachowski/Xiaomi-cloud-tokens-extractor: This tool/script retrieves tokens for all devices connected to Xiaomi cloud and encryption keys for BLE devices.

import base64
import hashlib
import hmac
import json
import os
import random
import time
from sys import platform
from Crypto.Cipher import ARC4import requestsif platform != "win32":import readlineclass XiaomiCloudConnector:def __init__(self, username, password):self._username = usernameself._password = passwordself._agent = self.generate_agent()self._device_id = self.generate_device_id()self._session = requests.session()self._sign = Noneself._ssecurity = Noneself._userId = Noneself._cUserId = Noneself._passToken = Noneself._location = Noneself._code = Noneself._serviceToken = Nonedef login_step_1(self):url = "https://account.xiaomi.com/pass/serviceLogin?sid=xiaomiio&_json=true"headers = {"User-Agent": self._agent,"Content-Type": "application/x-www-form-urlencoded"}cookies = {"userId": self._username}response = self._session.get(url, headers=headers, cookies=cookies)valid = response.status_code == 200 and "_sign" in self.to_json(response.text)if valid:self._sign = self.to_json(response.text)["_sign"]return validdef login_step_2(self):url = "https://account.xiaomi.com/pass/serviceLoginAuth2"headers = {"User-Agent": self._agent,"Content-Type": "application/x-www-form-urlencoded"}fields = {"sid": "xiaomiio","hash": hashlib.md5(str.encode(self._password)).hexdigest().upper(),"callback": "https://sts.api.io.mi.com/sts","qs": "%3Fsid%3Dxiaomiio%26_json%3Dtrue","user": self._username,"_sign": self._sign,"_json": "true"}response = self._session.post(url, headers=headers, params=fields)valid = response is not None and response.status_code == 200if valid:json_resp = self.to_json(response.text)valid = "ssecurity" in json_resp and len(str(json_resp["ssecurity"])) > 4if valid:self._ssecurity = json_resp["ssecurity"]self._userId = json_resp["userId"]self._cUserId = json_resp["cUserId"]self._passToken = json_resp["passToken"]self._location = json_resp["location"]self._code = json_resp["code"]else:if "notificationUrl" in json_resp:print("Two factor authentication required, please use following url and restart extractor:")print(json_resp["notificationUrl"])print()return validdef login_step_3(self):headers = {"User-Agent": self._agent,"Content-Type": "application/x-www-form-urlencoded"}response = self._session.get(self._location, headers=headers)if response.status_code == 200:self._serviceToken = response.cookies.get("serviceToken")return response.status_code == 200def login(self):self._session.cookies.set("sdkVersion", "accountsdk-18.8.15", domain="mi.com")self._session.cookies.set("sdkVersion", "accountsdk-18.8.15", domain="xiaomi.com")self._session.cookies.set("deviceId", self._device_id, domain="mi.com")self._session.cookies.set("deviceId", self._device_id, domain="xiaomi.com")if self.login_step_1():if self.login_step_2():if self.login_step_3():return Trueelse:print("Unable to get service token.")else:print("Invalid login or password.")else:print("Invalid username.")return Falsedef get_devices(self, country):url = self.get_api_url(country) + "/home/device_list"params = {"data": '{"getVirtualModel":true,"getHuamiDevices":1,"get_split_device":false,"support_smart_home":true}'}return self.execute_api_call_encrypted(url, params)def get_beaconkey(self, country, did):url = self.get_api_url(country) + "/v2/device/blt_get_beaconkey"params = {"data": '{"did":"' + did + '","pdid":1}'}return self.execute_api_call_encrypted(url, params)def execute_api_call_encrypted(self, url, params):headers = {"Accept-Encoding": "identity","User-Agent": self._agent,"Content-Type": "application/x-www-form-urlencoded","x-xiaomi-protocal-flag-cli": "PROTOCAL-HTTP2","MIOT-ENCRYPT-ALGORITHM": "ENCRYPT-RC4",}cookies = {"userId": str(self._userId),"yetAnotherServiceToken": str(self._serviceToken),"serviceToken": str(self._serviceToken),"locale": "en_GB","timezone": "GMT+02:00","is_daylight": "1","dst_offset": "3600000","channel": "MI_APP_STORE"}millis = round(time.time() * 1000)nonce = self.generate_nonce(millis)signed_nonce = self.signed_nonce(nonce)fields = self.generate_enc_params(url, "POST", signed_nonce, nonce, params, self._ssecurity)response = self._session.post(url, headers=headers, cookies=cookies, params=fields)if response.status_code == 200:decoded = self.decrypt_rc4(self.signed_nonce(fields["_nonce"]), response.text)return json.loads(decoded)return Nonedef get_api_url(self, country):return "https://" + ("" if country == "cn" else (country + ".")) + "api.io.mi.com/app"def signed_nonce(self, nonce):hash_object = hashlib.sha256(base64.b64decode(self._ssecurity) + base64.b64decode(nonce))return base64.b64encode(hash_object.digest()).decode('utf-8')@staticmethoddef generate_nonce(millis):nonce_bytes = os.urandom(8) + (int(millis / 60000)).to_bytes(4, byteorder='big')return base64.b64encode(nonce_bytes).decode()@staticmethoddef generate_agent():agent_id = "".join(map(lambda i: chr(i), [random.randint(65, 69) for _ in range(13)]))return f"Android-7.1.1-1.0.0-ONEPLUS A3010-136-{agent_id} APP/xiaomi.smarthome APPV/62830"@staticmethoddef generate_device_id():return "".join(map(lambda i: chr(i), [random.randint(97, 122) for _ in range(6)]))@staticmethoddef generate_signature(url, signed_nonce, nonce, params):signature_params = [url.split("com")[1], signed_nonce, nonce]for k, v in params.items():signature_params.append(f"{k}={v}")signature_string = "&".join(signature_params)signature = hmac.new(base64.b64decode(signed_nonce), msg=signature_string.encode(), digestmod=hashlib.sha256)return base64.b64encode(signature.digest()).decode()@staticmethoddef generate_enc_signature(url, method, signed_nonce, params):signature_params = [str(method).upper(), url.split("com")[1].replace("/app/", "/")]for k, v in params.items():signature_params.append(f"{k}={v}")signature_params.append(signed_nonce)signature_string = "&".join(signature_params)return base64.b64encode(hashlib.sha1(signature_string.encode('utf-8')).digest()).decode()@staticmethoddef generate_enc_params(url, method, signed_nonce, nonce, params, ssecurity):params['rc4_hash__'] = XiaomiCloudConnector.generate_enc_signature(url, method, signed_nonce, params)for k, v in params.items():params[k] = XiaomiCloudConnector.encrypt_rc4(signed_nonce, v)params.update({'signature': XiaomiCloudConnector.generate_enc_signature(url, method, signed_nonce, params),'ssecurity': ssecurity,'_nonce': nonce,})return params@staticmethoddef to_json(response_text):return json.loads(response_text.replace("&&&START&&&", ""))@staticmethoddef encrypt_rc4(password, payload):r = ARC4.new(base64.b64decode(password))r.encrypt(bytes(1024))return base64.b64encode(r.encrypt(payload.encode())).decode()@staticmethoddef decrypt_rc4(password, payload):r = ARC4.new(base64.b64decode(password))r.encrypt(bytes(1024))return r.encrypt(base64.b64decode(payload))def print_tabbed(value, tab):print(" " * tab + value)def print_entry(key, value, tab):if value:print_tabbed(f'{key + ":": <10}{value}', tab)username = "小米ID"
password ="用户密码"
servers = ["cn"]connector = XiaomiCloudConnector(username, password)
print("Logging in...")
logged = connector.login()
if logged:print("Logged in.")print()for current_server in servers:devices = connector.get_devices(current_server)if devices is not None:if len(devices["result"]["list"]) == 0:print(f"No devices found for server \"{current_server}\".")continueprint(f"Devices found for server \"{current_server}\":")for device in devices["result"]["list"]:print_tabbed("---------", 3)if "name" in device:print_entry("NAME", device["name"], 3)if "did" in device:print_entry("ID", device["did"], 3)if "blt" in device["did"]:beaconkey = connector.get_beaconkey(current_server, device["did"])if beaconkey and "result" in beaconkey and "beaconkey" in beaconkey["result"]:print_entry("BLE KEY", beaconkey["result"]["beaconkey"], 3)if "mac" in device:print_entry("MAC", device["mac"], 3)if "localip" in device:print_entry("IP", device["localip"], 3)if "token" in device:print_entry("TOKEN", device["token"], 3)if "model" in device:print_entry("MODEL", device["model"], 3)print_tabbed("---------", 3)print()else:print(f"Unable to get devices from server {current_server}.")
else:print("Unable to log in.")

运行以上脚本,获得以下输出(Token,Model):

六.安装python-miio:

pip install python-miio

七.获取设备能力( 小米/米家产品库 - Xiaomi Miot Spec ):

输入上面获取的MODEL 点击查询

测试代码:

import miio
import timeip='192.168.1.100'
token='...................................' s = miio.device.Device(ip=ip, token=token)#设置为关闭状态:
ret=s.raw_command('set_properties' ,[{'did': 'Switch', 'siid': 2, 'piid': 1, 'value':False}])
print(ret)#获取开关状态:
ret=s.raw_command('get_properties' ,[{'did': 'Switch', 'siid': 2, 'piid': 1}])
print(ret)#打开:
ret=s.raw_command('set_properties' ,[{'did': 'Switch', 'siid': 2, 'piid': 1, 'value':True}])
print(ret)#获取功耗
for _ in range(10):        ret=s.raw_command('get_properties' ,[{'did': 'power_consumption', 'piid':6, 'siid': 5}])watt=ret[0]['value']/100.0print("{}.W".format(watt))time.sleep(3)#关闭:
ret=s.raw_command('set_properties' ,[{'did': 'Switch', 'siid': 2, 'piid': 1, 'value':False}])
print(ret) 

运行以上代码,确认是否符合预期

八.在Rock3A上安装监控服务:

监控代码: vi /home/rock/mictrl.py:

import miio
import timeip='192.168.1.100'
token='xxxxxxxxxxxxxxxxxxxxxxxxx' def set_switch_status(value):s = miio.device.Device(ip=ip, token=token)ret=s.raw_command('set_properties' ,[{'did': 'Switch', 'siid': 2, 'piid': 1, 'value':value}])print("set_switch_status:",ret)def get_power_consumption():s = miio.device.Device(ip=ip, token=token)ret=s.raw_command('get_properties' ,[{'did': 'power_consumption', 'piid': int(6), 'siid': 5}])return ret[0]['value']/100.0err=0
while True:p=get_power_consumption()print(p)if p<20:err+=1else:err=0if err>3 and p>0:set_switch_status(False)time.sleep(10)

安装开机服务:

cat <<EOF | sudo tee /etc/systemd/system/mictrl.service
[Unit]
Description=mictrl.service[Service]
Type=simple
ExecStart=python3 /home/rock/mictrl.py
Restart=always
RestartSec=10[Install]
WantedBy=multi-user.target
EOFsystemctl enable mictrl
systemctl start mictrl
systemctl status mictrl

小米智能插座监控设备耗电,并自动断电相关推荐

  1. 小米智能插座、小米温湿度计2、涂鸦灯泡 接入Home Assistant

    有没有和HA直连的设备啊??????(未解决)? 云端接入 接入分为WIFI和蓝牙 云端接入:使用小米账号,存在延迟,断网不可用 本地接入:HA托管,延迟低,断网可用.蓝牙的本地接入可能还不需要网关 ...

  2. 小米智能插座采用Marvell EZ-Connect芯片解决方案--88MC200微控制器、Avastar 88W8801

    小米智能插座采用Marvell EZ-Connect芯片解决方案 Marvell EZ-Connect芯片解决方案包括88MC200微控制器.Avastar 88W8801 Wi-Fi SoC和EZ- ...

  3. 小米node2红外_使用python-miio控制小米智能插座

    0 设备信息 本次采用设备为小米智能插座基础版,购买链接为:天猫购买链接 产品型号:ZNCZ04CM 1 python-miio模块 米家的智能设备都遵循了 miio 的协议,协议内容参见:mihom ...

  4. 小米开源监控系统OpenFalcon应对高并发7种手段

    2019独角兽企业重金招聘Python工程师标准>>> 小米开源监控系统OpenFalcon应对高并发7种手段 原创 2016-04-01 秦晓辉 高可用架构 编者按:本文是秦晓辉在 ...

  5. 自动路由_小米路由器Mesh首销 多路由自动切换/为智能家居而生

    [CNMO新闻]在小米.米家推出的众多生态链产品中,小米路由器的销量非常大,但是口碑却不尽如人意,尤其是在连接小米智能家居设备时,稳定性很差,时常断连.不过,这种糟糕的用户体验在小米路由器Mesh推出 ...

  6. 计算机主板会自动切断电源是怎么回事,主机启动一秒又自动断电一直循环 就只擦内存条...

    导语:谈论到主机,大家都了解,有人问台式电脑主机点开机没反应,还有朋友想问主机自动断电反复重启显示屏不显示,这到底是咋回事?其实电脑开不了机,主机灯一直闪呢,下面是小编分享的主机启动一秒又自动断电一直 ...

  7. 小米开源监控open-falcon安装

    https://www.cnblogs.com/liangqihui/p/6618127.html 前言 近期爆出Zabbix有严重bug,加上一直对zabbix的性能.UI不满.所以这次想钻研一下最 ...

  8. 环境与设备监控计算机套定额,电气火灾监控设备调试、套定额的注意事项

    电气火灾监控设备调试.套定额的注意事项 1.关于电气火灾监控系统与火灾自动报警系统是否为同一系统 根据<火灾自动报警系统设计规范>GB50116-2013关于电气火灾监控系统设计相关规定, ...

  9. 温湿度监控设备遇到的常见问题

    1.温湿度监控设备用于食品.电子生产车间.药房.冰箱.冷库.仓库.机房.实验室.工业暖通空调.图书馆.档案室.博物馆.孵化器.温室.烟草.食品仓库.医院.蔬菜.水果.花卉农业温室.农场.机房.实验室. ...

最新文章

  1. Git之变基方式Rebase的使用
  2. kali Linux 火狐浏览器改中文
  3. 机器学习实战(python)-Ch02KNN-Notes
  4. 【转】Microsoft Azure存储服务:存储账户****
  5. go mod常用命令
  6. php like %%,thinkphp实现like模糊查询实例
  7. 怎么把 html做成雪花特效,CSS3 HTML5下雪特效 雪花飘飘
  8. 10.26 第二次面试小感
  9. 动态路由下的导航守卫--(to,from,next)
  10. SQL入门经典-思维导图
  11. 冰河木马简易使用 ——病毒木马 003
  12. html5手机的注册页面,H5页面结合vue实现登录注册组件
  13. 轻量化网络ShuffleNet MobileNet v1/v2 解析
  14. php 检测必填,使用PHP Filter函数进行验证,但忽略空的非必填字段
  15. Pr剪辑上分攻略---电子相册制作
  16. 数据结构算法-学习体系-持续更新
  17. 计算机无法读取配置文件,由于权限不足,无法读取配置文件
  18. oracle 朱志辉_甲骨文(Oracle)授权教育中心落户我校
  19. Codeforces 940E: Cashback 单调队列优化DP
  20. [导入]了解OGRE——起步常见问题

热门文章

  1. python怎么输出复数_python基础知识及应用(二)输入输出|递归|深浅拷贝|全局变量|复数...
  2. 消除“Unfortunately, System UI has stopped”的方法
  3. dingding告警
  4. 抖音电商主播运营技巧话术脚本策划方案带货流程计划表格
  5. mysql怎么给数据加序号_MySQL数据库之在mysql中给查询的结果添加序号列
  6. 用计算机写试卷反思,“我的试卷,我分析,我反思1——学生写试卷分析及反思的收获...
  7. openssl 的安装
  8. 如何拿到tabbarcontroller,如何拿到主导航控制器
  9. Python GUI之tkinter窗口视窗教程大集合
  10. 万字长文回顾智能驾驶进化史