Mock デバイスで開発する(ハードウェア不要)#

🚀 5分クイックスタート#

ハードウェアなしで、すぐに haniwers をテストしたい場合:

# 1. プロジェクトディレクトリへ移動
cd haniwers

# 2. Mock デバイスでデータ取得テスト(5秒で終了)
poetry run haniwers-v1 daq --mock -v

# 3. Mock デバイスで閾値設定テスト(v1.2.0以降)
poetry run haniwers-v1 threshold write --thresholds "1:100" --mock -v

うまくいったら、次は「詳しく学ぶ」セクションに進んでください!


📚 詳しく学ぶ#

Mock デバイスとは?#

実際の OSECHI 検出器がなくても、開発・テストができるようにシミュレートされたデバイスです。

項目

説明

何ができるのか?

ハードウェア不要でコマンドをテストできる

どのコマンドに対応?

DAQ(データ取得)、Threshold(閾値設定)

CLI での使い方

コマンドに --mock フラグを追加するだけ

Python での使い方

RandomMocker または Mocker クラスを使用

3 つの Mock デバイスの違い#

┌─────────────────────────────────────────────────────┐
│          実際のデバイス(Device)                    │
│  OSECHI 検出器を接続しているときだけ使える         │
└─────────────────────────────────────────────────────┘
                        ↑
          設定でどちらかを選択
                        ↓
┌─────────────────────────────────────────────────────┐
│  RandomMocker(ランダムデータ)     Mocker(CSV再生) │
│  設定不要、すぐ始められる        過去データを使いたい  │
│  開発・テスト向け              CI/CD・再現テスト向け  │
└─────────────────────────────────────────────────────┘

🎯 使用例#

例 1: CLI で Mock デバイスを使う(最も簡単)#

# データ取得テスト
poetry run haniwers-v1 daq --mock

# 閾値設定テスト
poetry run haniwers-v1 threshold write --thresholds "1:100;2:120;3:110" --mock

# ポート情報表示(実ハードウェアの確認用)
poetry run haniwers-v1 port list

例 2: Python コードで RandomMocker を使う#

from haniwers.v1.config.model import MockerConfig
from haniwers.v1.daq.mocker import RandomMocker

# 1. Mock デバイス設定
config = MockerConfig(
    csv_path=None,      # CSV ファイルなし = ランダムデータ
    speed=10.0,         # 10倍速でシミュレート
    jitter=0.01,        # 現実的なばらつき
)

# 2. Mock デバイスを作成
mocker = RandomMocker(config, seed=42)  # seed=42 で再現可能

# 3. 使用
mocker.connect()
data = mocker.readline()  # センサーデータ(7項目)を取得
print(data)               # 例: '2 5 8 512 25.43 100550.12 55.67'
mocker.disconnect()

例 3: Python コードで閾値設定テスト(v1.2.0 新機能)#

from haniwers.v1.config.model import MockerConfig
from haniwers.v1.daq.mocker import RandomMocker
from haniwers.v1.threshold.writer import write_threshold

# Mock デバイス初期化
mocker = RandomMocker(MockerConfig())

# 成功ケース:正常に閾値書き込み
success = write_threshold(mocker, ch=1, vth=100)
print(f"書き込み成功: {success}")  # → True

# 失敗ケース:デバイスが拒否
mocker.set_next_response("dame")  # 拒否レスポンスを設定
success = write_threshold(mocker, ch=1, vth=200)
print(f"書き込み成功: {success}")  # → False

🔧 詳細設定#

設定ファイルを使う(Python コード開発向け)#

ファイル: sandbox/config.toml

# Mock デバイス用の最小設定
[device]
port = "/dev/null"  # Mock デバイス(ハードウェアなし)

[mocker]
csv_path = null     # ランダムデータ生成
speed = 5.0         # 5倍速シミュレート
jitter = 0.01       # 現実的なばらつき

Python コード:

from pathlib import Path
from haniwers.v1.config.loader import ConfigLoader
from haniwers.v1.daq.mocker import RandomMocker
from haniwers.v1.daq.sampler import Sampler

# 設定ファイルから設定を読み込み
loader = ConfigLoader(Path("sandbox/config.toml"))
config = loader.config

# Mock デバイス作成
mocker = RandomMocker(config.mocker)

# データ取得実行
output_dir = Path("sandbox/data")
output_dir.mkdir(parents=True, exist_ok=True)

sampler = Sampler(mocker, config.daq, output_dir)

