Kasir/Documentation/NiimbotPrinter-FlowChart.md
Baghaztra 8665584567 [Update] print label
Library niimblue tidak digunakan, namun potongan kode tetap disimpan
2025-10-15 14:33:47 +07:00

37 KiB
Raw Permalink Blame History

📊 Diagram Alur Kerja Printer Niimbot

🔄 Alur Lengkap: Dari UI ke Printer

graph TD
    A[User buka halaman Brankas] --> B{Printer sudah<br/>terhubung?}
    B -->|Tidak| C[Klik 'Hubungkan Printer']
    B -->|Ya| D[Status: Terhubung]
    
    C --> E[Modal NiimbotConnector muncul]
    E --> F{Pilih metode koneksi}
    F -->|Bluetooth| G[Klik 'Hubungkan Printer']
    F -->|USB/Serial| G
    
    G --> H[Browser: Dialog pairing muncul]
    H --> I[User pilih Niimbot device]
    I --> J[Library: initClient & connect]
    
    J --> K{Koneksi<br/>berhasil?}
    K -->|Tidak| L[Tampilkan error]
    K -->|Ya| M[Fetch printer info]
    
    M --> N[Status: Terhubung ✓]
    N --> D
    
    D --> O[User klik item di Brankas]
    O --> P[Modal item muncul]
    P --> Q[Generate QR Code URL]
    Q --> R[Tampilkan preview QR]
    
    R --> S[User klik 'Cetak ke Niimbot']
    S --> T{Printer<br/>terhubung?}
    
    T -->|Tidak| U[Alert: Hubungkan printer]
    U --> C
    
    T -->|Ya| V[createQRLabelCanvas]
    V --> W[Load QR image]
    W --> X[Draw ke canvas:<br/>QR + Kode + Nama + Berat]
    X --> Y[Convert canvas to DataURL]
    
    Y --> Z[printQRCode composable]
    Z --> AA[Stop heartbeat]
    AA --> AB[Create PrintTask]
    AB --> AC[ImageEncoder.encodeCanvas]
    AC --> AD[printTask.printInit]
    AD --> AE[printTask.printPage]
    
    AE --> AF{Print<br/>sukses?}
    AF -->|Tidak| AG[Tampilkan error]
    AF -->|Ya| AH[printTask.printEnd]
    
    AH --> AI[Start heartbeat]
    AI --> AJ[Alert: Berhasil dicetak!]
    AJ --> AK[Printer cetak label]

🏗️ Arsitektur Komponen

┌─────────────────────────────────────────────────────────────┐
│                      BrankasList.vue                        │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  UI Layer                                              │ │
│  │  - Tombol "Hubungkan Printer"                         │ │
│  │  - Tombol "Cetak ke Niimbot"                          │ │
│  │  - Modal item dengan QR Code                          │ │
│  └────────────────────────────────────────────────────────┘ │
│                           │                                  │
│                           ▼                                  │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Logic Layer                                           │ │
│  │  - printQR()              → Trigger print              │ │
│  │  - createQRLabelCanvas()  → Generate canvas dengan QR  │ │
│  │  - handlePrinterConnected() → Event handler           │ │
│  └────────────────────────────────────────────────────────┘ │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│              useNiimbotPrinter.js (Composable)              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  State Management                                      │ │
│  │  - printerClient (reactive)                           │ │
│  │  - connectionState                                     │ │
│  │  - isPrinting, printProgress                          │ │
│  └────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Methods                                               │ │
│  │  - initClient()    → Buat NiimbotClient               │ │
│  │  - connect()       → Hubungkan ke printer             │ │
│  │  - disconnect()    → Putuskan koneksi                 │ │
│  │  - printQRCode()   → Print image ke printer           │ │
│  └────────────────────────────────────────────────────────┘ │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│            @mmote/niimbluelib (Library)                     │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  NiimbotBluetoothClient / NiimbotSerialClient         │ │
│  │  - connect()          → Web Bluetooth/Serial API      │ │
│  │  - fetchPrinterInfo() → Get printer metadata          │ │
│  │  - startHeartbeat()   → Maintain connection           │ │
│  └────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  PrintTask                                             │ │
│  │  - newPrintTask()     → Buat task print               │ │
│  │  - printInit()        → Inisialisasi print            │ │
│  │  - printPage()        → Kirim data gambar             │ │
│  │  - waitForFinished()  → Tunggu selesai                │ │
│  │  - printEnd()         → Akhiri print                  │ │
│  └────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  ImageEncoder                                          │ │
│  │  - encodeCanvas()     → Encode canvas ke binary       │ │
│  └────────────────────────────────────────────────────────┘ │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│                  Browser Web APIs                           │
│  - Web Bluetooth API  (navigator.bluetooth)                 │
│  - Web Serial API     (navigator.serial)                    │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│                  Printer Niimbot (Hardware)                 │
│  - Terima perintah via BLE/USB                              │
│  - Decode binary image data                                 │
│  - Print ke label thermal                                   │
└─────────────────────────────────────────────────────────────┘

