Initial commit: ESP32-C3 WiFi→BLE bridge for Phomemo M110
- BLE client (NimBLE) with auto-scan/reconnect - ESC/POS protocol encoder (GS v 0 raster) - Web API: /api/status, /api/connect, /api/print - Web UI: image upload with dithering, QR codes, positioning - Client-side QR generation (qrcode-generator) - Supports bitmap, QR, and raw ESC/POS print types
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
# ESP32 M110 Label Printer Bridge
|
||||
|
||||
WiFi → BLE Bridge für den **Phomemo M110** Bluetooth-Etikettendrucker.
|
||||
Läuft auf **ESP32-C3** (PlatformIO / Arduino).
|
||||
|
||||
## Hardware
|
||||
|
||||
- **ESP32-C3** DevKit (oder kompatibel mit WiFi + BLE)
|
||||
- **Phomemo M110** Etikettendrucker (203 dpi, 48mm Druckbreite)
|
||||
|
||||
## Quickstart
|
||||
|
||||
### 1. Konfiguration
|
||||
|
||||
WiFi-Zugangsdaten und BLE-Name des Druckers in `platformio.ini` eintragen:
|
||||
|
||||
```ini
|
||||
build_flags = -std=gnu++17 -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DWIFI_SSID='"MeinWLAN"'
|
||||
-DWIFI_PASS='"MeinPasswort"'
|
||||
-DPRINTER_BLE_NAME='"Q199G4180950002"'
|
||||
```
|
||||
|
||||
Den BLE-Namen findest du auf dem Etikett auf der Drucker-Rückseite.
|
||||
|
||||
### 2. Build & Flash
|
||||
|
||||
```bash
|
||||
pio run -t upload # Firmware
|
||||
pio run -t uploadfs # Web-Interface (LittleFS)
|
||||
```
|
||||
|
||||
### 3. Verwenden
|
||||
|
||||
Web-Interface unter `http://<esp32-ip>/` öffnen.
|
||||
|
||||
Oder per curl:
|
||||
|
||||
```bash
|
||||
# Status
|
||||
curl http://192.168.1.100/api/status
|
||||
|
||||
# QR-Code drucken (106×106px, zentriert)
|
||||
curl -X POST http://192.168.1.100/api/print \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"qr","data":"https://techahead.de","scale":4}'
|
||||
|
||||
# Bild drucken (1-Bit Bitmap als Base64)
|
||||
curl -X POST http://192.168.1.100/api/print \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"bitmap","data":"...","width":384,"height":200,"density":15,"offsetX":0}'
|
||||
|
||||
# BLE-Scan starten
|
||||
curl -X POST http://192.168.1.100/api/connect
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
| Endpoint | Methode | Beschreibung |
|
||||
|----------|---------|-------------|
|
||||
| `/` | GET | Web-Interface |
|
||||
| `/api/status` | GET | JSON: WiFi, BLE, Drucker-Status |
|
||||
| `/api/connect` | POST | BLE-Scan starten |
|
||||
| `/api/print` | POST | Druckauftrag |
|
||||
|
||||
### POST /api/print
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "qr",
|
||||
"data": "https://example.com",
|
||||
"scale": 4,
|
||||
"offsetX": 0
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "bitmap",
|
||||
"data": "<base64>",
|
||||
"width": 384,
|
||||
"height": 200,
|
||||
"density": 15,
|
||||
"offsetX": 0
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "raw",
|
||||
"data": "<base64-ESC/POS-bytes>"
|
||||
}
|
||||
```
|
||||
|
||||
## Web-Interface
|
||||
|
||||
- **🖼️ Bild drucken:** Upload per Drag & Drop, Vorschau mit B/W-Dithering (Atkinson, Floyd-Steinberg, Schwellwert), Positionierung auf 48mm-Band, einstellbare Druckdichte
|
||||
- **📱 QR-Code:** Text/URL eingeben, Skalierung, Positionierung. QR wird client-seitig generiert — Vorschau = Druckergebnis
|
||||
- **Status:** WiFi/BLE-Verbindung, RSSI, Uptime
|
||||
|
||||
## M110 BLE Protokoll
|
||||
|
||||
- **Service UUID:** `0000FF00-0000-1000-8000-00805F9B34FB`
|
||||
- **Write Characteristic:** `0000FF02-0000-1000-8000-00805F9B34FB`
|
||||
- **Verbindung:** Per advertised name, kein Pairing
|
||||
- **Protokoll:** ESC/POS `GS v 0` Raster-Bitmap
|
||||
- **Auflösung:** 384px (48mm) @ 203dpi → 48 Bytes/Zeile
|
||||
- **Esc/POS-Kommandos:**
|
||||
- `ESC @` — Drucker initialisieren
|
||||
- `ESC N 0x0D <speed>` — Druckgeschwindigkeit (1–5)
|
||||
- `ESC N 0x04 <density>` — Druckdichte (1–15)
|
||||
- `GS DC1 <type>` — Medientyp (0x0A=LabelWithGaps, 0x0B=Continuous)
|
||||
- `GS v 0 <xL><xH><yL><yH> <data>` — Raster-Bitmap (max 240 Zeilen empfohlen)
|
||||
- `GS F0 05 00` / `GS F0 03 00` — Footer
|
||||
|
||||
Das Protokoll basiert auf Reverse-Engineering von [phomemo-tools](https://github.com/vivier/phomemo-tools) und [phomemo-macos](https://github.com/jacquesg/phomemo-macos).
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
esp32-m110-label/
|
||||
├── platformio.ini # PlatformIO Config
|
||||
├── private_config.ini.example # Vorlage für Credentials
|
||||
├── README.md
|
||||
├── src/
|
||||
│ ├── main.cpp # WiFi, HTTP-API, Setup
|
||||
│ ├── config.h # UUIDs, Konstanten
|
||||
│ ├── printer.h # M110 ESC/POS Encoder
|
||||
│ ├── ble_client.h # NimBLE Scanner + Connection Manager
|
||||
│ └── qr_renderer.h # QR-Code → Bitmap Renderer
|
||||
└── data/
|
||||
├── index.html # Web-Interface
|
||||
└── qrcode.min.js # QR-Code Generator (client-side)
|
||||
```
|
||||
|
||||
## Libraries
|
||||
|
||||
- [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino) — BLE Stack (ESP32-C3 optimiert)
|
||||
- [ESPAsyncWebServer](https://github.com/esphome/ESPAsyncWebServer) — Async HTTP Server
|
||||
- [ArduinoJson](https://arduinojson.org/) — JSON Parsing
|
||||
- [QRCode](https://github.com/ricmoo/QRCode) — QR-Code Generation (ESP32, optional)
|
||||
- [qrcode-generator](https://github.com/kazuhikoarase/qrcode-generator) — QR-Code Generation (Client/JS)
|
||||
|
||||
## Lizenz
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user