npm package: @finan-me/react-native-zywell-thermal-printer
Description: Native bridge for Zywell Thermal printer
Author: sang.le
Latest version: 1.2.5

# @finan-me/react-native-zywell-thermal-printer

Native bridge for Zywell Thermal printer với Connection Pool tự động quản lý kết nối

## Installation

```bash
npm install @finan-me/react-native-zywell-thermal-printer
```

## ⚡ Features

- 🖨️ **Zywell Thermal Printer**: In ảnh qua LAN/WiFi và Bluetooth
- 🚀 **Connection Pool**: Tự động quản lý và tái sử dụng kết nối
- 📶 **Bluetooth Support**: Hỗ trợ kết nối và in qua Bluetooth
- 📱 **Cross Platform**: Hỗ trợ iOS và Android
- 🔄 **Auto Reconnect**: Tự động kết nối lại khi cần thiết

## 🚀 Quick Start

### In đơn giản (Khuyến nghị)

```typescript
import { print } from "@finan-me/react-native-zywell-thermal-printer";

// Cách đơn giản nhất - chỉ 1 dòng!
const result = await print("192.168.1.100", "/path/to/receipt.png");

// Với config
const result = await print("192.168.1.100", "/path/to/receipt.png", {
  size: 80,
  width: 576,
  cut_paper: true,
  mode: "THERMAL",
});
```

### In nhiều máy đồng thời

```typescript
import { printConcurrent } from "@finan-me/react-native-zywell-thermal-printer";

const jobs = [
  { ip: "192.168.1.100", imagePath: "/images/kitchen.png" },
  { ip: "192.168.1.101", imagePath: "/images/receipt.png" },
  { ip: "192.168.1.102", imagePath: "/images/label.png" },
];

const results = await printConcurrent(jobs);
results.forEach((r) => {
  console.log(`${r.ip}: ${r.success ? "✅" : "❌"} ${r.error || ""}`);
});
```

### In tuần tự (cùng 1 máy)

```typescript
import { printSequential } from "@finan-me/react-native-zywell-thermal-printer";

const jobs = [
  { ip: "192.168.1.100", imagePath: "/orders/order1.png" },
  { ip: "192.168.1.100", imagePath: "/orders/order2.png" },
  { ip: "192.168.1.100", imagePath: "/orders/order3.png" },
];

const results = await printSequential(jobs);
```

## 📚 API Reference

### Connection Methods

| Method                | Description                  | Parameters        | Returns           |
| --------------------- | ---------------------------- | ----------------- | ----------------- |
| `connectNet(ip)`      | Kết nối máy in qua mạng      | `ip: string`      | `Promise<string>` |
| `connectBLE(address)` | Kết nối máy in qua Bluetooth | `address: string` | `Promise<string>` |

### Printing Methods

| Method                                       | Description                          | Parameters                                                                            | Returns                  |
| -------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------- | ------------------------ |
| `print(address, imagePath, opts?, type?)`    | In với connection pool (khuyến nghị) | `address: string`<br>`imagePath: string`<br>`opts?: PrinterConfig`<br>`type?: string` | `Promise<string>`        |
| `printPic(address, imagePath, opts?, type?)` | In ảnh (legacy)                      | Same as above                                                                         | `Promise<string>`        |
| `printConcurrent(jobs)`                      | In nhiều jobs đồng thời              | `jobs: Array<PrintJob>`                                                               | `Promise<Array<Result>>` |
| `printSequential(jobs)`                      | In nhiều jobs tuần tự                | `jobs: Array<PrintJob>`                                                               | `Promise<Array<Result>>` |

### Disconnection Methods

| Method                       | Description         | Parameters                           | Returns |
| ---------------------------- | ------------------- | ------------------------------------ | ------- |
| `disconnect(address, type?)` | Ngắt kết nối máy in | `address: string`<br>`type?: string` | `void`  |

### Maintenance Methods

| Method                       | Description                              | Parameters                          | Returns           |
| ---------------------------- | ---------------------------------------- | ----------------------------------- | ----------------- |
| `clearBuffer(address, type)` | Xóa buffer máy in                        | `address: string`<br>`type: string` | `void`            |
| `cleanup()`                  | Dọn dẹp connections cũ (gọi mỗi 30 phút) | None                                | `Promise<string>` |

### Status Methods

| Method                    | Description                 | Parameters   | Returns                     |
| ------------------------- | --------------------------- | ------------ | --------------------------- |
| `getConnectionStatus(ip)` | Lấy trạng thái kết nối      | `ip: string` | `Promise<ConnectionStatus>` |
| `pingConnection(ip)`      | Kiểm tra connection healthy | `ip: string` | `Promise<boolean>`          |

## 🔧 Configuration

### PrinterConfig Options

```typescript
interface PrinterConfig {
  size?: number; // 58 hoặc 80 (mặc định: 80)
  width?: number; // Chiều rộng in pixels (mặc định: 576)
  cut_paper?: boolean; // Cắt giấy sau khi in (mặc định: true)
  mode?: string; // "THERMAL" hoặc "LABEL" (mặc định: "THERMAL")
  paper_size?: number; // Kích thước giấy cho mode LABEL (mặc định: 50)
}
```

### Android Permissions

Add to `android/src/main/AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
```

### iOS Permissions

Add to `Info.plist`:

```xml
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth access to connect to thermal printers</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs Bluetooth access to connect to thermal printers</string>
```