📡 Sequence Diagram: Proses Print

User          BrankasList    useNiimbot    niimbluelib    Browser API    Printer
 │                │              │              │              │            │
 │  Klik item     │              │              │              │            │
 ├───────────────>│              │              │              │            │
 │                │              │              │              │            │
 │  Modal muncul  │              │              │              │            │
 │<───────────────┤              │              │              │            │
 │                │              │              │              │            │
 │  Klik 'Cetak'  │              │              │              │            │
 ├───────────────>│              │              │              │            │
 │                │              │              │              │            │
 │                │ printQRCode()│              │              │            │
 │                ├─────────────>│              │              │            │
 │                │              │              │              │            │
 │                │              │ stopHeartbeat()             │            │
 │                │              ├─────────────>│              │            │
 │                │              │              │              │            │
 │                │              │ newPrintTask()              │            │
 │                │              ├─────────────>│              │            │
 │                │              │              │              │            │
 │                │              │ encodeCanvas()              │            │
 │                │              ├─────────────>│              │            │
 │                │              │              │              │            │
 │                │              │              │ BLE/Serial   │            │
 │                │              │              │ Write Data   │            │
 │                │              │              ├─────────────>│            │
 │                │              │              │              │            │
 │                │              │              │              │  Send Data │
 │                │              │              │              ├───────────>│
 │                │              │              │              │            │
 │                │              │              │              │  Printing  │
 │                │              │              │              │  ........  │
 │                │              │              │              │            │
 │                │              │              │  Status ACK  │            │
 │                │              │              │<─────────────┤            │
 │                │              │              │              │            │
 │                │              │ printEnd()   │              │            │
 │                │              ├─────────────>│              │            │
 │                │              │              │              │            │
 │                │              │ startHeartbeat()            │            │
 │                │              ├─────────────>│              │            │
 │                │              │              │              │            │
 │                │ Alert sukses │              │              │            │
 │                │<─────────────┤              │              │            │
 │                │              │              │              │            │
 │  Label tercetak│              │              │              │            │
 │<───────────────┴──────────────┴──────────────┴──────────────┴────────────┤
 │                                                                           │

🔌 Connection Flow Detail

Bluetooth Connection

1. User Action
   └─> Klik "Hubungkan Printer"

2. initClient('bluetooth')
   └─> new NiimbotBluetoothClient()

3. connect()
   └─> navigator.bluetooth.requestDevice({
        filters: [{ namePrefix: 'Niimbot' }],
        optionalServices: [SERVICE_UUID]
      })

4. Browser Dialog
   └─> User pilih device "Niimbot-XXXX"

5. device.gatt.connect()
   └─> Establish BLE connection

6. getPrimaryService(SERVICE_UUID)
   └─> getCharacteristic(TX_CHAR, RX_CHAR)

7. Event: 'connect' triggered
   └─> connectionState = 'connected'

8. fetchPrinterInfo()
   └─> Send command: GET_INFO
   └─> Receive: model, serial, firmware version

9. startHeartbeat()
   └─> Kirim ping setiap 1 detik
   └─> Cek printer masih hidup

USB/Serial Connection

1. User Action
   └─> Klik "Hubungkan Printer"

2. initClient('serial')
   └─> new NiimbotSerialClient()

3. connect()
   └─> navigator.serial.requestPort({
        filters: [{ usbVendorId: 0xXXXX }]
      })

4. Browser Dialog
   └─> User pilih USB device

5. port.open({ baudRate: 9600 })
   └─> Establish serial connection

6. Setup reader/writer streams
   └─> readable.getReader()
   └─> writable.getWriter()

7. Event: 'connect' triggered
   └─> connectionState = 'connected'

8. fetchPrinterInfo() & startHeartbeat()
   └─> (sama dengan Bluetooth)

🖼️ Image Processing Pipeline

