Files
qianbian/analysis/web/protocol-raw.md
T

10 KiB
Raw Blame History

墨水屏 Web 上位机 BLE 协议提取报告(原始证据)

来源:analysis/web/(ble.js 4408 行 / index.html 1309 行 / moban.js 943 行 / timedjs.js 714 行 / timedjs2.js 323 行 / switch2.js 54 行 / time.js 21 行 / hex.js 15 行) 设备:4.2寸 400x300 黑白红三色墨水屏,DA14585,设备名前缀 NRF-

1. GATT 结构

项 值 证据
设备名过滤 namePrefix: 'NRF-' ble.js:4052-4054
optionalServices 0000221f-...34fb、00001f10-...34fb、13187b10-eba9-a3ba-044e-83d3217d9a38 ble.js:4054
EPD Service 13187b10-eba9-a3ba-044e-83d3217d9a38 ble.js:4163
EPD Characteristic 4b646063-6264-f3a7-8941-e65356ea82fe ble.js:4165
RXTX Service 00001f10-0000-1000-8000-00805f9b34fb ble.js:4101
RXTX Characteristic 00001f1f-0000-1000-8000-00805f9b34fb ble.js:4103
0000221f 仅声明未使用 ble.js:4054
  • epdCharacteristic:图像数据块 + 刷屏命令(00xx/01/AA),writeValueWithResponse(ble.js:38-44),订阅 notify(ble.js:4167-4205)。
  • rxtxCharacteristic:全部控制命令(时间/模式/WiFi/激活/倒计时/模板槽位),writeValueWithResponse + 100ms 后 read(ble.js:50-71);另有 writeValueWithoutResponse(ble.js:84-90);notify 是设备ID 14 字节应答主通道(ble.js:4121-4137)。
  • 连接顺序:preConnect()(ble.js:4045)→ connect()(ble.js:4158)先 EPD 后 RXTX(ble.js:4207);断线重连≤5次(ble.js:30-36)。

2. 命令协议

2.1 发送封装

函数 行为 证据
sendCommand EPD writeValueWithResponse ble.js:38-44
rxTxSendCommand RXTX write+100ms read ble.js:50-75
rxTxSendCommand2 RXTX writeWithoutResponse ble.js:84-90
triggerEpdCmd hex→EPD ble.js:3971-3974
triggerRxTxCmd hex→RXTX ble.js:3963-3966
triggerRxTxCmd2 hex→RXTX(无响应) ble.js:3967-3970
setri RXTX 发 cmd,300ms 后补 e2 ble.js:3956-3962
clearScreen EPD 发 00{cmd} 再 01 ble.js:45-49
triggerEpdRed_lut RXTX E6{cmd}(0 直接返回) ble.js:3975-3980
triggerEpdJH RXTX EF{cmd},500ms 后 e2 ble.js:3981-3987
triggerEpdCHEPAI 字符双写+EF 前缀,500ms 后 e2 ble.js:3988-3998
triggerRxTxCmd_LED cmd+note+color+HH+MM ble.js:3999-4009
triggerRxTxCmd_XM cmd+HH+MM ble.js:4010-4020
triggerRxTxCmd_LB e901+hex(n)+cmd ble.js:4022-4038

2.2 Opcode 一览

EPD 通道:

Opcode 含义 证据
00{xx} 刷屏第一步 ble.js:47
01 刷屏执行/整图结束刷新 ble.js:48,160,230
AA 日历小图传输结束 ble.js:159
03{ff|00}{offset:2B BE}{data} 整图数据块(≤240B/块) ble.js:98,104
04{ff|00}{offset:2B BE}{data} 日历小图数据块(hex 总长 7000/18000 时) ble.js:99,104

RXTX 通道:

Opcode 含义 证据
e2 提交/强制刷新(多数命令收尾) ble.js:256,3961 等
dd{unix:4B}{year:2B}{month:1B}{day:1B}{week:1B} 设置时间 ble.js:251-257
2300/2301 三色/黑白屏模式 index.html:840-841
14 12/24 小时制切换 index.html:845
15 时钟颜色切换 index.html:881
e3 反色模式 index.html:878
e4 时钟字体切换 index.html:880
e5 旋转180° index.html:886
e10000..e10003 图片模式 图一~图四 index.html:868-873
e10103/e10104/e10105 日历模式一/二/三 index.html:860-862
e10201/e10202/e10203 时钟模式一/二/三 index.html:853-855
E6{lut} 红/黑 LUT 校准:01–0f 设红、10–f0 设黑 ble.js:3978; index.html:885-887
FB01{HH}{MM} / FB00{HH}{MM} 开/关休眠时段 index.html:897-898; ble.js:4017
e901{n:hex}{01|00} 图片轮播间隔(01=分钟 00=小时) ble.js:4035
EA0{slot} 上传选槽位 EA00–EA03 ble.js:213,237
EA000{n-1} 轮播数量 1–4 ble.js:241-249
EF{激活码hex} 激活设备 ble.js:3891,3983
EF{逐位双写号码} 停车牌("12"→EF1122) ble.js:3990-3995
EFEF 请求设备 ID(14B notify 应答) ble.js:3924,4123
FA 关闭倒计时 timedjs2.js:142,308
ff00{year}{MM}{dd} 时钟倒计时日期(year=4位十进制ASCII) timedjs2.js:250-253
ffff{year}{MM}{dd} 日历倒计时日期 timedjs2.js:245-248
04{128B hex} + 0{charCount}{余hex} 时钟倒计时前缀文字位图(>4字符拆两包) timedjs2.js:206-217
0{charCount}{位图hex} 同上 ≤4字符单包 timedjs2.js:218-224
990{j}{72B hex} 日历倒计时文字位图(每字符一包,24x24/8) timedjs2.js:229-233,300-304
ASCII WIFI_SSID:..;WIFI_PASS:..;CITY:.. WiFi+天气城市配置(UTF-8 直发) ble.js:3839-3863
{cmd}{note}{color}{HH}{MM} LED 变体(遗留) ble.js:4000-4008

3. 图像传输协议(sendBufferData ble.js:92-107)

  1. 分块:my_step=480 hex 字符 = 240 数据字节/块(ble.js:9,100)。
  2. 帧格式(ble.js:104):cod(1B: 03整图/04小图) + code(1B: ff=bw平面 00=红平面) + offset(2B 大端,=字节序号) + ≤240B 数据。块总长 244B。
  3. cod 判定(ble.js:98-99):hex 长度 7000(=3500B=280x100/8) 或 18000(=9000B=400x180/8) 用 04,否则 03。
  4. 无应用层 ACK,顺序 writeWithResponse(ble.js:102-106)。
  5. 结束:delay(300) → 整图发 01;日历小图(宽280 或 高180)发 AA(ble.js:158-160)。

上传函数差异:

函数 前置 打包 结束
upload_image 无 296宽→canvas2bytes_bw;250/212宽→bw;其他→canvas2bytes 双平面 01/AA
upload_image_moban(bat) RXTX EA0{bat} 296宽→bw,否则双平面 01
upload_image_lb(cmd) RXTX EA0{cmd} 同 upload_image 同
upload_image_lb_num(cmd) RXTX EA000{cmd-1} 不传图 无

三色 = 两次发送:bw 平面(code=ff) + 红平面(code=00)(ble.js:154-155,219-222)。

4. 像素打包(timedjs.js)

函数 扫描 位序 用途 证据
canvas2bytes 行主序 y0→H,x0→W MSB first,8px/B 400x300/800x480/280x100/400x180 timedjs.js:564-584
canvas2bytes_bw 列主序 x 从 W-1→0,y0→H MSB first 2.9寸296x128、2.13寸 timedjs.js:586-611
canvas2bytes_to 转置 MSB first 未调用 timedjs.js:612-632

位值:bw 平面 R,G,B 全>0→1(白) 否则 0(黑);bwr 平面 R>0,G=0,B=0→1(红)(timedjs.js:573-576,599-601)。 400x300 → 每平面 15000B。红色判定:r>g*1.5 && r>b*1.5 && r>threshold(timedjs.js:255 等)。

