本帖最后由 study321 于 2023-5-7 01:26 编辑
先上流程截图,部分功能还在完善优化,看回复热度选择发布 。 如果你有兴趣、有需要,请在帖子里留言让我看到
这里先记录下部分技术知识总结,动手能力强的可以进行研究与程序编写。
#1. KEY & IV 获取
由于没有多个设备试验,所以无法判断每个路由器的key 和 iv 是否一致。
这个 key 和 iv ,关系到后边的登录密码生成等。
获取地址:
GET 请求
http://192.168.31.1/cgi-bin/luci/web
复制代码
然后在HTML里搜索: key: 、 iv: 关键字即可看到
#2. 小米路由器的STOK获取
STOK是登录后返回的token ,这个token和当前设备登录的mac关联,所以为了后续能在node-red服务器上(我是用docker运行)进行接口请求,则需要使用node-red服务器的mac地址进行模拟登录。
登录POST地址:
http://192.168.31.1./cgi-bin/luci/api/xqsystem/login
复制代码
管理密码生成函数(供参考,对应的mac、key、iv参数上边获取 到):
// 小米路由器的加密函数
var Encrypt = {
key, iv,
nonce: null,
init: function () {
var nonce = this.nonceCreat();
this.nonce = nonce;
return this.nonce;
},
nonceCreat: function () {
var type = 0;
var deviceId = mac;
var time = Math.floor(new Date().getTime() / 1000);
var random = Math.floor(Math.random() * 10000);
return [type, deviceId, time, random].join('_');
},
oldPwd: function (pwd) {
return sha1(this.nonce + sha1(pwd + this.key).toString()).toString();
}
};
var pwd = flow.get("MI_ROUTE_PWD");
var nonce = Encrypt.init();
var oldPwd = Encrypt.oldPwd(pwd);
var param = {
username: 'admin',
password: oldPwd,
logtype: 2,
nonce: nonce
};
复制代码
其中的sha1加密 ,可自己进行。 我这里提供我是用的sha加密方法:
var createHash = crypto.createHash;
const encrypt = (algorithm, content) => {
let hash = createHash(algorithm)
hash.update(content)
return hash.digest('hex')
}
const sha1 = (content) => encrypt('sha1', content)
复制代码
然后构造POST请求数据包:
msg.url = `http://${flow.get("MI_ROUTE_IP")}/cgi-bin/luci/api/xqsystem/login`;
msg.payload = `username=admin&password=${oldPwd}&logtype=2&nonce=${nonce}`;
复制代码
返回的数据是json格式 ,code参数有两个:0和401,401是认证失败 ,0是获取成功 。 可通过这个判断数据
登录成功,会返回token数据,这个就是接下来我们请求其他API接口需要用到的STOK了!
# 3. 获取设备列表
msg.url = `http://${flow.get("MI_ROUTE_IP")}/cgi-bin/luci/;stok=${flow.get("MI_ROUTE_STOK")}/api/misystem/devicelist`
复制代码
#4. 联动操作
有了数据,就好办了。
我这里分享我的一个玩法:判断设备是否在线,来判断人是否在家。 从而联动其他场景。
判断设备是否在线方法参考:
// 这里有三个判断的选择:
// 1. MAC地址
// 2. 路由器中设备的显示名称
// 3. 设备的IP地址
// 请选择填写一个即可
var checkArg = {
mac: ',
name: '',
ip: '192.168.31.88'
}
// 检查是否在线
var checked = false;
msg.payload.list.map(device => {
if (checked) return;
if (checkArg.mac) {
checked = device['mac'] == checkArg.mac;
} else if (checkArg.ip) {
device.ip.map(ipp => {
if (checked) return;
checked = ipp['ip'] == checkArg.ip;
});
} else {
checked = device['name'] == checkArg.name;
}
});
msg.payload = checked ? 1 : 0;
return msg;
复制代码
暂时写到这。 流程我还在完善,后边看热度分享 。
有兴趣的朋友们,回帖让我看一看!
【2023-05-07】流程已分享: https://bbs.hassbian.com/forum.php?mod=viewthread&tid=20980