QR Code URL (dari API)
      │
      ▼
  new Image()
      │
      ▼
  img.onload
      │
      ▼
Create Canvas (384x384)
      │
      ├─> Fill white background
      │
      ├─> drawImage(qr, x, y, size, size)
      │
      ├─> fillText(kode_item)
      │
      ├─> fillText(nama_produk)
      │
      ├─> fillText(berat)
      │
      ▼
canvas.toDataURL('image/png')
      │
      ▼
loadImageToCanvas(dataUrl)
      │
      ▼
[Optional] applyThreshold(canvas, 140)
      │
      ├─> getImageData()
      │
      ├─> for each pixel:
      │     avg = (r+g+b)/3
      │     if avg < 140: black
      │     else: white
      │
      ├─> putImageData()
      │
      ▼
ImageEncoder.encodeCanvas(canvas, 'top')
      │
      ├─> Convert to 1-bit bitmap
      │
      ├─> Rotate if needed (printDirection)
      │
      ├─> Pack bits: 8 pixels = 1 byte
      │
      ▼
Binary Data (EncodedImage)
      │
      ▼
printTask.printPage(encoded, quantity)
      │
      ▼
Send to Printer via BLE/Serial

📊 State Machine Diagram

┌─────────────────┐
│  DISCONNECTED   │◄────────┐
└────────┬────────┘         │
         │                  │
         │ connect()        │ disconnect()
         │                  │
         ▼                  │
┌─────────────────┐         │
│   CONNECTING    │         │
└────────┬────────┘         │
         │                  │
         │ success          │ error
         │                  │
         ▼                  │
┌─────────────────┐         │
│    CONNECTED    │─────────┤
└────────┬────────┘         │
         │                  │
         │ printQRCode()    │
         │                  │
         ▼                  │
┌─────────────────┐         │
│    PRINTING     │         │
│  [progress: X%] │         │
└────────┬────────┘         │
         │                  │
         │ finished         │
         │                  │
         ▼                  │
┌─────────────────┐         │
│    CONNECTED    │─────────┘
│   (heartbeat)   │
└─────────────────┘

🎯 Data Flow: QR Code → Printed Label

┌────────────────────────────────────────────────────────────┐
│  1. DATA SOURCE                                            │
│  ─────────────────────────────────────────────────────────│
│  selectedItem = {                                          │
│    kode_item: "BRN-001",                                  │
│    produk: {                                               │
│      nama: "Cincin Emas 24K",                             │
│      berat: 5.2                                            │
│    }                                                        │
│  }                                                          │
└────────────────────────────────────────────────────────────┘
                         │
                         ▼
┌────────────────────────────────────────────────────────────┐
│  2. QR CODE GENERATION (External API)                      │
│  ─────────────────────────────────────────────────────────│
│  URL: https://api.qrserver.com/v1/create-qr-code/         │
│       ?size=150x150&data=BRN-001                          │
│                                                             │
│  Returns: image/png (base64 or URL)                       │
└────────────────────────────────────────────────────────────┘
                         │
                         ▼
┌────────────────────────────────────────────────────────────┐
│  3. CANVAS CREATION                                        │
│  ─────────────────────────────────────────────────────────│
│  createQRLabelCanvas(qrUrl, item)                         │
│                                                             │
│  Canvas 384x384px:                                         │
│  ┌──────────────────────┐                                 │
│  │                      │                                  │
│  │    ┌──────────┐     │  ← QR Code (200x200)            │
│  │    │ ▓▓  ▓▓▓▓│     │                                  │
│  │    │▓  ▓▓  ▓ │     │                                  │
│  │    │ ▓▓▓  ▓▓▓│     │                                  │
│  │    └──────────┘     │                                  │
│  │                      │                                  │
│  │     BRN-001         │  ← Kode Item (bold 18px)        │
│  │  Cincin Emas 24K    │  ← Nama Produk (14px)           │
│  │      5.2g           │  ← Berat (12px)                 │
│  │                      │                                  │
│  └──────────────────────┘                                 │
└────────────────────────────────────────────────────────────┘
                         │
                         ▼
┌────────────────────────────────────────────────────────────┐
│  4. IMAGE ENCODING                                         │
│  ─────────────────────────────────────────────────────────│
│  ImageEncoder.encodeCanvas(canvas, 'top')                 │
│                                                             │
│  Process:                                                   │
│  - Convert RGB to grayscale                                │
│  - Apply threshold (< 140 = black, >= 140 = white)        │
│  - Pack 8 pixels into 1 byte (1-bit bitmap)               │
│  - Width: 384px = 48 bytes per row                        │
│  - Height: 384 rows                                        │
│  - Total: 48 × 384 = 18,432 bytes                         │
│                                                             │
│  Output: Uint8Array(18432)                                │
└────────────────────────────────────────────────────────────┘
                         │
                         ▼