### iOS Setup

#### CocoaAsyncSocket Dependency

This library requires CocoaAsyncSocket for WiFi printing support. The dependency is automatically included in the podspec.

**Standard Installation:**

If you're using **ONLY** this library:

```bash
cd ios && pod install
```

No additional configuration needed!

**Compatibility with react-native-thermal-receipt-printer:**

If you're using **BOTH** this library AND `react-native-thermal-receipt-printer`, you may encounter duplicate symbols error because `react-native-thermal-receipt-printer` includes CocoaAsyncSocket in its `libPrinterSDK.a` file.

To fix this, add the following to your `ios/Podfile` inside the `post_install` block:

```ruby
post_install do |installer|
  # ... other post install code

  # Fix duplicate symbols conflict between printer libraries
  # react-native-thermal-receipt-printer includes CocoaAsyncSocket in libPrinterSDK.a
  # react-native-zywell-thermal-printer needs CocoaAsyncSocket headers
  # This removes the implementation files but keeps the headers
  installer.pods_project.targets.each do |target|
    if target.name == 'CocoaAsyncSocket'
      source_files = target.source_build_phase.files
      source_files.delete_if { |file|
        ['GCDAsyncSocket.m', 'GCDAsyncUdpSocket.m'].include?(file.file_ref.name)
      }
    end
  end
end
```

Then run:

```bash
cd ios && pod install
```

**Troubleshooting:**

- **Error: 'CocoaAsyncSocket/GCDAsyncSocket.h' file not found**: Make sure you have the latest version and run `pod install`
- **Error: 137 duplicate symbols**: Apply the Podfile fix mentioned above if using both printer libraries
- **Build fails after pod install**: Try cleaning: `cd ios && rm -rf Pods Podfile.lock && pod install --repo-update`

## 💡 Connection Pool Management

Library tự động quản lý connection pool với các tính năng:

- **Auto Connect**: Tự động kết nối khi cần in
- **Connection Reuse**: Tái sử dụng connection trong 5 phút
- **Health Check**: Kiểm tra connection trước khi in
- **Stale Cleanup**: Tự động cleanup connection không dùng > 10 phút (khi gọi `cleanup()`)

### Cleanup Strategy

```typescript
import { cleanup } from "@finan-me/react-native-zywell-thermal-printer";

// Gọi cleanup định kỳ mỗi 30 phút
setInterval(async () => {
  const result = await cleanup();
  console.log(result); // "Cleaned up 3 stale connections"
}, 30 * 60 * 1000);

// Hoặc gọi khi app về background
AppState.addEventListener("change", (state) => {
  if (state === "background") {
    cleanup();
  }
});
```

## 🔍 Advanced Usage

### Health Check trước khi in batch

```typescript
import {
  pingConnection,
  printConcurrent,
} from "@finan-me/react-native-zywell-thermal-printer";

// Kiểm tra máy in trước khi in batch
const printers = ["192.168.1.100", "192.168.1.101"];
const availablePrinters = [];

for (const ip of printers) {
  if (await pingConnection(ip)) {
    availablePrinters.push(ip);
  }
}

// Chỉ in với máy sẵn sàng
const validJobs = jobs.filter((job) => availablePrinters.includes(job.ip));
const results = await printConcurrent(validJobs);
```

### Monitor Connection Status

```typescript
import { getConnectionStatus } from "@finan-me/react-native-zywell-thermal-printer";

const status = await getConnectionStatus("192.168.1.100");
console.log(status);
// Output:
// {
//   connected: true,
//   lastUsed: 30,  // seconds since last use
//   ipAddress: "192.168.1.100"
// }
```

## 🎯 Best Practices

1. **Sử dụng `print()`** thay vì `connectNet()` + `printPic()` riêng lẻ
2. **`printConcurrent()`** cho nhiều máy in khác nhau
3. **`printSequential()`** cho cùng 1 máy in hoặc cần thứ tự
4. **Gọi `cleanup()`** định kỳ mỗi 30 phút để dọn dẹp connections
5. **Không cần** gọi `disconnect()` sau mỗi lần in
6. **Health check** chỉ cần cho batch printing hoặc mission-critical apps

## 🆚 So sánh với cách cũ

| Feature        | Cách cũ     | Connection Pool      |
| -------------- | ----------- | -------------------- |
| Connect        | Mỗi lần in  | Tự động, tái sử dụng |
| Disconnect     | Thủ công    | Tự động cleanup      |
| Performance    | ~3-5s/print | ~1-2s/print          |
| Code           | 3-5 dòng    | 1 dòng               |
| Error handling | Try-catch   | Built-in retry       |

### Migration Example

```typescript
// ❌ Cách cũ - chậm và phức tạp
await connectNet("192.168.1.100");
await printPic("192.168.1.100", "/image.png", {
  is_disconnect: true,
});

// ✅ Cách mới - nhanh và đơn giản
await print("192.168.1.100", "/image.png");
```

## 🐛 Troubleshooting

### Connection issues

```typescript
// Kiểm tra connection
const isHealthy = await pingConnection("192.168.1.100");
if (!isHealthy) {
  // Force cleanup và thử lại
  await cleanup();
  await print("192.168.1.100", "/image.png");
}
```

### Memory management

```typescript
// Cleanup khi app terminate
const onAppTerminate = async () => {
  await cleanup();
};
```

## 📝 License

MIT