try:
    sampler.acquire_by_count(
        file_path=output_dir / "test_data.csv",
        event_count=100  # 100イベント取得
    )
    print("✅ データ取得成功")
finally:
    mocker.disconnect()

設定ファイルを使う(再現テスト向け)#

過去に記録した CSV ファイルを再生したい場合:

ファイル: sandbox/config-replay.toml

[device]
port = "/dev/null"

[mocker]
csv_path = "examples/sample_data.csv"  # CSV ファイルを指定
shuffle = false                        # 順序を保持
speed = 1.0                           # 実時間速度

❓ よくある質問#

Q: --mock フラグはどのコマンドで使える?#

# ✅ 使える
poetry run haniwers-v1 daq --mock
poetry run haniwers-v1 threshold write --mock
poetry run haniwers-v1 threshold scan --mock

# ❌ 使えない
poetry run haniwers-v1 port list --mock  # ハードウェア確認コマンドなので不要

Q: “CSV ファイルが見つからない” というエラーが出た#

# ❌ 間違い:ファイルが存在しないパス
config = MockerConfig(csv_path="data/missing.csv")

# ✅ 正解:存在するパスを指定
config = MockerConfig(csv_path="examples/sample_data.csv")

# または ✅ ランダムデータを使う(推奨)
config = MockerConfig(csv_path=None)  # None を指定する

Q: seed パラメータって何?#

# 同じ seed を使うと、毎回同じデータが出力される(再現可能)
mocker1 = RandomMocker(config, seed=42)
mocker2 = RandomMocker(config, seed=42)
# mocker1 と mocker2 は同じデータを生成

# seed を指定しないと、実行のたびに異なるデータが出力される
mocker3 = RandomMocker(config, seed=None)  # または seed を省略

Q: 実デバイスと Mock を切り替えるには?#

設定ファイルだけで切り替え可能(コード不要):

# Mock デバイスを使う
[device]
port = "/dev/null"

# 実デバイスに切り替える
[device]
port = "/dev/cu.usbserial-14230"

Python コードは同じ:

from haniwers.v1.daq.device import Device
device = Device(config.device)  # 設定に応じて自動選択

Q: Mock でも閾値書き込みテストできる?#

はい!v1.2.0 以降で対応しました:

# CLI での閾値設定テスト
poetry run haniwers-v1 threshold write --thresholds "1:100" --mock

# Python コードでのテスト
from haniwers.v1.threshold.writer import write_threshold
result = write_threshold(mocker, ch=1, vth=100)
print(f"成功: {result}")  # → True

Q: RandomMocker と Mocker の使い分けは?#

場面

使うもの

理由

ローカルで開発中

RandomMocker

CSV ファイル不要、すぐ始められる

過去データで検証

Mocker

同じデータで再現性のあるテストができる

CI/CD テスト

Mocker

毎回同じデータなので結果が予測可能

ストレステスト

RandomMocker

様々なパターンをランダムに生成


🐛 トラブルシューティング#

エラー: “No such file or directory”#

# ❌ 原因:ファイルパスが間違っている
mocker = Mocker(MockerConfig(csv_path="./data/missing.csv"))

# ✅ 解決策 1:ファイルの存在確認
import os
if os.path.exists("examples/sample_data.csv"):
    print("ファイルあり")
else:
    print("ファイルなし - ランダムモデを使おう")

# ✅ 解決策 2:ランダムモデを使う
mocker = RandomMocker(MockerConfig())

エラー: “port already in use”#

このエラーが出ても Mock デバイスには影響ありません。

# 実デバイスを接続している場合だけ出ます
poetry run haniwers-v1 daq --mock  # Mock なら問題なし

エラー: “Invalid threshold value”#

# ❌ 間違い:閾値の範囲外(1-1023)
write_threshold(mocker, ch=1, vth=2000)  # 大きすぎる

# ✅ 正解:有効な範囲内
write_threshold(mocker, ch=1, vth=100)   # OK

📖 関連ドキュメント#


💡 ベストプラクティス#

開発フロー#

1. Mock で機能をテスト
   poetry run haniwers-v1 daq --mock

2. 実ハードウェアで動作確認(手元に有る場合)
   poetry run haniwers-v1 daq

3. ユニットテスト追加
   poetry run pytest tests/

4. コミット・プッシュ
   git commit -m "feat: add new feature"
   git push

チェックリスト#

  • Mock デバイスで動作確認した

  • ユニットテストを追加した

  • poetry run ruff format でコード整形した

  • poetry run pytest ですべてのテストが通った