┌────────────────────────────────────────────────────────────┐
│  5. PRINT PROTOCOL                                         │
│  ─────────────────────────────────────────────────────────│
│  printTask.printInit()                                     │
│  └─> Send: [CMD_INIT, density, labelType, ...]           │
│                                                             │
│  printTask.printPage(encoded, quantity)                   │
│  └─> Send in chunks:                                      │
│      [CMD_IMAGE_HEADER, width, height]                    │
│      [CMD_IMAGE_DATA, chunk1...]                          │
│      [CMD_IMAGE_DATA, chunk2...]                          │
│      ...                                                    │
│      [CMD_IMAGE_END]                                       │
│                                                             │
│  printTask.waitForFinished()                              │
│  └─> Poll status every 100ms                              │
│      until status = FINISHED                               │
│                                                             │
│  printTask.printEnd()                                      │
│  └─> Send: [CMD_PRINT_END]                               │
└────────────────────────────────────────────────────────────┘
                         │
                         ▼
┌────────────────────────────────────────────────────────────┐
│  6. PHYSICAL OUTPUT                                        │
│  ─────────────────────────────────────────────────────────│
│  Printer Niimbot:                                          │
│  - Receives binary data via BLE/USB                        │
│  - Thermal head heats selected pixels                      │
│  - Paper feeds forward                                     │
│  - Label printed with QR + text                            │
│  - Cut (automatic or manual)                               │
│                                                             │
│  Result: Physical label 40x40mm dengan QR code            │
└────────────────────────────────────────────────────────────┘

🧩 Component Interaction Map

                    ┌──────────────────────┐
                    │   App.vue / Router   │
                    └──────────┬───────────┘
                               │
                               ▼
                    ┌──────────────────────┐
                    │  BrankasList.vue     │
                    │                      │
                    │  ┌────────────────┐  │
                    │  │ Header         │  │
                    │  │ - Printer Btn  │──┼──┐
                    │  └────────────────┘  │  │
                    │                      │  │
                    │  ┌────────────────┐  │  │
                    │  │ Item List      │  │  │
                    │  │ - Click item   │──┼──┼──┐
                    │  └────────────────┘  │  │  │
                    │                      │  │  │
                    │  ┌────────────────┐  │  │  │
                    │  │ Item Modal     │  │  │  │
                    │  │ - QR Preview   │  │  │  │
                    │  │ - Print Btn    │──┼──┼──┼──┐
                    │  └────────────────┘  │  │  │  │
                    └──────────────────────┘  │  │  │
                                              │  │  │
        ┌─────────────────────────────────────┘  │  │
        │                                        │  │
        ▼                                        │  │
┌──────────────────┐                            │  │
│ NiimbotConnector │                            │  │
│     .vue         │                            │  │
│                  │                            │  │
│ - Connect UI     │◄───────────────────────────┘  │
│ - Status display │                               │
│ - Printer info   │                               │
└────────┬─────────┘                               │
         │                                         │
         │ uses                                    │
         │                                         │
         ▼                                         │
┌──────────────────────────────────────────────────┼───┐
│  useNiimbotPrinter.js (Composable)               │   │
│                                                   │   │
│  - State: printerClient, connectionState, etc    │◄──┘
│  - Methods: connect(), disconnect(), printQR()   │
│                                                   │
│  ┌─────────────────────────────────────────────┐ │
│  │  Event Listeners Setup                      │ │
│  │  - on('connect')                            │ │
│  │  - on('disconnect')                         │ │
│  │  - on('printprogress')                      │ │
│  │  - on('heartbeat')                          │ │
│  └─────────────────────────────────────────────┘ │
└──────────────────┬───────────────────────────────┘
                   │ imports
                   ▼
┌────────────────────────────────────────────────────┐
│  @mmote/niimbluelib                                │
│                                                    │
│  - NiimbotBluetoothClient                         │
│  - NiimbotSerialClient                            │
│  - ImageEncoder                                    │
│  - PrintTask abstraction                          │
│  - Utils                                           │
└──────────────────┬─────────────────────────────────┘
                   │ uses
                   ▼
