Skip to content

About

ESP32-S3 WiFi Print Server — turns any USB printer into a network printer via Raw Socket :9100. Web UI + OTA + mDNS.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

ESP32-S3 WiFi Print Server

当前版本:v2.6.0

把 USB 打印机变成网络打印机。Windows / macOS / Linux 装原厂驱动后,通过标准 Raw Socket 9100 直接打印, 不需要装任何打印服务器软件。

[电脑] ──WiFi── [ESP32-S3] ──USB OTG── [打印机]

核心特性一句话:固件对打印数据完全透明,不理解任何页面描述语言, 所以 PCL / PostScript / ESC-P / ESC/POS / PJL / PCLm / GDI(主机型)全部可用 —— 渲染由电脑端驱动完成,板子只负责把字节搬到 USB 上。


目录


先看这个:能不能用

支持

场景 说明
标准 USB Printer Class(接口类 0x07) 最常见情况,插上就能用
GDI / 主机型打印机 渲染在电脑端驱动完成,板子只透明转发。实测 Epson Stylus Photo 1390、HP LaserJet MFP
厂商私有接口(0xFF) 机型库放行后接管。已放行 HP(含非标准 255/9/1)、Canon
IPP-over-USB(7/1/4) 能识别并接管,目前仍透传不代理
热敏票据机 / 标签机 Zebra、TSC、Star、Gprinter、QinHeng 已在库中

不支持

场景 原因
高速打印机(High-Speed 480Mbps 独占) ESP32-S3 只有 Full-Speed 12Mbps,实测 0.6–1 MB/s。A3/2880dpi 大图会明显慢
一体机的扫描 / 传真 只转发打印通道
手机端免驱打印 iOS/Android 免驱发的是 PDF / URF,主机型(GDI)根本不认识。要在设备端做 PDF→原机语言的栅格化,MCU 做不到。主机型请在 Windows / macOS / Linux 装原厂驱动使用
打印中需要双向状态查询 支持回读(见下),但同一时刻只受理一个连接,打印期间的状态查询连接会被拒绝

双向回读(v2.4.0 起)

固件在 Bulk IN 端点常挂一条读传输,把打印机吐出来的字节原样写回 TCP:

  • Windows 端口设置里可以真正勾上「启用双向支持」
  • PJL 状态查询、缺纸/卡纸应答、票据机 ACK 都能回传
  • 这是后续做 IPP 代理的前置能力

注意:实测 HP 机型在常驻回读下会拒收打印数据,机型库已对 HP 整族关闭回读(Q_NO_BIDIR)。 若你的机器被回读干扰,在 printer_db.cpp 里给它加 Q_NO_BIDIR。


硬件要求

项目 规格
开发板 ESP32-S3 开发板(必须带 USB OTG)
Flash 4MB
PSRAM 2MB 或以上(实测 XMC 4MB Flash + 2MB PSRAM 可用)
USB OTG 线 Type-C / Micro-USB 转 USB-A 母口,必须是 OTG 线,普通充电线不行
打印机线 USB-A 公转 USB-B 公(打印机原装线)
供电 5V / 1A 以上

接线

  • 标「USB」的接口 → 接 OTG 线 → 打印机(Host 模式)
  • 标「UART / COM」的接口 → 接电脑烧录,烧录后作为供电口

⚠️ 板载 USB-Serial/JTAG 口(VID:PID 303A:1001)不是 OTG 口。接错口枚举不到打印机。


编译与烧录

1. 安装 ESP32 核心

板管理器搜索 esp32,安装版本 3.3.10(IDF v5.5.4)。

🔴 必须钉死 3.3.10,绝对不要升级。 Arduino IDE / arduino-cli 会自动升级开发板包。实测升到 3.3.11 后 USB Host 不再枚举打印机: 网页显示「未连接」、enumCount=0、vid=0000,断电重启打印机、重插 USB 全都无效 —— 看起来像硬件坏了,其实只是核心版本变了。

判别信号:编译突然整机重编(数分钟)+ 产物体积明显变化 (3.3.10 ≈ 1,089,824 字节;3.3.11 ≈ 1,076,736 字节)。

退回:

arduino-cli core uninstall esp32:esp32        # 注意:不能带 @版本号
arduino-cli core install  esp32:esp32@3.3.10

