# ESP32-S3 LYF Printer Controller (Wi-Fi REST API) ESP32-S3 works as a Wi-Fi REST controller and replaces Android App logic: - REST client -> ESP32-S3 (`esp_http_server`) - ESP32-S3 -> BLE printer (`lyfPrinter`, `FFF2` write / `FFF1` notify) - Command compatibility: - Print path: `0x00~0x07` - OTA path: `0xA0~0xA4` ## Features - Wi-Fi STA-only mode (configured SSID/password; no SoftAP fallback) - Built-in web UI at `/` for connect/status, text print, and image upload print - BLE central client auto-scan/connect to printer name - Async print queue with jobs (`queued/running/success/failed/canceled`) - Printer precheck (paper / battery / temperature) - Built-in UTF-8 text rendering with Chinese support (GB2312 character set, 16x16 bitmap) - Android-compatible print flow: - `0x00` power on - `0x03` set print param - `0x04` chunked raster send + ACK - `0x00` power off - `0x02` feed paper - REST APIs: - Health/connection: - `GET /v1/health` - `POST /v1/printer/connect` - `POST /v1/printer/disconnect` - `GET /v1/printer/status` - Print: - `POST /v1/print/raster` - `POST /v1/print/image` (`base64_msb_1bpp` or `base64_gray8`) - `POST /v1/print/qr` - `POST /v1/print/text` - `POST /v1/print/receipt` - `POST /v1/print/label` - Jobs: - `GET /v1/jobs` - `DELETE /v1/jobs` - `GET /v1/jobs/{id}` - `DELETE /v1/jobs/{id}` - Label control: - `POST /v1/label/gap_move` - `GET /v1/label/offset` - `POST /v1/label/offset` - OTA: - `GET /v1/ota/version` - `POST /v1/ota/jump_boot` - `POST /v1/ota/jump_app` - `POST /v1/ota/erase_page` - `POST /v1/ota/write_frame` - `POST /v1/ota/upgrade` ## Build Prerequisites: - ESP-IDF v5.x - ESP32-S3 board ```bash cd ai_printer idf.py set-target esp32s3 idf.py menuconfig idf.py build ``` ## Config In `menuconfig -> LYF Controller Config`: - `LYF_WIFI_SSID` - `LYF_WIFI_PASSWORD` - `LYF_HTTP_PORT` - `LYF_API_KEY` (optional) When `LYF_API_KEY` is not empty, each request must include: ```text X-API-Key: ``` STA-only behavior: - If SSID is empty, startup fails. - If STA connect fails, startup fails (no AP fallback). ## Flash ```bash cd ai_printer idf.py -p /dev/tty.usbmodemXXXX flash monitor ``` ## Web UI Open the controller IP in a browser: ```text http:/// ``` The page provides: - health/status check - connect/disconnect printer - submit a simple text print job - upload an image (gray8 payload) and let ESP32-S3 handle threshold/scale/raster conversion - view jobs list If API key is enabled, input it in the page before invoking actions. ## REST Examples ### Health ```bash curl http:///v1/health ``` ### Connect printer ```bash curl -X POST http:///v1/printer/connect \ -H 'Content-Type: application/json' \ -d '{"name":"lyfPrinter","timeout_ms":15000}' ``` Auto-match a compatible printer (by BLE service `0xFFF0`): ```bash curl -X POST http:///v1/printer/connect \ -H 'Content-Type: application/json' \ -d '{"name":"*","timeout_ms":20000}' ``` ### Raster print ```bash curl -X POST http:///v1/print/raster \ -H 'Content-Type: application/json' \ -d '{ "width":384, "height":200, "density":"中等", "encoding":"base64_msb_1bpp", "data":"" }' ``` ### Image print (gray8 auto-scale to 384) ```bash curl -X POST http:///v1/print/image \ -H 'Content-Type: application/json' \ -d '{ "width":800, "height":600, "encoding":"base64_gray8", "data":"", "scale_to_width":true, "threshold":160, "density":"中等" }' ``` ### QR print ```bash curl -X POST http:///v1/print/qr \ -H 'Content-Type: application/json' \ -d '{ "text":"https://example.com/pay/123", "ecc":"H", "module_scale":0, "margin_modules":2, "density":"中等" }' ``` ### Text print ```bash curl -X POST http:///v1/print/text \ -H 'Content-Type: application/json' \ -d '{ "text":"欢迎使用LYF打印机\\n订单号: A1024\\n谢谢惠顾", "density":"中等", "scale":2, "line_spacing":2, "max_height":1800 }' ``` ### Receipt print ```bash curl -X POST http:///v1/print/receipt \ -H 'Content-Type: application/json' \ -d '{ "title":"LYF FOOD", "density":"中等", "footer":"Thanks!", "items":[ {"name":"DishA","qty":2,"price":12.5}, {"name":"DishB","qty":1,"price":8.0} ] }' ``` ### Label print (with optional gap/offset) ```bash curl -X POST http:///v1/print/label \ -H 'Content-Type: application/json' \ -d '{ "width":384, "height":260, "encoding":"base64_msb_1bpp", "data":"", "gap_move_before":true, "offset_tenths_mm":128, "density":"中等" }' ``` ### Jobs ```bash curl http:///v1/jobs curl http:///v1/jobs/1 curl -X DELETE http:///v1/jobs/1 curl -X DELETE http:///v1/jobs -d '{"include_success":true,"include_failed":true,"include_canceled":true}' ``` ### Label control ```bash curl -X POST http:///v1/label/gap_move curl http:///v1/label/offset curl -X POST http:///v1/label/offset \ -H 'Content-Type: application/json' \ -d '{"offset_tenths_mm":128}' ``` ### OTA primitives ```bash curl http:///v1/ota/version curl -X POST http:///v1/ota/jump_boot curl -X POST http:///v1/ota/erase_page -H 'Content-Type: application/json' -d '{"page_num":0}' curl -X POST http:///v1/ota/write_frame -H 'Content-Type: application/json' -d '{"packet_num":0,"is_last_frame":false,"data":""}' curl -X POST http:///v1/ota/jump_app ``` ### OTA full upgrade ```bash curl -X POST http:///v1/ota/upgrade \ -H 'Content-Type: application/json' \ -d '{ "firmware":"", "jump_boot":true, "jump_app":true, "page_size":1024, "packet_size":236, "timeout_ms_per_step":5000 }' ``` ## Notes - BLE side is central/client role, not printer peripheral role. - `base64_msb_1bpp` uses Android-compatible bit order (MSB first). - `/v1/print/text` and `/v1/print/receipt` now support UTF-8 Chinese via embedded 16x16 GB2312 glyphs. - Characters outside embedded glyph set are rendered as square fallback boxes. - QR encoding uses embedded `qrcodegen` (Project Nayuki C implementation). ## Font Assets Embedded files: - `main/domain/assets/fonts/cn16_index.bin` - `main/domain/assets/fonts/cn16_glyphs.bin` Regenerate from your own CJK font: ```bash cd ai_printer python3 -m pip install --user pillow python3 tools/gen_cn16_font.py \ --font app/src/main/assets/fonts/msyh.ttc \ --font-index 0 ```