npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chnak/deli-printer

v1.0.4

Published

得力 DL-886AW 蓝牙标签打印机 Node.js SDK(TSPL 协议)

Readme

Deli DL-886AW 蓝牙标签打印机 SDK

Node.js + TSPL 协议 + 蓝牙 SPP 串口通讯的轻量级 SDK。 专为得力 DL-886AW 设计,支持自动端口扫描、中文文本、QR 码、条码、矩形框。


✨ 特性

  • 📡 自动端口扫描 — 蓝牙端口号会变?没关系,用设备名/MAC/VID 一键定位
  • 🇨🇳 完美中文支持 — 内置 TSS24.BF2 字体,GBK 编码
  • 📐 直觉化坐标 — 所有坐标用 mm 标注,告别 dots 单位计算
  • 🎨 5 种 Widget — text / qrcode / barcode / box / line
  • 🖨️ 预览模式 — 不连打印机也能生成 TSPL 指令调试
  • 🔌 零依赖 — 除 serialport + iconv-lite 外无第三方依赖(不依赖有 bug 的 printer-command-generator)

📦 安装

方式一:从 npm 安装(推荐)

npm install @chnak/deli-printer

依赖(自动安装):

方式二:从源码运行

git clone <repo-url>
cd deli-printer
npm install

📖 使用方式

从 npm 安装后

const DeliPrinter = require('@chnak/deli-printer');

从源码运行

const DeliPrinter = require('./deli-sdk');

下文示例均以 npm 方式为准。


🚀 快速开始

1. 按设备名自动扫描端口(推荐)

const DeliPrinter = require('@chnak/deli-printer');

const printer = new DeliPrinter({
  name: '0168',                       // 设备标识(蓝牙 MAC 末 4 位)
  page: { width: 40, height: 30 },    // 标签尺寸 mm
});

await printer.open();                 // 自动扫描并连接

await printer.printLabel({
  widgets: [
    { type: 'text',    x: 2,  y: 2,  content: '拿铁咖啡', fontSize: 4 },
    { type: 'text',    x: 2,  y: 9,  content: '¥29.90',   fontSize: 4 },
    { type: 'qrcode',  x: 12, y: 14, content: 'COF-001',  size: 6 },
    { type: 'text',    x: 14, y: 27, content: 'COF-001',  fontSize: 2 },
  ],
});

await printer.close();

2. 指定固定端口

const printer = new DeliPrinter({
  port: 'COM14',                      // 固定端口
});

3. 仅预览(不连打印机)

await printer.open({ preview: true });
const cmds = await printer.printLabel({ widgets: [...] });
console.log(cmds);                    // 输出 TSPL 指令字符串
await printer.close();

4. 作为 npm 包发布后使用

# 发布
npm login
npm publish --access public

# 在其他项目中使用
npm install @chnak/deli-printer
// 其他项目入口文件
const DeliPrinter = require('@chnak/deli-printer');
// ...

🔍 端口自动扫描

Windows 蓝牙 SPP 配对后会分配虚拟 COM 端口,但 friendlyName 只显示通用名(如「蓝牙链接上的标准串行 (COM14)」),真正的设备标识藏在 PNP ID 中

SDK 提供三种匹配方式:

// 1. 列出所有串口
const ports = await DeliPrinter.listPorts();
// → [{ path: 'COM4',  pnpId: '...VID_05D6_PID_000A...', friendlyName: '蓝牙链接上的标准串行 (COM4)' }, ...]

// 2. 按设备标识查找(按优先级匹配)
await DeliPrinter.findPort('05D6');   // → COM4  (按得力厂商 VID)
await DeliPrinter.findPort('000A');   // → COM4  (按 DL-886AW 产品 PID)
await DeliPrinter.findPort('0168');   // → COM14 (按蓝牙 MAC 末 4 位 hex)
await DeliPrinter.findPort('CH340');  // → COMx  (按 USB 转串口芯片名)

// 3. 找不到时打印所有端口供手动选择
await DeliPrinter.findPort('NONEXISTENT_DEVICE');
// → null,并自动打印 [scan] 发现 N 个串口:...