装完需整机重编译再 OTA。装/卸都很慢(10 分钟量级),期间低 CPU 属正常。

2. 工具菜单设置

设置项 选择 说明
Board ESP32S3 Dev Module
USB CDC On Boot Disabled 必须 Disabled,否则 USB Host 不可用
USB Mode USB-OTG (TinyUSB)
USB DFU On Boot Disabled
USB MSC On Boot Disabled
PSRAM OPI PSRAM
Flash Size 4MB 按实际 Flash 选
Partition Scheme Minimal SPIFFS (1.9MB APP / 190KB SPIFFS) 必须选含 OTA 的方案

对应 FQBN:

esp32:esp32:esp32s3:USBMode=default,CDCOnBoot=default,PSRAM=enabled,FlashSize=4M,PartitionScheme=min_spiffs

3. 编译

Arduino IDE:打开 ESP32S3_PrintServer_v2.ino → 选择串口 → 点上传。

arduino-cli:

arduino-cli compile --fqbn "esp32:esp32:esp32s3:USBMode=default,CDCOnBoot=default,PSRAM=enabled,FlashSize=4M,PartitionScheme=min_spiffs" .

编译时只给 --build-path,不要同时给 --output-dir(指向同一目录会报 are the same file, 是假错,.bin 其实已经正确生成)。

4. 烧录失败

按住 BOOT → 按一下 RST → 松开 RST → 松开 BOOT,进入下载模式后重试。


首次配网

  1. 烧录完成,接好 USB OTG 线
  2. 串口监视器(115200)应看到 [USB] 打印机就绪
  3. 手机或电脑连 WiFi PrintServer-Setup,密码 12345678
  4. 浏览器打开 http://192.168.4.1
  5. 用出厂账号登录:admin / admin
  6. 扫描 → 选 WiFi → 输密码 → 连接
  7. 成功后设备切换到新 IP,页面自动跳转,用同一套账号密码再登录一次
  8. 进 系统 → 修改管理员密码(不改的话,除配网外的所有写操作都会被 403 挡住)

ESP32 只支持 2.4GHz WiFi。

忘记管理员密码:长按板子 BOOT 键约 10 秒(串口会打印提示),密码清空回 admin。 没有实体按键的板子把 config.h 的 AUTH_FACTORY_RESET_PIN 改成 -1 关闭此功能 (同时也就失去了这个救场手段)。

设备连不上网、网页打不开:等 3 分钟。固件判定长时间离线后会自动开出 PrintServer-Setup 热点,连上去重新配置即可,不用拆机重刷。期间它一直在后台尝试连回原 WiFi。


添加网络打印机

Windows

  1. 设置 → 蓝牙和其他设备 → 打印机和扫描仪 → 添加设备
  2. 搜索完成后点 手动添加
  3. 选 使用 TCP/IP 地址或主机名添加打印机
  4. 设备类型 TCP/IP 设备,地址填板子 IP(或 printserver.local)
  5. 系统查询大概率超时 → 直接点 自定义 手动设置
  6. 协议 Raw,端口 9100
  7. 取消勾选「SNMP 状态已启用」(重要,否则 Windows 判定打印机离线)
  8. 选打印机驱动
  9. 用真实打印作业验证(不是固件测试页,见故障排查)

macOS

系统设置 → 打印机与扫描器 → 添加打印机 → 切到 IP 标签页 → 协议 HP Jetdirect - Socket → 地址填 IP → 使用 → 选择软件 搜型号。

Linux (CUPS)

# Web: http://localhost:631 → Administration → Add Printer
sudo lpadmin -p WiFiPrinter -E -v socket://192.168.1.50:9100 -m everywhere

网页管理界面

访问 http://printserver.local。未登录时整页盖登录框;登录后 5 个页签,每 2 秒自动刷新:

页签 内容
概览 打印机状态与型号、当前作业(已接收 / 已发往 USB / 回读已回收 / 速率 / 用时)、累计统计、运行时长、内存
打印机 USB 链路全量信息(VID:PID、接口、协议、端点、包长、是否 IPP-over-USB、重枚举次数)、Device ID、序列号;「打印测试页」「软复位」按钮(异步,结果以 toast 弹出)
网络 WiFi 状态、SSID、IP、当前 / 近 1 分钟最差 / 均值信号、离线时长、断线与重连次数、当前重试间隔、后备 AP 是否已开;扫描并切换网络
系统 修改管理员密码、OTA 升级、重启、恢复出厂
添加打印机 Windows / macOS 图文步骤,IP 自动填入

