← 返回文档中心

商为云打印设备蓝牙 BLE 配网协议

版本 V1.0 | 发布日期 2026-09-28 | 文档性质 公开(可提供给集成商、ISV 与终端用户技术团队)
适用范围:商为云打印设备系列(云盒 / 热敏票据 / 标签)中具备 BLE 的型号 | 配套参考:《云打印机对接第三方 MQTT 通信协议》

0. 概述与适用范围

本协议描述如何通过蓝牙低功耗(BLE)为商为云打印设备完成网络配置:下发 WiFi 凭据、 设置静态 / 动态 IP,并读取设备当前的联网状态。适用于手机 App、微信小程序、桌面配网工具等 各类宿主应用 —— 协议只依赖标准 GATT 的 写(Write)/ 读(Read)两种操作, 不依赖任何厂商私有 SDK。

设备侧 BLE GATTS 提供两个服务:

服务UUID(16 位缩写)用途
服务一0x00FF蓝牙打印数据通道(特征值 FF01),与本配网协议无关,另见蓝牙打印相关文档
服务二0x00EEWiFi 配网服务(特征值 EE01)—— 本协议的全部报文都发生在该服务上
公开范围说明:本文所述报文格式、字段与状态码均为设备现网固件已实现的稳定能力, 可直接用于第三方集成。未在本协议中出现的能力(如 BLE 打印、OTA)不在公开范围内, 如有需要请联系商务获取。

1. 快速上手:配网全流程

一次典型配网按以下顺序完成,全程约 10 ~ 30 秒:

  1. 扫描 —— 发现目标设备(可按广播名粗筛,见 2.2);
  2. 连接 —— 与目标设备建立 BLE 连接;
  3. 服务发现 —— 枚举服务,确认存在 0x00EE 配网服务及其特征值(见 2.1);
  4. 读取当前状态 —— 对 EE01 发起 Read,获取设备当前配网与联网状态(见 3.3);
  5. 写入 WiFi 凭据 —— 向 EE01 写入 type=1 JSON(见 3.1); 写入后 BLE 连接保持,可继续写入 IP 设置并轮询状态;
  6. (可选)写入 IP 设置 —— 静态 IP 场景写入 type=2 JSON(见 3.2);
  7. 轮询状态 —— 周期性 Read 观察 net_status, 直到变为 4(已接入互联网);
  8. 结束 —— 设备联网成功后即可断开 BLE,后续业务经云端 / MQTT 进行。

2.1 服务与特征值

配网服务 0x00EE 下的特征值 EE01 同时具备写与读两种属性,两种操作共用同一特征值:

项目UUID属性
配网服务(Service)000000EE-0000-1000-8000-00805F9B34FB—
配网特征值(Characteristic)0000EE01-0000-1000-8000-00805F9B34FBwrite / read
兼容性建议(重要):应用在服务发现时,推荐按「服务 UUID 前 8 位为 000000EE」+ 特征值 properties 是否包含 write / read 来匹配, 而不是硬编码完整 128 位 UUID 字符串。这样可兼容设备侧不同固件批次对 UUID 表示 (16 位 / 128 位、大小写)的差异 —— 商为官方配网小程序即采用此匹配方式。

2.2 设备广播与发现

设备开机后对外广播,广播名为「产品前缀 + 标识」的形式。应用可按业务需要过滤扫描结果; 最终确认设备是否支持本协议,以服务发现中是否存在 0x00EE 配网服务为准, 广播名仅用于缩小扫描范围。

2.3 数据格式与写入规则

  • 应用与设备之间以 JSON 文本组织数据,编码为 UTF-8,支持中文 SSID 等多字节字符;
  • 写操作:一次 write 承载一条完整 JSON(不要拆分为多次写入); JSON 报文可能超过 BLE 默认 MTU 单帧容量(20 字节),请确保连接后协商了足够的 ATT MTU (iOS 由系统自动协商;Android 建议在写入前调用 setBLEMTU 请求更大的 MTU, 详见 4.3);
  • 读操作:对 EE01 发起 read,设备以 JSON 作为特征值应答返回 (宿主框架的 characteristic 值回调中收取);
  • 解析宿主应以宽容策略处理状态 JSON:新版本固件可能追加新字段 (如 mac、dualwifi),未识别字段应忽略而非报错。

