|
本帖最后由 linmohc 于 2023-12-15 16:08 编辑
以下API逆向得到,一边还要编写程序接入到ha,基本上是用到哪写到哪,还需要继续完善,精力有限可能有不准确的地方,但是大致可用,欢迎大家一起讨论。
1. HTTP请求登录
POST https://rubyuserapi.vanward.com/api/user/login application/x-www-form-urlencoded
code=&mobile=手机号&password=万和智能app密码明文
响应:
{"User":{"Uuid":"用户id需要保存后续用到","Token":"token需要保存后续用到","Mobile":"手机号","UnReadMsgCount":0},"Domain":["rubyusercomet.vanward.com"]}
2. 刷新TOKEN
第一步获得的token在连接ws后失效,下次再连接除了用第一步重新登录,还可以用这个接口获得新token
POST https://rubyuserapi.vanward.com/api/user/autoLogin application/x-www-form-urlencoded
uuid=用户id&token=旧token
响应与第一步相同
3. 连接websocket
用第一步中返回的Domain字段中随便一个域名,固定端口2301构成,如:wss://rubyusercomet.vanward.com:2301/ws
使用的是binaryframe
连接后需要马上发送认证消息
数据包由heaer+payload构成,其中header固定5字节,第一位为操作码,后4字段为大端int32,标识payload长度,如发送Hello,操作码为1,构数据包如下:
0x01, 0x05, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F
payload是一个json对象
已知操作码:
0x00: 登录,响应与请求相同,payload: {"Id": "用户UUid", "Token": "xxxx"}
0x0A: 心跳,响应与请求相同
WebSocket协议
登录请求,操作码: 0x00{"Id": "用户UUid", "Token": "xxx"}
登录响应,操作码: 0x00
{
"Code": 0,
"Devices": [
{
"ActiveDate": "设备激活日期?",
"Alias": "设备别名(在app中设置)",
"DeviceId": "设备id,需要记录保存",
"Mac": "设备mac地址",
"Master": "暂时不知道什么东西",
"Product": {
"CtrlPageUrl": "http://local/u2",
"FirmwareId": "固件id,估计没什么用",
"Icon": "https://smart-vanward.oss-cn-shenzhen.aliyuncs.com/vanwardsmart/1/JSLQ27-LS5W16/%E8%AE%BE%E5%A4%87%E5%9B%BE%E6%A0%871585561034123.png",
"Model": "JSLQ27-LS5W16", // 设备型号
"Name": "JSLQ27-LS5W16",
"Pid": "不清楚有什么用处",
"Script": {
"Content": "s[1] === 1 ? '已打开':'已关闭';",
"Showonoff": true
},
"Series": "LS5 系列号,这个要保存,后面需要用来判断功能",
"Type": "燃气热水器", // 设备类型,如果有多种类型设备需要用这个值进行判断
"catagoryId": 0,
"catagoryName": "燃气热水器"
},
"Status": [0,1,4,0,15,0,45,24,0,0,0,0,24,9,7,9,0,0,0,38,0,0,0,0,23,0,7,16,12,24,0,0,0,0,0,0], // 设备状态包括水温模式等,详见下面
"Version": "1.4.3", // 固件版本
"deviceType": 0, // 看起来像设备类型,但是官方并没有用这个值进行判断,反而用的是Product.Type
"firmwareId": "frt92421-1e3f-479e-a98b-aa5692da1599",
"isOnline": true, // 设备离线(如断开WiFi)这里为false
"serverId": "comet-CNS-01"
}
],
"Msg": "登录成功"
}
--------------------------------------------------------------------------------
心跳请求,操作码:0x0A
心跳只需要发header的5字节包出去即可,即固定
0x0A 0x00, 0x00, 0x00, 0x00, 0x00
连接空闲时每60秒要发送一次心跳,否则服务端会断开连接
心跳响应
无,服务器不发送响应
--------------------------------------------------------------------------------
设备心跳请求
无,不需要客户端发送,服务端会主动推送过来
设备心跳响应,操作码:0x23
{"Id":"设备id"}
--------------------------------------------------------------------------------
设备状态报告请求
无,不需要客户端发送,服务端会主动推送过来
设备状态报告响应,操作码:0x22
{"Id":"设备id", "Status": [0,1,4,0,15,0,45,24,0,0,0,0,24,9,7,9,0,0,0,38,0,0,0,0,23,0,7,16,12,24,0,0,0,0,0,0]}
--------------------------------------------------------------------------------
更新设备状态请求,操作码:0x04
{
"Status": [1, 4, 44, 0, 15, 0, 40, 0, 0, 0, 0, 0], // 写设备状态,与读状态序列不同注意甄别
"Id": "设备id",
"MsgId": 1, // 消息id,实际官方并没有实现此值增长,保持为1即可
"Timestamp": 1702620580, // 当前Unix时间戳
"Model": "JSLQ27-LS5W16", // 设备型号,从登录请求中获得
"Series": "LS5" // 设备系列,从登录请求中获得
}
更新设备状态请求
无
--------------------------------------------------------------------------------
读设备状态(这个是服务器端返回的Status字段)
(因为家里只有万和热水器,没有其他万和设备,所以下面的状态可能在其他类型设备上不通用,但是所有万和热水器都适用下面的状态
索引 | 说明 | 1 | 热水器通电状态:0待机/1正常通电 | 2 | 热水器模式,1普通/2厨房/4节能/5自适温/6自定义1/7自定义2/8自定义3/21温水浴 | 4 | 未知 | 5 | 未知 | 6 | 水温 | 8 | 加热状态,需要按位与运算判断,1加热中/2通水中/4散热风扇/8防冻功能 | 11 | 实时产水量,需要/10为L/min | 18 | 零冷水巡航模式设置,高地址第3位为水增压,高地址第5-8位为巡航模式 | 19 | 零冷水温度 | 20 | 未知 | 21 | 未知 | 23 | 手动零冷水巡航,0未运行/1运行中 | 25 | 未知 | 33 | 零冷水预约模式,0非预约模式/1预约模式 |
其中索引8加热状态要按位运算得出,如第8位非0时说明防冻功能正在运行,其他的直接取值即可
零冷水巡航模式设置(读18) | 二进制数位 | 说明 | B7 | 固定为0 | B6 | 固定为0 | B5 | 1为水增压 | B4 | 固定为0 | B3 | 巡航模式,0关闭/1全天候/2点动
其中预约模式为0 | B2 | B1 | B0 |
--------------------------------------------------------------------------------
写设备状态(发送到服务器端的Status字段)
索引 | 说明 | 0 | 热水器通电状态,用读设备状态(1)初始化 | 1 | 模式,用读设备状态(2)初始化 | 2 | 水温,用读设备状态(6)初始化 | 3 | 未知,用读设备状态(25)初始化 | 4 | 未知,用读设备状态(4)初始化 | 5 | 零冷水巡航设置,用读设备状态(18)初始化 | 6 | 零冷水温度,用读设备状态(19)初始化 | 7 | 未知,用读设备状态(20)初始化 | 8 | 未知,用读设备状态(21)初始化 | 9 | 触发一次零冷水巡航,用读设备状态(23)初始化,此项设1时会触发一次巡航且热水器完成时自动停止。除非实现自动化需要,否则填0 | 10 | 固定为0 | 11 | 零冷水预约模式,用读设备状态(33)初始化 |
补充:
Series为LS5时,最低温度为30,否则为35
基于以上信息基本上可以对热水器的完全控制,这两天看情况会用Go实现一个简单的接口以供大家调用或参考。
有遗漏或错误的地方也欢迎大家一起继续探讨
|
评分
-
查看全部评分
|