顶部在默认密码未改时挂醒目横幅;打印机进入「无响应保护期」也会提示。


HTTP API

除状态和登录外,所有接口都需要登录(Cookie PSID 或 Authorization: Bearer <token>)。 跨站请求会被拒绝(校验 Origin 与 Host 一致)。

端点 方法 登录 说明
/api/auth/state GET 否 鉴权状态:authenticated / needChange / 是否被锁定
/api/auth/login POST — 表单 user pass,成功返回会话 Cookie
/api/auth/logout POST 是 销毁当前会话
/api/auth/passwd POST 是 oldpass newpass newpass2;成功后自动重签会话
/api/status GET 是 完整状态 JSON(打印机 / USB / 作业 / 统计 / 网络质量 / 异步操作结果)
/api/debug GET 是 崩溃日志、boot 计数、泄漏传输计数
/api/wifi/scan GET 是 后台扫描,返回上次结果(非阻塞)
/api/wifi/connect POST 是¹ ssid password,返回新 IP
/api/testpage POST 是² 提交测试页,立刻返回,轮询 /api/status 的 ops.testpage
/api/printer/reset POST 是² 同上,结果看 ops.usbReset
/api/restart POST 是² 重启 ESP32
/api/factory-reset POST 是¹ 清除 WiFi + 管理员密码并重启
/api/ota POST multipart 是² OTA 升级,字段名 firmware;可加 ?pw= 传 OTA_PASSWORD

¹ 允许在「还没改掉出厂默认密码」时调用 —— 配网和救场是基础能力,不能被锁死。 ² needChange 状态下返回 403 {"error":"default-password"}。

ops 状态码:0 无请求 / 1 执行中 / 2 成功 / 3 失败。 异步化是因为这些操作要发 USB 控制或批量传输,遇到不应答的打印机会阻塞几十秒。


机型行为特征库

兼容性的关键不在「认不认得这台打印机」,而在知不知道它的坏脾气。

固件对数据是透明的,PCL / PS / ESC-POS / GDI 天然都能打。真正决定「某一台打印机能不能用、好不好用」 的从来不是打印语言,而是它在 USB 层的一些怪癖:

  • 对所有控制传输长时间 NAK(爱普生 1390)→ 不能发 Device ID
  • 作业开头被塞 ESC @ 就卡住不出纸(HP 走 @PJL 流)
  • 作业结束补 FF 反而让它永久等待下一页(PCLm 流尾部自带 %%EOF)
  • 暴露的根本不是标准打印机类接口,而是厂商私有接口(部分惠普 MFP)

这些无法从描述符推断,只能一台台实测积累。printer_db.cpp 维护 VID:PID → 行为特征位 的表, 命中的机型会覆盖 config.h 的全局默认值。

特征位

标志 含义
Q_WANT_ESC_RESET 作业开头要发 ESC @(多数 ESC/P 爱普生、针式机)
Q_NO_ESC_RESET 千万别发 ESC @(HP 等 @PJL 流机型:发了会卡「正在打印文档」不出纸)
Q_NO_CTRL 完全不应答控制传输,禁发 Device ID / 字符串描述符 / 端口状态(Epson 1390)
Q_TAIL_NONE 作业结束什么都不补(PCLm / PDF / PS / PJL 系 —— 自带收尾标记,补任何东西都是又开一页)
Q_TAIL_FF 作业结束无条件补 FF(ESC/P、ESC/POS —— 流式格式没有收尾标记)
Q_NO_FAIL_RECOVER 禁止故障自愈序列(少数机型被收尾序列打死)
Q_NO_TEXT_TESTPAGE 禁用固件自带的纯文本测试页(主机型 PCLm / PCL3GUI / GDI 收下但既不渲染也不结束,会卡死到必须断电)
Q_VENDOR_IFACE 允许接管厂商私有(0xFF)批量接口(HP / Canon 已放行)
Q_NO_BIDIR 不回读 Bulk IN
Q_IPP_OVER_USB 已知 IPP-over-USB 设备(描述符哪怕不是标准 7/1/4)
Q_WANT_FORMFEED / Q_NO_FORMFEED 已废弃,见 Q_TAIL_NONE / Q_TAIL_FF
Q_NO_ZLP 不补零长度包(极少数老机)

