Metadata-Version: 2.4
Name: barcodewatch
Version: 0.1.0
Summary: Threaded serial line reader with a simple callback API, built for barcode scanners
Author: tuo170
License-Expression: MIT
Project-URL: Homepage, https://github.com/tuo170/barcodewatch
Project-URL: Issues, https://github.com/tuo170/barcodewatch/issues
Keywords: barcode,serial,scanner,tkinter,threading
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Classifier: Intended Audience :: Developers
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyserial>=3.5
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Dynamic: license-file

# barcodewatch

[![Tests](https://github.com/tuo170/barcodewatch/actions/workflows/test.yml/badge.svg)](https://github.com/tuo170/barcodewatch/actions/workflows/test.yml)

> Threaded serial line reader for Python with a simple callback API, built for barcode scanners.

シリアル接続のバーコードスキャナーなどから送られてくる行単位のデータを、バックグラウンドスレッドで読み取り続け、完了した1行ごとにコールバックへ渡すライブラリです。GUI(tkinterなど)のメインループを止めずに、スキャンイベントを受け取れます。

```python
from barcodewatch import Scanner
from barcodewatch.presets import TERA_HW0002

def on_scan(data: str) -> None:
    print(f"scanned: {data}")

with Scanner("/dev/ttyUSB0", **TERA_HW0002) as scanner:
    scanner.on_scan(on_scan)
    ...
```

## なぜbarcodewatchなのか

バーコードスキャナーはキーボードエミュレーション(HID)モードで使われることが多いですが、業務用スキャナーはシリアル(RS-232/USB-CDC)接続で使うことも珍しくありません。シリアル接続の場合、自分でポートを開いて読み取りループを書く必要があり、GUIと組み合わせようとするとスレッド周りの設計が地味に面倒です。

barcodewatch（本プログラム）では、ポートを開いてバックグラウンドスレッドで読み取りを開始し、区切り文字(CR/LF/CRLF)で区切られた1行が完成するたびに登録済みコールバックを呼び出す、という最小限の仕組みだけを提供します。

現状、行単位のテキストデータ受信のみの機能となっています。バイナリプロトコルの解析やスキャナー側の設定変更(コマンド送信)が本格的に必要な場合は、他のより高機能なライブラリについても検討してください。

## インストール

```bash
pip install barcodewatch
```

[PyPI](https://pypi.org/project/barcodewatch/)で公開しています。

## API

- `Scanner(port, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=1.0)` — シリアルポートを開き、即座にバックグラウンドの読み取りスレッドを開始します。`port`と`timeout`以外のデフォルト値は`serial.Serial`自身のデフォルトと同じで、特定の機種を前提にした値は一切持ちません(`timeout`のみ、読み取りスレッドが`close()`に素早く反応できるようにするための実装上の都合で`1.0`にしています。機種の設定ではありません)。
- `barcodewatch.presets` — 特定機種向けの設定をまとめたモジュール。現状`TERA_HW0002`(元記事の想定機種)のみですが、他機種を使う場合は同じ形の`dict`を自分で定義して`Scanner(port, **your_preset)`のように渡せます。`Scanner`自体は特定機種を一切知りません。
- `scanner.on_scan(callback)` — `callback(data: str)`を登録します。CR/LF/CRLFで区切られた行が完成するたびに呼び出されます。何個でも登録可能で、どのスレッドから呼んでも安全です。
- `scanner.send(data)` — 生のバイト列をシリアルポートに書き込みます。
- `scanner.running` — 読み取りスレッドが停止すると`False`になります(`close()`後、またはデバイスが切断された場合など)。
- `scanner.close()` — スレッドを停止し、ポートを閉じます。何度呼んでも安全です(`with Scanner(...) as scanner:`を使えば自動的に呼ばれます)。

tkinterと組み合わせた一通りの使用例は[`examples/tkinter_gui.py`](examples/tkinter_gui.py)を参照してください。

## 動作検証

### 検証環境(2026-08-23)

| 項目 | 内容 |
|---|---|
| OS | Windows 11 Pro |
| Python | 3.10.6(プロジェクト専用のvenv) |
| インストール方法 | `pip install -e .` |
| 依存パッケージ | pyserial 3.5 |
| バーコードリーダー | Tera HW0002(USB接続、USB-SERIAL CH340として認識、COM5) |

### 確認できたこと

- `Scanner("COM5", **TERA_HW0002)`でポートを開き、実機でバーコードを連続スキャンして`on_scan`コールバックに値が正しく渡ることを確認。
- [`examples/tkinter_gui.py`](examples/tkinter_gui.py)を実行し、tkinterウィンドウの「Scan Data:」欄にスキャンごとの値が正しく反映されることを確認。

### 未検証

- Linux / macOSでの動作(pyserial自体はクロスプラットフォームのため動作するはずだが、実機未確認)

## ライセンス

MIT — [LICENSE](LICENSE)を参照してください。

## 背景

このライブラリは、[Qiitaに投稿した元のプログラム](https://qiita.com/tuo170/items/f9bf5665722116c14895)を土台に、バグ修正・API整理・パッケージ化を行って作られています。

実装のコーディングやレビュー、設計の壁打ち相手としてClaude Codeを使用しました。