抖动算法(dithering() 分发 timedjs.js:513-563):

  • 黑白:none/floydsteinberg(7,3,5,1 /16)/atkinson(1/8×6)/bayer(4x4 15,135,45,165],[195,75,225,105],[60,180,30,150],[240,120,210,90)/stucki(/42)/jarvis(/48)
  • 黑白红:bwr_ 前缀同名 6 种,默认 bwr_atkinson
  • threshold 默认 125;diffusion 0–100/100 误差缩放
  • bwrPalette=黑白红(timedjs.js:504-508)
  • 预处理 applyImageAdjustments:亮度/对比度/饱和度(timedjs.js:2-38),灰度 0.299/0.587/0.114

5. 时钟/日历/倒计时

setTime(ble.js:251-257)RXTX 连发 dd… + e2:

偏移 长度 含义
0 1B dd
1 4B unix 秒(本地时区修正 Date.now()/1000 - tzOffset*60,ble.js:4222)
5 2B 年(大端)
7 1B 月 1–12
8 1B 日
9 1B 星期(getDay()

倒计时:

  • 时钟界面 gridSize=16:>4 字符(中文=1 英文=0.5)拆两包 04+128B / 0{n}+余;≤4 单包 0{n}(timedjs2.js:206-224)
  • 日历界面 gridSize=24:每字符一包 990{j}+72B,间隔1s(timedjs2.js:228-235)
  • 日期帧 ff00{year}{MM}{dd}(时钟)/ffff...(日历),year=4位十进制ASCII(timedjs2.js:244-254)
  • 收尾 E2;关闭 FA+1s+E2(timedjs2.js:141-145)
  • upload_rili:990*→FA→e10103→E2(timedjs2.js:308-312)

6. 模板系统(moban.js)

6 模板渲染到 #unifiedCanvas(#epdwh 选 400x300/800x480/296x128),无 BLE 代码;上传走 upload_image_moban(0)→EA00+图块+01(index.html:1243)。

模板 data-template 渲染
日程 schedule renderPresetTemplate moban.js:140-145,369-467
名片 businesscard 同上 moban.js:146-151
备忘录 memo 同上 moban.js:152-157
课程表 course renderCourseTable(默认5天x4节,3–7天、2–9节) moban.js:29-63,165-317
二维码 qrcode renderQRCodeMode(qrcodejs CorrectLevel.M) moban.js:81-113,501-570
自定义文本 customText renderCustomMode(自动换行) moban.js:572-693

红字语法 【…】(parseColoredText moban.js:470-498);反色模式 7 种(moban.js:122-137)。

7. 激活机制

  • API:http://4638e813e4.qicp.vip:8889/key_generator.php(ble.js:3866)
  • fullAutoActivate(ble.js:3932-3955):
    1. 读 #fixedId(用户固定ID,UI 隐藏 index.html:930-935)
    2. getDeviceIdFromScreen:RXTX 发 EFEF,8s 超时,notify 累计 14 字节(EXPECTED_ID_BYTES=14 ble.js:4123),可打印转 ASCII 否则 hex(ble.js:4121-4137)
    3. requestActivationCode:GET ?id={fixedId}&key={deviceId}(ble.js:3879-3886)
    4. extractActivationCode:正则 激活码1:([0-9A-F]{32,}) / 激活码:(…) / 任意≥32hex(ble.js:3869-3876)
    5. sendActivationToDevice:EF+大写激活码,400ms 后 e2(ble.js:3889-3902)
  • 算法在服务端 key_generator.php,客户端无实现。自助站 qbsg.top,作者微信 2549294317。
  • 固件下载同 host:http://4638e813e4.qicp.vip:8889/GuJian/file_down.php(index.html:836),型号列表在服务端。

8. 高级命令

index.html:919-920:#cmdcmd 任意 hex → triggerRxTxCmd 直发 RXTX。 hex.js:2-15:hexToBytes/bytesToHex/intToHex(大端 pad)。

9. 变体与其他

  • LED=灯板变体(遗留);XM=休眠(FB00/FB01);LB=轮播(e901/EA000);CHEPAI=停车牌;JH=激活;lut=LUT 校准 E6
  • 设备名前缀仅 NRF-(ble.js:4053)
  • chinaCities 城市→天气代码表 ble.js:259 起约3580行,用于 WIFI 配置 CITY 字段
  • 死代码:SendCommand(i 未初始化)、upload_image_lbs(未定义)