两者都没写 = Q_TAIL_AUTO:按作业末尾字节自动判断(安全兜底)。

补录一台新机

  1. 插上打印机,访问 /api/status,记下 usb.vid / usb.pid / usb.protocol

  2. 在 printer_db.cpp 的 PROFILES 里加一行:

    {0x04B8, 0x9999, "Epson 某某机型", Q_NO_CTRL | Q_WANT_ESC_RESET | Q_TAIL_FF},

    PID 填 PID_ANY 表示对该厂商所有产品生效(厂商级行为,如 HP 全线禁 ESC @)

  3. 只填有实测依据的标志。没证据的机型不要乱标,让它走全局默认值更安全

  4. 改完重新编译 + OTA

⚠️ 补录时不要改 config.h 的全局默认值去迁就一台机器 —— 那会影响所有未登记的机型。 全局值只是「查不到该机型时的兜底」。

这张表是这个方案里最不容易被复制的部分:代码能开源,几百台真机的调校数据不行。


作业生命周期

:9100 同时只受理一个连接(有意为之:半路的 foreign language 数据流混进来会打印错位)。

客户端连接
  ├─ 15s 内没收到任何数据      → 判定空连接,丢弃(免重启自愈)
  ├─ 收到数据
  │    ├─ 全部字节成功下发 + TCP 静默 1.5s → 主动关闭,作业完成
  │    ├─ 传输失败 / 打印机断连           → _abortJob():标记失败 + 干净关连接 + 按机型复位
  │    ├─ 120s 没成功下发任何字节        → 判定打印机失联,释放通道
  │    ├─ 10 分钟未结束                  → 强制回收通道
  │    └─ 60s 双向都无收发               → 最终兜底断开
  └─ 通道被占用时的连接          → 立即拒绝并计数(stats.rejected)

为什么要「主动关闭」:RAW 9100 是字节流协议,没有长度字段也没有 EOJ 握手。 Windows 发完作业后会等服务端关闭 TCP,而旧固件在等 Windows 先关闭 —— 双方互等到 系统级超时(实测约 60 秒)。表现是队列长时间停在「正在打印」,后续作业全堵在后面。 v2.6.0 起,数据全量下发后 TCP 静默 JOB_DATA_IDLE_END_MS(默认 1500ms)就由服务端主动 FIN, Windows 队列约 2 秒内结束。

作业收尾策略按机型区分:驱动流的收尾标记各不相同,固件「好心」补的换页符反而会让打印机 永久等待下一页。

打印语言 驱动自带收尾 固件是否补 FF
PCLm / PDF %%EOF 不补
PCL5/6 + PJL UEL + @PJL EOJ 不补
PostScript 0x04 (Ctrl-D) 不补
ESC/P(爱普生 1390) 无 补
ESC/POS(票据机) 无 补

故障排查