┌────────────────────────────────────────────────────┐
│  Browser APIs                                      │
│  - navigator.bluetooth (Web Bluetooth API)        │
│  - navigator.serial (Web Serial API)              │
└────────────────────────────────────────────────────┘

Performance Timeline

Event Timeline (typical print job):

0ms     │ User clicks "Cetak ke Niimbot"
        │
10ms    │ Check printer connection
        │ └─> Already connected ✓
        │
20ms    │ createQRLabelCanvas() start
        │ └─> Load QR image
        │
150ms   │ Image loaded, draw to canvas
        │ └─> Draw QR, text, etc
        │
170ms   │ canvas.toDataURL()
        │
200ms   │ printQRCode() called
        │ └─> stopHeartbeat()
        │
220ms   │ newPrintTask()
        │
240ms   │ ImageEncoder.encodeCanvas()
        │ └─> RGB → grayscale
        │ └─> Threshold
        │ └─> Pack to 1-bit
        │
450ms   │ Encoding complete (18KB data)
        │
470ms   │ printTask.printInit()
        │ └─> Send init command
        │
490ms   │ ACK received
        │
500ms   │ printTask.printPage()
        │ └─> Send image header
        │
520ms   │ Send data chunk 1/10
540ms   │ Send data chunk 2/10
...     │ ...
740ms   │ Send data chunk 10/10
        │
750ms   │ All data sent
        │
780ms   │ waitForFinished() polling start
        │
800ms   │ Status: PRINTING (0%)
900ms   │ Status: PRINTING (25%)
1000ms  │ Status: PRINTING (50%)
1100ms  │ Status: PRINTING (75%)
1200ms  │ Status: PRINTING (100%)
        │
1220ms  │ Status: FINISHED
        │
1230ms  │ printTask.printEnd()
        │
1250ms  │ startHeartbeat()
        │
1260ms  │ Alert: "QR Code berhasil dicetak!"
        │
Total: ~1.3 seconds dari klik hingga selesai

🔐 Security & Privacy

Data Flow Security:

┌──────────────────┐
│  User's Browser  │
└────────┬─────────┘
         │
         │ HTTPS (encrypted)
         │
         ▼
┌──────────────────┐
│   QR API Server  │  ← External: api.qrserver.com
└────────┬─────────┘   (Kirim kode_item only)
         │
         │ Returns image URL
         │
         ▼
┌──────────────────┐
│  User's Browser  │
│  - Generate      │
│    canvas        │
│  - Encode image  │
└────────┬─────────┘
         │
         │ BLE/USB (direct, tidak via internet)
         │ Encrypted jika BLE
         │
         ▼
┌──────────────────┐
│ Niimbot Printer  │  ← Local device, tidak terkoneksi internet
└──────────────────┘

Privacy Notes:
- Data tidak lewat server backend aplikasi
- QR Code dibuat real-time di browser
- Gambar langsung dikirim ke printer lokal
- Tidak ada logging data item ke cloud

📈 Error Handling Flow

                    ┌──────────────────┐
                    │   User Action    │
                    └────────┬─────────┘
                             │
                             ▼
                    ┌──────────────────┐
                    │  Try: connect()  │
                    └────────┬─────────┘
                             │
                ┌────────────┴────────────┐
                │                         │
         ┌──────▼──────┐          ┌──────▼──────┐
         │   Success   │          │    Error    │
         └──────┬──────┘          └──────┬──────┘
                │                        │
                │                        ▼
                │               ┌────────────────┐
                │               │ Catch error    │
                │               │ - Log to       │
                │               │   console      │
                │               │ - Set error    │
                │               │   message      │
                │               │ - Alert user   │
                │               └────────┬───────┘
                │                        │
                │                        ▼
                │               ┌────────────────┐
                │               │ connectionState│
                │               │ = 'disconnected│
                │               └────────────────┘
                │
                ▼
       ┌────────────────┐
       │ fetchPrinterInfo│
       └────────┬────────┘
                │
         ┌──────┴──────┐
         │             │
   ┌─────▼─────┐ ┌────▼────┐
   │  Success  │ │  Error  │
   └─────┬─────┘ └────┬────┘
         │            │
         │            └──> Log & continue (non-critical)
         │
         ▼
┌─────────────────┐
│ startHeartbeat()│
└─────────┬───────┘
          │
          └──> Connected & Ready

Semua diagram ini membantu memahami bagaimana sistem bekerja end-to-end! 🎉