3.1 写入:WiFi 配置(type=1)

向 EE01 写入如下 JSON,命令设备连接指定 WiFi:

{
                          "type": 1,
                          "ssid": "Office-WiFi",
                          "pwd":  "password123"
                        }
参数值类型说明
typeNumber固定为 1,标识 WiFi 配置报文
ssidStringWiFi 的 SSID,最长 32 字符,支持中文等多字节字符(UTF-8)
pwdStringWiFi 密码,最长 64 字符;开放网络可为空
写入后的预期行为:设备收到有效 WiFi 配置后不会主动断开 BLE 连接, 而是保持连接转入连网流程(扫描 → 关联 → DHCP → 接入云端)。宿主应用可继续通过 Read 轮询 net_status,直到变为 4(已接入互联网)。 若此期间出现连接断开(微信小程序错误码 10006 / 10012 等), 属异常而非预期 —— 多为距离过远、信号干扰或系统回收连接所致, 应提示用户靠近设备并重连后继续轮询。

3.2 写入:IP 设置(type=2)

向 EE01 写入如下 JSON,设置设备的 IP 获取方式。设备默认使用动态 IP(DHCP), 仅在部署环境要求固定地址时才需要本步骤:

{
                          "type": 2,
                          "ip_mode": 1,
                          "ip":      "192.168.1.100",
                          "netmask": "255.255.255.0",
                          "gateway": "192.168.1.1",
                          "dns":     "8.8.8.8"
                        }
参数值类型说明
typeNumber固定为 2,标识 IP 设置报文
ip_modeNumberIP 模式:1 = 静态 IP,0 = 动态 IP(DHCP)
ipStringIPv4 地址,如 "192.168.1.100"。静态必填
netmaskString子网掩码,如 "255.255.255.0"。静态必填
gatewayString网关,如 "192.168.1.1"。静态必填
dnsStringDNS 服务器,如 "8.8.8.8"。静态必填

动态 IP 模式(ip_mode=0)下,四个地址字段可省略。 字段名统一为 ip_mode(与状态应答 3.3 中的字段一致);历史资料中出现的 ipmode 写法以本文为准。

3.3 读取:设备网络状态

对 EE01 发起 Read,得到如下状态 JSON:

{
                          "type": 1,
                          "net_status": 4,
                          "link_type": 1,
                          "ssid": "Office-WiFi",
                          "ip_mode": 0,
                          "ip": "192.168.1.23",
                          "netmask": "255.255.255.0",
                          "gateway": "192.168.1.1",
                          "dns": "8.8.8.8",
                          "dualwifi": true,
                          "mac": "AABBCCDDEEFF"
                        }
参数值类型说明
typeNumber固定为 1,标识网络状态报文
net_statusNumber1 未配网 | 2 已配网未联网 | 3 已获取 IP | 4 已接入互联网(状态机见 4.1)
link_typeNumber联网方式:0 以太网 | 1 WiFi | 2 4G
ssidString已配置的 WiFi SSID;未配置时不携带
ip_modeNumber0 动态 IP | 1 静态 IP;net_status 为 3、4 时携带
ip / netmask / gateway / dnsString当前网络参数;net_status 为 3、4 时携带
dualwifiBoolean双频能力标志:true 支持 2.4G + 5.8G;部分固件携带
macString设备 MAC 地址;部分固件携带
双频提示:仅支持 2.4G 的机型无法连接 5.8G 热点。应用可在配网前先读一次状态, 按 dualwifi 判断设备能力,提前过滤手机当前所连的 5.8G 热点,避免下发必败的凭据。