现象 原因与处理
串口无 [USB] 输出 检查是不是用了普通充电线而不是 OTG 线;确认接在「USB」口不是「UART」口
打印机一直「未连接」、enumCount=0 先确认 ESP32 核心是 3.3.10(见安装核心)。升到 3.3.11 会这样,断电重启打印机、重插 USB 都无效。然后断电重启打印机、重插 USB
未找到可用打印接口 描述符里既没有标准打印机类也没有被放行的私有接口。到 /api/status 记 vid/pid,在 printer_db.cpp 补一行并加 Q_VENDOR_IFACE
型号显示为 VID:xxxx Device ID 读失败(该机型在库里配了 Q_NO_CTRL)。不影响打印
Windows 打印机显示离线 端口设置里取消勾选 SNMP
Windows 添加卡在查询中 直接点自定义,指定 Raw / 9100
macOS 队列暂停 手动点恢复,确认协议为 HP Jetdirect
打印乱码 驱动选错;或 TESTPAGE_PREPEND_ESC_RESET 与机型不匹配
打印用着用着失灵,重启才好 空连接占住了作业通道(Windows 双向探测、被取消作业留下的半开连接)。固件会自动回收,无需重启
固件测试页打不出来 主机型(GDI / PCL3GUI / PCLm)打印机只认官方驱动生成的数据流,纯文本测试页不会出纸 —— 这不算故障。这类机型网页上测试页按钮已自动隐藏。请用真实打印作业验证链路
HP 卡在「正在打印文档」不出纸 作业开头硬塞 ESC @ 会打乱 PJL 解析。JOB_RESET_ON_CONNECT 和 TESTPAGE_PREPEND_ESC_RESET 必须是 0(默认已是 0),且机型库已对 HP 全线置 Q_NO_ESC_RESET
打印机打完一直不结束,下一份要等很久 v2.6.0 已修(数据下发完 1.5 秒主动断连)。若仍出现,看串口有没有 [Print] 数据已全量下发,TCP 静默 XXXms,主动结束作业;另外检查 Windows 的「保留打印的文档」是否开着(会让已结束记录视觉上保留)
sent=0、USB 传输失败 status=0 打印机自身在拒收数据:缺粉 / 卡纸 / 残留卡住的作业 / 面板报错。断电重启打印机并检查耗材。固件侧只能快速失败保护,无法替打印机复位
打印到一半重复了好多份 Windows 后台在重试失败的作业。看 /api/status 的 stats.failedJobs 和 job.bytesSent 是否对不上 —— 一般是打印机侧先出问题,不是固件
打印机出问题时网页/API 卡住 v2.4.0:主循环被批量传输占住。 v2.5.0 起打印服务已独立成 FreeRTOS 任务,管理页始终可用
bootCount 持续增长 板子在崩溃循环。先把打印机物理拔掉,等 uptime 稳定上涨后再 OTA。/api/debug 能看到 lastCrashStage / stageLine
OTA 失败 / 403 default-password 还在用出厂密码 admin/admin,先登录改密码
忘了我设的管理员密码 长按 BOOT 键 10 秒清空密码(串口会打印提示)
换路由器 / 改 WiFi 密码后失联 等 3 分钟,设备自动开 PrintServer-Setup 热点,连上去重新配置
WiFi 连着但打印很卡、时断时续 看「网络 → 近 1 分钟最差信号」。长期低于 -75 dBm 请挪近或加中继;WIFI_DISABLE_SLEEP 保持 1
重新连上 WiFi 后打印机变离线 固件会自动重建 mDNS 与 :9100 监听。仍异常就看 wifi.disconnects 是否增长,必要时手动重启
printserver.local 无法访问 Windows 缺 mDNS,直接用 IP
Arduino IDE 看不到网络端口 装 Bonjour Print Services

配置参数

编辑 config.h。

⚠️ 下面带 JOB_ / ENABLE_ / USB_ 前缀的打印相关项只是「查不到该机型时的全局默认值」。 printer_db.cpp 里登记过的机型以库中的 Q_* 标志为准。要改某台机器的行为,改库不要改这里。

身份与网络

参数 默认 说明
FW_VERSION 2.6.0 固件版本
PRINTER_NAME ESP32_PrintServer 设备标识名
MDNS_HOSTNAME printserver mDNS 主机名,浏览器用 http://printserver.local
RAW_SOCKET_PORT 9100 JetDirect / AppSocket 打印端口
AP_SSID / AP_PASSWORD PrintServer-Setup / 12345678 配网热点

USB

参数 默认 说明
USB_XFER_CHUNK 8192 单次 USB 批量传输大小
USB_XFER_TIMEOUT_MS 30000 单块传输等待上限(打印机走纸时会 NAK,要留余量)
PRINT_CHUNK 16384 每次从 TCP 取多少字节交给 USB
PRINT_BUFFER_SIZE 256 * 1024 PSRAM 打印缓冲
STATUS_POLL_MS 2000 IEEE 1284 端口状态轮询间隔
ENABLE_BIDIR_PASSTHROUGH 1 读 Bulk IN 并把应答回写 TCP
USB_RX_BUFFER_SIZE 4 * 1024 IN 端点回读环形缓冲
ENABLE_PORT_STATUS_POLL 0 IEEE1284 端口状态查询。保持 0:不少 GDI 机型对它长时间 NAK,而本 IDF 版本 timeout_ms 无效、EP0 无取消接口,会留下永久悬挂的传输

故障自愈

