快速开始
自己部署只需要三步:装 Node、clone 代码、启动。没有构建步骤,没有第三方依赖,也不会往系统里装任何全局包。
不会部署?那就用云端托管
注册账号后云端会自动开一台独立实例,浏览器打开就能用,关掉网页也继续在线收消息。
环境要求
| 项目 | 要求 |
|---|---|
| Node.js | ≥ 18(推荐 20 / 22 LTS) |
| 操作系统 | macOS / Linux / Windows |
| ffmpeg + ffprobe | 可选。非 AMR 语音转码、长语音 / 长视频自动切段需要 |
| npm 依赖 | 无。不需要执行 npm install |
下载代码
git clone https://github.com/laolibuhuifei/JZclient-for-node.git JZClientForNode
cd JZClientForNodeJZclient-for-node,后面那个参数是把目录改名成 JZClientForNode,纯属好看,不影响运行。
启动
npm start
# 或者
node bin/jzclient.js首次运行直接进入登录流程,输入小天才账号密码即可。登录票据和设备标识缓存在本地,之后每次启动会自动把 WebUI 拉起来。
- 输入账号密码:账号就是在小天才 App 里用的那个手机号和密码。
- 新设备验证:新设备首次登录会返回
010410,程序会拉出该账号的密保问题,默认选中包含「天才号」的那条,填 10 位手表天才号即可。 - 自动拉起 WebUI:终端会打印本机地址、局域网地址和访问令牌。
- 浏览器打开:点终端里的「快捷链接」,或者打开首页粘贴令牌。
运行期数据放在哪
登录票据、设备标识、手表状态、AI 配置、OneBot 令牌全部在 ~/.watch-parent-cli/config.json。这个文件基本等于账号密码,别提交到仓库、别发给别人、别贴到群里。
"webui": { "port": 8787, "host": "0.0.0.0", "token": "jz_..." }~/.watch-parent-cli 目录等于退出登录 + 丢掉设备标识,下次启动会被当成新设备,重新走一遍密保验证。
常用环境变量
| 变量 | 作用 |
|---|---|
WP_LOG=debug | 输出请求体、IM 原始帧等细节,排查问题用 |
WP_LOG=warn | 只看告警和错误 |
WP_LOG=silent | 完全静默 |
WP_LOG_COLOR=0 | 关闭 ANSI 颜色(NO_COLOR=1 同效),适合重定向到文件 |
WebUI 使用
命令行只负责账号,所有功能都在 WebUI 里操作。登录成功后自动启动,终端会打印地址、局域网地址和访问令牌:
WebUI 已启动 http://127.0.0.1:8787
局域网 http://192.168.1.20:8787
访问令牌 jz_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
快捷链接 http://127.0.0.1:8787/?token=jz_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx两种进入方式
- 点「快捷链接」——URL 里的
?token=会自动种 Cookie 再跳回干净的地址 - 直接打开首页,在登录页粘贴令牌
0.0.0.0(局域网能访问),但所有 /api 接口都要求访问令牌,没有令牌只能看到登录页。只想本机用就把 host 改成 "127.0.0.1"。连续输错 8 次会锁定该 IP 10 分钟;着急就在命令行按 t new 重新生成(会踢掉已登录的浏览器)。
页面一览
| 页面 | 能做什么 |
|---|---|
| 主页 | 账号概览、CPU / 内存实时磁贴、系统信息、手表列表、每日一言、公告 |
| 概览 | 头像、型号、电量、在线状态、快捷状态 |
| 定位 | 实时位置、历史轨迹、安全区域、丢表模式 |
| 聊天 | 会话列表、消息收发、图片 / 语音 / 视频 / 位置 / 链接 / 表情 |
| 功能 | 宝贝资料、通讯录、好友、健康、应用、WiFi、闹钟、设置、隐藏功能、绑定 |
| 我的 | 账号信息、OneBot 接入、对外 API、外观背景、退出登录 |
多块手表时,左上角的表名胶囊是切换器——点一下换表,当前页所有卡片跟着切过去。功能入口会按型号能力自动裁剪,不会给你一堆点不动的按钮。
深浅色主题
顶栏右上角的图标循环切换三种状态:跟随系统 → 浅色 → 深色。选择存在 localStorage 的 jz_theme 键里,刷新后保留。
改端口 / 换令牌
"webui": { "port": 8787, "host": "0.0.0.0", "token": "jz_..." }改完重启进程生效。把 token 清空后会重新生成一个,旧的浏览器会话随之失效。
绑定手表
支持两种绑定方式,都在 WebUI 的「功能 → 绑定手表」页操作。
没绑定过的手表
- 输入 16 位手表绑定号
- 若服务端返回
010014,输入手表屏幕上显示的验证码 - 选择手表端登录的账号:
0创建新账号(绑定后你是管理员,新账号由手表端注册生成);1..n迁移已有账号(可选是否保留旧手表上的数据) - 提交后当前账号成为该手表管理员
已有管理员的手表
- 查询会显示管理员信息,绑定方式只能选「申请加入」
- 如服务端要求校验管理员手机号,输入管理员完整手机号(最多 5 次)
- 提交后由管理员在手表上同意,申请期间可随时撤回
验证码错误码
| 错误码 | 含义 |
|---|---|
010015 | 验证码错误 |
010016 | 验证码已失效 |
010017 | 错误次数已达上限 |
010018 | 当日次数已达上限 |
微聊与消息
登录成功后(以及 WebUI 服务启动时)会自动建立 IM 长连接,不用手动打开聊天页;断线后 5 秒自动重连。
支持的消息类型
文本、表情、颜文字、位置、链接、图片、语音、视频。微聊对语音和视频有单条时长上限,超了手表端放不出来,所以程序会自动切段发送:
| 类型 | 单条上限 | 切段阈值 | 段数上限 | 段间隔 |
|---|---|---|---|---|
| 语音 | 60 秒 | 58 秒 | 20 段 | 350 ms |
| 视频 | 30 秒 | 28 秒 | 30 段 | 500 ms |
每段在日志里标成 [语音 2/3]、[视频 2/7],发的顺序就是播放顺序。网页录音、拖拽上传、OneBot 的 record 段、B 站点播走的是同一套切段逻辑。
收不到消息怎么排查
先看聊天页顶部的状态条,它会实时告诉你链路到底通不通:
| 状态文案 | 含义 |
|---|---|
| IM 已连接 · 12 秒前收到数据 | 链路正常 |
| IM 连接异常,正在重连… | 连接断了,5 秒后自动重连 |
| IM 已连接 · 已 N 分钟没有收到数据(变红) | 连接半死,程序会在心跳连续 3 次失败且 120 秒无入帧后主动销毁重连 |
true。所以程序内部用心跳和入帧时间双重判定,不会出现「显示已连接但一条消息都收不到」。
状态正常但依然没消息时,按顺序排查:
- 手表端聊天记录里有没有这条消息(确认手表真的发出去了)
- 该会话是否在范围内——OneBot 和 B 站点播的「只收这些会话」是按手表分开勾的,单聊和家庭群是两个会话
- 用
WP_LOG=debug npm start重启,看日志里有没有对应的recv行
OneBot v11 接入
WebUI 起来后会为每块手表各拉起一套 OneBot v11 服务,可以把微聊接进 AstrBot、NoneBot 这类机器人框架。没有「全局一套收所有表」的模式——每块表的端口、令牌、会话范围都是分开的,机器人只会看到它那块表的会话。
| 传输 | 地址 | 令牌 |
|---|---|---|
| HTTP API | http://0.0.0.0:<该表端口>(第一块表默认 5700) | onebotWatches[watchId].http.token |
| 正向 WebSocket | ws://0.0.0.0:<该表端口>(第一块表默认 5701) | onebotWatches[watchId].ws.token |
| 反向 WebSocket | 由 onebotWatches[watchId].wsClient.url 指定(默认关闭) | onebotWatches[watchId].wsClient.token |
5700 起按 10 递增(5700/5701、5710/5711…),会和其他手表的端口一起避让。令牌首次启用时自动生成并写回配置。
在哪配置
WebUI →「我的」→「OneBot v11 接入」卡片 → 右上角「设置」。卡片只显示当前手表(左上角切换条选中的那块),切到别的表它就跟着切过去。
- 本表设置:启用开关、HTTP 端口、WS 端口、反向 WS(地址 / 令牌 / 重连间隔)、「只收这些会话」勾选、两个令牌的重置按钮
- 通用设置:所有手表共用 —— QQ 兼容模式、心跳间隔
- 保存:只重启这块表的实例,别的表不受影响。端口被占用时会保存成功但状态显示「未运行」
正向还是反向?
| 场景 | 用哪种 | 说明 |
|---|---|---|
| AstrBot 和本程序在同一台机器 / 同一局域网 | 正向 WS | AstrBot 主动连 ws://<本机 IP>:5701,本程序不用开端口映射 |
| AstrBot 在公网服务器,本程序在家庭网络内 | 反向 WS | 本程序主动连 AstrBot 的 WS 端点,穿透 NAT 不用做端口映射 |
| 只需要偶尔调一下接口 | HTTP API | POST http://<IP>:5700/<action>?access_token=... |
AstrBot 配置:正向 WS
- 平台选
OneBot v11 (aiocqhttp) - WS 地址填
ws://<电脑局域网 IP>:<那块表的端口>(第一块表默认 5701) - access_token 填那块表自己的 WS 令牌
多块手表就建多个 OneBot v11 平台,各自填对应表的地址和令牌。
AstrBot 配置:反向 WS
- AstrBot 里新建一个 OneBot v11 平台,连接方式选反向 WebSocket,记下它监听的端口(默认
6199,路径固定/ws)和 access_token - WebUI 里那块表的「本表设置 → 反向 WS」打开开关,填地址和令牌;或者直接改配置
- 保存后热重启。日志出现
[onebot] 反向 WS 已连接即成功;断线会按reconnect秒数自动重连
"wsClient": { "enabled": true, "url": "ws://1.2.3.4:6199/ws", "token": "对方设置的令牌", "reconnect": 5 }X-Self-ID(这块表的 IM 账号标识)和 X-Client-Role: Universal,aiocqhttp 依赖这两个头识别连接,缺了会被直接拒绝。路径要写全:AstrBot 固定 /ws,部分框架用 /onebot/v11/ws,只写到端口会被拒。令牌会同时以 Authorization: Bearer 和 ?access_token= 两种形式发送。
支持的 action
| 分类 | action |
|---|---|
| 基础 | get_login_info get_status get_version_info can_send_image can_send_record clean_cache |
| 查询 | get_friend_list get_group_list get_group_info get_group_member_list get_stranger_info get_recent_contact |
| 发送 | send_private_msg send_group_msg send_msg send_group_forward_msg send_private_forward_msg |
| 消息 | get_msg get_forward_msg get_group_msg_history get_friend_msg_history get_image get_record |
消息段支持 text face image record video at reply location share file forward;媒体段认 http(s)、base64://、data URL 和本地绝对路径四种写法。
QQ 兼容模式
按 QQ 写的插件会调一堆 QQ 专有动作,只要有一个返回 1404,很多插件整条链路就崩了。所以按三档处理(开关 onebot.qqCompat,默认开):
- 静默成功:
delete_msg/set_group_ban/set_group_card/send_like… 微聊物理上做不到,返回{}让插件继续往下跑。注意这些动作不会真的发生 - 返回空值:
get_group_honor_info/get_cookies/get_csrf_token… 结构对得上 QQ、内容是空的 - 明确拒绝:
set_group_leave/set_group_kick/delete_friend/ocr_image… 危险或确实做不到,直接报错
qqCompat 后「静默成功」那一档会改成明确报错,方便排查「插件为什么没反应」。delete_friend 会破坏手表绑定关系,永远拒绝。
暂不支持:HTTP 上报(webhook)、真正的撤回、禁言、戳一戳、群文件、好友 / 入群申请审批。
B 站点播
让手表在微聊里自己点视频看:孩子发一句 /搜索 小猪佩奇,机器人回 10 条带序号的视频;再发 /播放 3,程序就把第 3 条下载下来用微聊视频发过去,手表端直接能播。
| 命令 | 作用 |
|---|---|
/搜索 关键词 | 搜 B 站视频,回前 10 条并标上序号(标题 · UP主 · 时长) |
/播放 序号 | 下载上一条搜索结果里的第 N 条并发过来 |
/b站 | 看用法 |
命令写法很宽松,不用记:
- 斜杠可有可无:
/搜索 小猪佩奇和搜索 小猪佩奇一样,点歌是搜索的别名 - 裸词必须带参数:
搜索两个字单独发出去不算命令,不然正常聊天里说「搜索不到」也会被抢走 - 单聊里可以直接回数字:搜完列表后回一个
1就等于/播放 1(只在单聊生效,群里说数字太容易误触) - 发在没勾选的会话里会收到提示,不会静默丢弃
配置
WebUI →「我的」→「B 站点播」,每块手表单独一套:
- 开关:只对启用的手表生效
- 会话范围:勾选在哪些会话里响应(不勾 = 按手表名自动匹配单聊 + 家庭群,和 OneBot 一致)
- 时长 / 大小上限:单条视频的闸门,默认 10 分钟 / 100MB
- 每天上限:防小孩一口气刷十几条,默认 20 条,
0表示不限
fetch 和 ffmpeg,没有 yt-dlp 之类的第三方工具。搜索结果按「手表 + 会话」隔离保留 30 分钟,群里搜的序号不会串到单聊。超过 30 秒的视频自动切段发送。仅用于个人学习与家庭自用,视频版权归原作者与 B 站所有。
日志与排查
日志有两个出口:终端(带颜色,适合 > webui.log)和 WebUI 日志页(网页实时滚动,适合远程看)。两边内容一致,都经过同一套脱敏。
[18:00:56.062] INFO webui 服务已启动 http://127.0.0.1:8787
[18:00:57.301] INFO im 长连接已建立
[18:01:12.884] INFO chat recv msgType=1 dialogId=...出问题先看这三处
- 终端 / 日志页有没有 ERROR:绝大多数问题这里已经有原文,比猜快得多
- 聊天页顶部的 IM 状态条:判断是「没连上」还是「连上了但对方没发」
- 「我的」里 OneBot 卡片的状态:显示「未运行」通常是端口被占用或启动失败,日志里有原因
WP_LOG=debug npm start,会把请求体、IM 原始帧都打出来。注意 debug 日志里可能含手机号等敏感信息,贴出来前先脱敏。
常见问题
需要先 npm install 吗?
不需要。项目零第三方依赖,clone 下来直接 npm start。
WebUI 页面打不开
先确认端口没被占用:lsof -nP -iTCP:8787。默认监听 0.0.0.0,本机和局域网都能连;连不上就看系统防火墙有没有拦这个端口。
一直停在令牌输入页
令牌在启动终端里打印,也可以在命令行里按 t 再看一次。输错 8 次会被锁 10 分钟,着急就按 t new 重新生成一个(会踢掉已登录的浏览器)。
登录失败 / 接口返回参数错误
检查 src/site.config.js 里的 ssoHost、ssoSalt、checksum、brand、apkType 是否与客户端版本匹配。官方客户端升级后接口路径和签名会变,需要同步调整。
新设备验证过不去,一直报 000002
010410 是正常的「新设备」提示,按提示答密保问题(默认选「手表天才号」)。换票返回 000002 是服务端异步落库造成的竞态,程序会自动重试 3 次,仍失败就用密码重新登录一次,不需要你操作。
反向 WS 一直重连 / 日志报「连接被拒绝」
ws:// 和 wss:// 要跟对方一致(对方开了 TLS 就得用 wss://)。url 要写全路径:AstrBot 固定 /ws,部分框架用 /onebot/v11/ws,只写到端口会被拒。令牌要和对方设置的一致。日志里出现 反向 WS 已连接 才算成功,之后每隔 reconnect 秒重试一次是正常行为。
语音发送失败
非 AMR 格式需要本机安装 ffmpeg 做转码。
报「音频切分失败(需要 ffmpeg)」
单条语音上限 60 秒,超过 58 秒会走自动切段,这一步依赖 ffmpeg(切分)和 ffprobe(量时长),两个都在 ffmpeg 发行包里。装完确认 ffmpeg -version 和 ffprobe -version 都能跑。
会不会封号?
型号能力门控是为了降低异常请求被风控的概率,但不保证不封号。请只对自己拥有或已获得明确授权的账号和手表使用,风险自行评估。
我的数据会被上传到哪?
登录票据、设备标识、手表状态都只存在本机 ~/.watch-parent-cli/config.json。项目作者的服务器只提供两件事:主页公告、以及可选的云端托管平台。用自托管时数据不会离开你的机器。
已知限制
项目按「能跑通、能日常用」的标准在做,下面这些是明确还没搞定的部分,欢迎提 PR。
功能缺口
- 短信验证码登录:SSO 路径已确认,尚未接入,目前只能账号密码登录
- 摄像头管控、应用白名单:未实现
- 隐私相关开关:各网关写接口都返回
000007,目前只能查看不能修改 - 单应用使用时长:接口还没定位到
- OneBot v11 缺 HTTP 上报(webhook);撤回 / 禁言 / 戳一戳 / 群文件只是「静默成功」的兼容实现
需要真机验证
- 全新手表的管理员绑定:代码已实现,缺真表端到端验证
- 非管理员迁移:未实测
协议风险
- 接口路径、参数和签名会随官方客户端版本变化,升级后可能需要同步调整
src/site.config.js - 型号能力门控不保证不封号,请自行评估风险
不想自己维护?
云端托管帮你搞定 Node 环境、端口、证书和在线保活,你只管用。