3.4 扩展:设备信息查询(固件版本与 MAC)

固件版本与 MAC 的读取按以下优先级处理(与商为官方配网小程序一致):

  • 首选:直接 Read。对 EE01 发起 Read,设备经特征值应答返回 版本与 MAC 信息(收取通道与状态读取相同);
  • 兜底:AT+INFO? 指令。Read 失败时,向 EE01 写入 ASCII 字符串 AT+INFO?\r\n,设备随后经特征值应答返回包含版本与 MAC 的应答文本。

应答文本形如 VER:1.2.3 MAC:AABBCCDDEEFF,或等价的 JSON "version" / "mac" 字段;建议按 VER: / MAC: 前缀或 JSON 字段两种形态宽容匹配(MAC 地址可能含冒号分隔符)。

工程注意(与官方配网小程序一致):发出查询后等待应答或 5 秒超时; 等待期间应暂停常规的状态轮询,避免状态 JSON 被误当作设备信息应答解析; 超时后提示用户靠近设备重试。

4.1 状态机与轮询建议

设备 net_status 沿以下状态机推进(不回跳;配置失效或网络变化时可能回到 2):

1 未配网 ──写入WiFi──▶ 2 已配网未联网 ──关联成功──▶ 3 已获取IP ──云端可达──▶ 4 已接入互联网

轮询节奏建议(与商为官方配网小程序一致):

场景建议轮询间隔
刚下发 WiFi 凭据、等待联网结果1 秒(尽快给出成功 / 失败反馈)
net_status = 2(已配网未联网)1.5 秒
net_status = 3(已获取 IP)2 秒
net_status = 4(已接入互联网)停止轮询
net_status = 1(未配网,停留页面)3 秒(降频省电)
  • 注意避免并发 Read:建议对读操作加 1 ~ 1.5 秒的在途锁, 上一次未返回前不发起新的 Read;
  • Read 应答与写入失败回调在不同平台可能经不同事件收取, 轮询逻辑不要绑定在写入回调上,保持独立定时器驱动。

4.2 安全说明

链路安全边界(如实告知):本协议的 JSON 报文(含 WiFi 密码)在 BLE 链路上以明文承载, 链路层安全依赖手机与设备建立连接时系统级的 BLE 配对 / 加密机制。因此建议:
  • 配网操作请在设备近场(3 米以内)完成,避免在远距离或公共场合暴露凭据;
  • 配网成功后,如需更高安全性,建议在业务侧引导用户修改该热点的密码;
  • 设备不提供远程 BLE 配置能力 —— 攻击者无法经网络触发本协议,攻击面仅限近场物理接触范围内。

4.3 平台适配要点

平台要点
微信小程序 使用 wx.openBluetoothAdapter → startBluetoothDevicesDiscovery → createBLEConnection → getBLEDeviceServices / getBLEDeviceCharacteristics 标准流程;写入用 wx.writeBLECharacteristicValue。正常流程下设备不会在写入 WiFi 凭据后 主动断开 BLE;若出现 10006 / 10012 属连接异常断开(见 3.1), 应提示用户重连。
Android 扫描 BLE 必须授予定位权限(部分安卓版本需开启系统定位开关); 默认 ATT MTU 为 23 字节,写入前请调用 requestMtu() 请求更大 MTU, 以容纳完整 JSON 报文。
iOS MTU 由系统自动协商,无需手动请求;注意 CBCharacteristicWriteWithResponse 方式写入,确保 JSON 完整送达。
HarmonyOS 使用系统蓝牙 API 按相同 GATT 流程接入即可;定位权限要求与 Android 一致。

4.4 微信小程序示例代码

以下为关键步骤片段(节选自商为官方配网小程序的实测实现,可直接复用):

① 服务与特征值发现(按前缀 + 属性匹配)

// 枚举服务:按 UUID 前 8 位匹配,避免硬编码完整 128 位 UUID
                        wx.getBLEDeviceServices({
                          deviceId,
                          success(res) {
                            const svc = res.services.find(s => s.uuid.slice(0, 8).toUpperCase() === '000000EE')
                            if (!svc) { /* 设备不支持配网服务 */ return }
                            wx.getBLEDeviceCharacteristics({
                              deviceId,
                              serviceId: svc.uuid,
                              success(res) {
                                // 同一特征值 EE01 同时承担 write / read
                                for (const c of res.characteristics) {
                                  if (c.properties.write)  writeId  = c.uuid
                                  if (c.properties.read)   readId   = c.uuid
                                }
                              }
                            })
                          }
                        })

② 写入 WiFi 凭据

// 写入 WiFi 凭据(UTF-8 编码,单次写入完整 JSON)
                        const payload = utf8Encode(JSON.stringify({ type: 1, ssid, pwd }))
                        wx.writeBLECharacteristicValue({
                          deviceId, serviceId: svcId, characteristicId: writeId,
                          value: payload.buffer,
                          fail(e) {
                            if (e.errCode === 10006) {
                              // 连接异常断开(正常流程设备不会主动断开)—— 提示用户靠近设备后重连
                            }
                          }
                        })

③ 轮询状态(含在途锁)

// Read 应答经特征值回调收取(微信小程序所有特征值变化都走这一个回调)
                        wx.onBLECharacteristicValueChange(res => {
                          const json = JSON.parse(utf8Decode(res.value))   // 状态 JSON,见 3.3
                          // json.net_status === 4 即配网成功
                        })

                        let readInFlight = false
                        function pollStatus() {
                          if (readInFlight) return
                          readInFlight = true
                          wx.readBLECharacteristicValue({
                            deviceId, serviceId: svcId, characteristicId: readId,
                            complete() { setTimeout(() => readInFlight = false, 1500) }
                          })
                        }
                        // 配网等待期 1s/次;net_status=4 后停止

附录 A:字段速查表

字段方向type类型说明与出现条件
type双向—Number报文类型:写入 1=WiFi 配置、2=IP 设置;状态应答固定为 1
ssid写入1String ≤32目标 WiFi SSID(UTF-8)
pwd写入1String ≤64WiFi 密码,开放网络可为空
ip_mode写入2Number1 静态 / 0 动态
ip netmask gateway dns写入2String静态 IP 四项必填;动态模式可省略
net_status应答1Number1 未配网 / 2 未联网 / 3 已获 IP / 4 已联网
link_type应答1Number0 以太网 / 1 WiFi / 2 4G
ssid应答1String已配置 SSID;未配置时不携带
ip_mode应答1Numbernet_status=3、4 时携带
ip netmask gateway dns应答1Stringnet_status=3、4 时携带
dualwifi应答1Boolean双频能力标志,部分固件携带
mac应答1String设备 MAC,部分固件携带

附录 B:版本记录

版本日期说明
V1.02026-09-28 首个公开版本。整理自现网固件实现与商为官方配网小程序实测代码: 双服务(0x00FF 打印 / 0x00EE 配网)与 EE01 写/读两属性定义; type=1 WiFi 配置、type=2 IP 设置、状态 JSON(含 dualwifi / mac 扩展字段);设备信息查询(Read 优先,AT+INFO? 兜底); 状态机与轮询节奏建议;平台适配要点与小程序示例代码。

字段兼容性承诺:后续版本只增不删、不改变既有字段语义;宿主应用按「忽略未知字段」解析即可向前兼容。

深圳商为科技有限公司 · SW-AIoT | 官网:www.sw-aiot.com | 邮箱:sw@sw-aiot.com
本文档描述商为云打印设备蓝牙 BLE 配网的公开协议。设备固件与本文档持续演进, 实际交付设备的最终行为以合同约定与出厂固件为准;协议扩展与商务合作请联系我们或当地授权代理商。