参数 默认 说明
USB_RECOVER_ENABLED 1 传输失败时自动尝试拉回打印机(halt 端点 → SOFT_RESET → 收尾序列)
USB_RECOVER_AFTER 1 连续几次无回调就触发。必须为 1:某块写失败后立刻 break 结束作业,"连续 2 次"在同一份作业里永远凑不满
USB_RECOVER_MAX_PER_JOB 2 单份作业最多自愈几次
USB_RECOVER_MAX_WAIT_MS 1200 自愈各步骤等待上限
USB_RECOVER_RETRY 1 自愈后原地重试失败的那块
USB_STALL_MAX_TIMEOUTS 3 连续几次无回调判定打印机失联
USB_STALL_COOLDOWN_MS 15000 冷却时长,期间新作业立刻失败返回,保住网页响应

作业生命周期

参数 默认 说明
JOB_NODATA_TIMEOUT_MS 15000 连上后一直没数据 → 判定空连接自动断开
JOB_DATA_IDLE_END_MS 1500 数据全量下发后 TCP 静默多久即判定作业结束并主动断连(v2.6.0 新增,修 Windows 队列 60 秒不结束)
JOB_IDLE_TIMEOUT_MS 60000 异常连接最终兜底。必须大于 USB_XFER_TIMEOUT_MS
JOB_TX_STALL_MS 120000 作业期内这么久没成功下发过任何字节 → 释放通道
JOB_MAX_DURATION_MS 600000 单作业最长占用通道 10 分钟
JOB_RESET_ON_CONNECT 0 作业开头发 ESC @。Epson 可设 1,HP 必须 0
JOB_APPEND_FORMFEED 1 作业结束补 FF。PCLm / PS / PJL 系必须 0
TESTPAGE_PREPEND_ESC_RESET 0 ESC/P 机型可设 1;PCL / PS / HP 必须 0

任务与看门狗

参数 默认 说明
PRINT_TASK_CORE 0 打印任务跑在哪个核心(loop() 在 core1,分离才真正并行)
PRINT_TASK_PRIORITY / _STACK_SIZE 2 / 8192
USB_HOST_TASK_PRIORITY / _STACK_SIZE 5 / 10240 栈不能低于 10240
WDT_TIMEOUT_SEC 60
LED_PIN 2 无外接 LED 也不影响功能

WiFi

参数 默认 说明
WIFI_DISABLE_SLEEP 1 关掉 modem sleep。强烈建议保持 1,节能模式会造成数百毫秒延迟抖动
WIFI_RETRY_MIN_MS / _MAX_MS 5000 / 60000 重连退避上下限
WIFI_REASSOC_AFTER 3 失败几次后升级为完整重新关联
WIFI_DRIVER_RESET_AFTER 8 再失败几次后复位 WiFi 驱动
WIFI_FALLBACK_AP_MS 180000 离线多久后开后备配网 AP(0 关闭)
WIFI_RSSI_SAMPLE_MS / _HISTORY 2000 / 30 信号采样间隔与保留点数(约 1 分钟)

安全

参数 默认 说明
AUTH_ENABLED 1 调试时可临时置 0
AUTH_DEFAULT_USER / _PASS admin / admin 出厂账号密码,登录后强制修改
AUTH_PASS_MIN_LEN / _MAX_LEN 4 / 32
AUTH_SESSION_TIMEOUT_MS 2h 会话空闲过期
AUTH_MAX_SESSIONS 6 并发会话上限。槽位满时淘汰最久没活动的那个,不会被拒绝
AUTH_MAX_FAILS 5 连续输错几次开始锁定(指数退避,上限 30 分钟)
AUTH_FACTORY_RESET_PIN 0 长按该 GPIO 10 秒清空管理员密码,-1 关闭
OTA_PASSWORD 空 建议设置,否则局域网内谁都能刷机

内存

参数 默认 说明
HEAP_GUARD_ENABLE 1
HEAP_GUARD_MIN_KB / _HOLD_MS 24 / 30000 堆低于该值并持续这么久 → 空闲时自动重启,防碎片化变永久故障

文件结构