匹配优先级

| 优先级 | 匹配位置 | 适用场景 | |--------|----------|----------| | 1 | friendlyName / manufacturer | USB 转串口设备(CH340、CP2102 等) | | 2 | PNP ID 中的 VID/PID | 得力蓝牙 SPP(VID=05D6, PID=000A) | | 3 | PNP ID 末段 hex 末几位 | 蓝牙 MAC 地址(如 28D41E190168 末 4 位 0168 |

推荐:使用 MAC 末 4 位

const printer = new DeliPrinter({ name: '0168' });  // 最精确

为什么不是 VID?因为 VID 只能识别厂商,万一你有多个得力设备就分不清了。MAC 地址每台设备唯一。


📐 Widget 类型

所有坐标 x / y / width / height / length 单位都是 mm(除条码 height 用 dots)。

1. text — 文本

// 推荐:fontSize = 3 的倍数,中英文字高一致
{ type: 'text', x: 2, y: 2,  content: '拿铁咖啡', fontSize: 6 }   // 中文 6mm
{ type: 'text', x: 2, y: 9,  content: '¥29.90',   fontSize: 6 }   // 英文 6mm ✓ 一致

// 高级:scale 直接指定 TSPL scale,绕开舍入
{ type: 'text', x: 2, y: 2,  content: '拿铁咖啡', scale: 2 }   // 中文 6mm
{ type: 'text', x: 2, y: 9,  content: '¥29.90',   scale: 4 }   // 英文 6mm ✓ 等高

参数:

  • x, y — 起始坐标(mm)
  • content — 文本内容
  • fontSize — 字高(mm),SDK 自动选 TSPL scale;推荐用 3 的倍数让中英文字高一致
  • scale — 可选,直接指定 TSPL scale(整数),绕开 fontSize 舍入误差
  • font — 可选,内置字体名(默认自动选择:中文=TSS24.BF2, 英文=Font 1)

⚠️ 字体高度一致性

中英文字体基础尺寸差一倍(24 vs 12 dots),同样的 fontSize 经过舍入后实际字高会不一致:

| fontSize | 中文 scale | 中文字高 | 英文 scale | 英文字高 | 一致? | |----------|-----------|---------|-----------|---------|------| | 1 | 1 | 3mm | 1 | 1.5mm | ❌ | | 3 | 1 | 3mm | 2 | 3mm | ✅ | | 4 | 1 | 3mm | 3 | 4.5mm | ❌ 偏差 1.5mm | | 6 | 2 | 6mm | 4 | 6mm | ✅ | | 9 | 3 | 9mm | 6 | 9mm | ✅ | | 12 | 4 | 12mm | 8 | 12mm | ✅ |

结论fontSize 必须是 3 的倍数(3, 6, 9, 12...) 才能中英文字高一致。

如需任意字高,可改用 scale 直接控制:

// 任意字高都让中英文字高一致
{ type: 'text', content: '拿铁咖啡', scale: 1 }   // 3mm
{ type: 'text', content: '¥29.90',   scale: 2 }   // 3mm ✓
{ type: 'text', content: '拿铁咖啡', scale: 2 }   // 6mm
{ type: 'text', content: '¥29.90',   scale: 4 }   // 6mm ✓
{ type: 'text', content: '拿铁咖啡', scale: 3 }   // 9mm
{ type: 'text', content: '¥29.90',   scale: 6 }   // 9mm ✓

规律:英文字体 scale 必须是中文的 2 倍 才能等高。

完整字体映射(DL-886AW 实测):

| fontSize | 中文实际字高 | 英文实际字高 | 中文 scale | 英文 scale | |----------|------------|------------|-----------|-----------| | 1 | 3mm | 1.5mm | 1 | 1 | | 3 | 3mm | 3mm | 1 | 2 | | 4 | 3mm | 4.5mm | 1 | 3 | | 6 | 6mm | 6mm | 2 | 4 | | 9 | 9mm | 9mm | 3 | 6 | | 12 | 12mm | 12mm | 4 | 8 |

中文自动用 TSS24.BF2(内置宋体 24 dots),英文/数字用 Font 1(12 dots)。

2. qrcode — 二维码

{ type: 'qrcode', x: 12, y: 14, content: 'https://example.com', size: 6 }

参数:

  • x, y — 左上角坐标(mm)
  • content — 编码内容
  • size — 每个 module 的 dots 数(1-10),SDK 内部会做版本检测

⚠️ 重要:QR 码实际尺寸计算

QR 码实际宽度 ≠ size × content.length,而是:

实际宽度(mm) = size × modules / 8
其中 modules = 21 + 4 × version(V1=21, V2=25, V3=29, V4=33...)

SDK 会自动检测版本。'COF-001' 编码后是 Version 1(21×21 modules)size=6 时实际宽度 = 6 × 21 / 8 = 15.75mm

居中示例(40mm 宽标签):

const size = 6, version = 1;              // modules = 21
const qrWidth = size * (17 + 4 * version); // = 126 dots = 15.75mm
const x = (40 - qrWidth / 8) / 2;          // ≈ 12.13mm
{ type: 'qrcode', x, y: 14, content: 'COF-001', size }

3. barcode — 条形码

{ type: 'barcode', x: 2, y: 13, content: 'COF-001', height: 60, narrow: 2, wide: 2, codeType: '128' }

参数:

  • x, y — 起始坐标(mm)
  • content — 条码内容
  • height — 条码高度(dots,非 mm)
  • narrow — 窄条宽度(dots)
  • wide — 宽条宽度(dots),可选默认等于 narrow
  • codeType — 条码类型:128 / 39 / EAN13 / EAN8 / UPCA / UPCE / CODABAR / 93

4. box — 矩形边框

{ type: 'box', x: 1, y: 1, width: 38, height: 28, thickness: 2 }

参数:

  • x, y — 左上角(mm)
  • width, height — 宽高(mm)
  • thickness — 边框粗细(dots),默认 1

5. line — 水平线

{ type: 'line', x: 2, y: 12, length: 36, thickness: 2 }

水平线(用 BARCODE 模拟)。参数:

  • x, y — 起点(mm)
  • length — 长度(mm)
  • thickness — 线粗(dots),默认 1

⚙️ 全部配置项

const printer = new DeliPrinter({
  // 连接方式
  port: 'COM14',                    // 串口号(与 name 二选一,name 优先)
  name: '0168',                     // 设备名关键词,自动扫描
  baudRate: 9600,                   // 波特率(DL-886AW 固定 9600)

  // 标签尺寸
  page: { width: 40, height: 30 },  // 标签尺寸 (mm)
  gap: 2,                           // 标签间距 (mm)
  gapOffset: 0,                     // GAP 偏移 (mm),几乎总是 0
  gapMode: 'GAP',                   // 'GAP' | 'BLINE'(黑标纸)

  // 打印参数
  direction: 0,                     // 方向:0=底部出纸(DL-886AW 必须用 0)
  density: 10,                      // 浓度 0-15(默认 10)
  speed: 4,                         // 速度 1-6(默认 4)
  offset: 0,                        // 打印偏移 (mm),用于微调

  // 编码
  encoding: 'gbk',                  // 'gbk'(中文必须)| 'utf8'
  codepage: 'GB18030',              // CODEPAGE 指令值
});

运行时修改配置

printer.setConfig({ gap: 3, direction: 0 });
printer.setConfig({ page: { width: 50, height: 30 } });

临时改每张标签的尺寸

await printer.printLabel({
  page: { width: 50, height: 30 },   // 仅本次用 50×30mm
  widgets: [...],
});

🎬 命令

说明:如果你是通过 npm 安装的 @chnak/deli-printer,需要先 clone 源码到本地来运行 demo(demo 文件不包含在 npm 包内),或参考 项目结构 自行组织文件。

以下命令假设你在源码目录下运行。

Demo 脚本(deli-sdk-demo.js

# 列出所有 demo
node deli-sdk-demo.js list

# 打印单个 demo
node deli-sdk-demo.js 1         # 英文 + QR
node deli-sdk-demo.js 2         # 中文商品价签
node deli-sdk-demo.js 3         # 条形码
node deli-sdk-demo.js 4         # 组合 + 矩形框

# 打印所有 demo
node deli-sdk-demo.js all

# 预览(不连打印机,输出 TSPL 指令)
node deli-sdk-demo.js preview 1
node deli-sdk-demo.js preview 2

独立预览脚本(deli-sdk-preview.js

node deli-sdk-preview.js 3       # 只生成 demo 3 的 TSPL 指令

🖼️ Demo 模板

| 编号 | 名称 | 内容 | |------|------|------| | 1 | 英文文本 + QR | 英文 + 二维码 | | 2 | 中文商品价签 | 中文商品名 + 价格 + 居中二维码 + SKU | | 3 | 条码 + QR | 条形码 + 二维码 + 文本 | | 4 | 完整组合 | 边框 + 标题 + 商品信息 + QR |

所有 demo 统一 40×30mm 标签,参考 deli-sdk-demo.jstemplates 对象。


🔧 故障排查

中文乱码 / 打印出 ?

SDK 默认已用 GBK 编码 + CODEPAGE GB18030。如仍乱码:

  1. 确认打印机固件支持中文(打印出 TSS24.BF2 字样说明字体已加载)
  2. 检查串口波特率是否为 9600
  3. 确认 encoding: 'gbk'(不要用 utf8)

打印错位 / 倒置 / 左右翻转

  • DL-886AW 必须用 direction: 0(SDK 默认)
  • offset 微调位置(正数下移,负数上移)

端口找不到 / 连接失败

# 查看所有串口
[System.IO.Ports.SerialPort]::GetPortNames()

# 查看蓝牙设备对应的 COM 端口
Get-PnpDevice | Where-Object {$_.Class -eq 'Bluetooth'} | Select-Object FriendlyName, InstanceId

如果设备名带 (NEW) 后缀,说明 Windows 蓝牙注册了多个端口。可以:

await DeliPrinter.printPorts();   // 列出所有端口
await DeliPrinter.findPort('0168');  // 按 MAC 末 4 位精确定位

需要强制启用 SPP 服务时可用 force-spp.ps1(PowerShell 脚本)。

二维码位置不对 / 居中偏移

  1. 确认文本长度对应的 QR 版本(V1=21 modules → 短文本)
  2. 用公式计算实际宽度:size × modules / 8(mm)
  3. 居中 x = (page.width - qrWidth) / 2

参考 deli-sdk-demo.js 第 2 个 demo 中的注释。


📝 协议要点

  • 物理层:蓝牙 SPP → 虚拟 COM 端口 → 串口 9600 8N1
  • 指令集:TSPL(TSC Printer Language)
  • 分辨率:203 DPI = 8 dots/mm
  • 中文方案:内置 TSS24.BF2 字体 + GBK 编码 + CODEPAGE GB18030
  • 打印流程:每张标签前发 SIZE / GAP / DIRECTION / CODEPAGE / CLS,渲染所有 widget 后 PRINT 1,1

🗂️ 项目结构

deli-printer/
├── deli-sdk.js          # 核心 SDK(DeliPrinter 类,对应 npm 包入口)
├── deli-sdk-demo.js     # Demo 模板 + 交互运行脚本
├── deli-sdk-preview.js  # 独立预览脚本
├── DIAGNOSIS.md         # 打印机诊断记录(ESC/TSPL 状态查询等)
├── force-spp.ps1        # PowerShell:强制启用蓝牙 SPP 服务
├── package.json         # npm 包配置(name: @chnak/deli-printer)
└── README.md            # 本文件

### 发布到 npm

```bash
npm login                  # 登录 npm 账号
npm publish --access public  # 发布 scoped 包

发布后其他人可直接:

npm install @chnak/deli-printer

然后 require('@chnak/deli-printer') 使用。


---

## 📄 License

MIT

---

## 🔗 相关链接

- **npm 包**:[@chnak/deli-printer](https://www.npmjs.com/package/@chnak/deli-printer)
- **GitHub**:<repo-url>
- **TSPL 指令参考**:见 `DIAGNOSIS.md`