ESP32S3_PrintServer_v2/
├── ESP32S3_PrintServer_v2.ino  主程序入口(setup / loop / 全局对象)
├── config.h                    配置参数(机型库未命中时的全局默认值)
├── printer_db.h / .cpp         机型行为特征库(VID:PID → Q_* 标志)
├── usb_printer.h / .cpp        USB Host 打印机驱动(枚举、匹配、传输、自愈、回读)
├── print_server.h / .cpp       Raw Socket 9100 服务器(独立 FreeRTOS 任务)
├── web_ui.h / .cpp             网页管理界面 + HTTP API + 登录鉴权接入
├── wifi_manager.h / .cpp       WiFi 配网 / 三级重连 / 退避 / 后备 AP / 信号采样
├── auth.h / .cpp               管理员鉴权(SHA-256 加盐、会话、暴力破解锁定)
├── crashlog.h / .cpp           崩溃日志(RTC 内存,重启后经 /api/debug 读出)
├── LICENSE                     MIT
└── README.md

已知限制

  1. 单作业通道。:9100 同时只受理一个连接(有意设计)。打印期间状态查询连接会被拒绝。 排 N 份作业时建议在 Windows 端口里取消勾选「启用双向支持」。
  2. 打印机内部死锁无法软件复位。当打印机自身的固件 / FIFO 卡死(sent=0、USB 传输失败 status=0 且面板报错),固件能做的只是快速失败保护 —— 端点 halt/flush/clear、SOFT_RESET、收尾序列 对这类情况实测无效。目前只能断电重启打印机。 要根治需要 USB 设备句柄重枚举 或可控 VBUS 的硬件兜底,尚未实现。
  3. ESP32-S3 只有 Full-Speed 12Mbps,实测吞吐 0.6–1 MB/s。高速打印机 / 大幅面照片会很慢。 升级路径是 ESP32-P4(内置 USB High-Speed PHY,480Mbps)。
  4. 主机型打印机不支持手机免驱。见先看这个。
  5. IPP-over-USB 只识别不代理。能认出 7/1/4 接口,但不做 IPP 请求代理。

版本历史

v2.6.0

  • 打印队列秒级结束。数据全量下发后 TCP 静默 1.5s 即主动断连,根治 Windows/macOS 队列「打完半天不结束、下一份要等很久」(原先双方互等约 60 秒)
  • 作业收尾策略按机型区分(Q_TAIL_NONE / Q_TAIL_FF)
  • 异常路径不再发禁忌的 ESC @(_resetPrinter() 统一遵守机型库)
  • 主机型打印机禁用纯文本测试页

v2.5.9

  • HP 加 Q_NO_FAIL_RECOVER,停止执行实测无效、反而污染打印机状态的恢复序列

v2.5.7

  • 作业收尾策略从「一刀切补 FF」改为按机型 + 作业尾部字节自描述判断

v2.5.1

  • 登录会话不再会把管理员关在门外:槽位满时淘汰最久未活动的会话,登录永不被拒绝
  • 打印通道看门狗:120s 无成功下发 → 释放通道;单作业 10 分钟强制回收
  • 打印任务独立成 FreeRTOS 任务后再无 WDT 重启

v2.5.0

  • 管理员登录:所有写操作都要登录,SHA-256 加盐存 NVS,HttpOnly Cookie,会话令牌,指数退避锁定
  • 打印服务搬出 loop(),独立 FreeRTOS 任务 + 独立核心。打印机「叫不应」不再锁死管理页
  • 网页触发的阻塞操作(测试页 / 软复位)改为异步
  • WiFi 三级重连 + 指数退避 + 关闭 modem sleep
  • 长时间离线自动开后备 AP
  • 断链自愈:WiFi 重连后自动重建 mDNS 与 :9100
  • 双向回读写保护、内存自愈

v2.4.0

  • 机型行为特征库(printer_db.cpp)—— 本方案商业化的核心资产
  • USB 接口匹配改为多级打分,放行惠普 MFP 非标准 255/9/1(依据 Linux ipp-usb 源码), 显式排除 HID / MSC / Imaging 等搭车接口
  • 双向回读:常驻 Bulk IN + 环形缓冲 → 写回 TCP
  • 打印机快速失败保护(USB_STALL_*)

更早

见 git log。


许可证

MIT License — 详见 LICENSE

致谢

基于 ESP-IDF USB Host 栈与 Arduino-ESP32 核心实现。 接口打分策略参考了 Linux ipp-usb 项目对惠普 MFP 非标准接口组合的处理。

About

ESP32-S3 WiFi Print Server — turns any USB printer into a network printer via Raw Socket :9100. Web UI + OTA + mDNS.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages