設定ガイド(v1)#

このガイドでは、v1 の ConfigLoader を使用して設定を読み込み、使用する方法を説明します。

概要#

Haniwers v1 では、Pydantic ベースの型安全な設定管理システムを提供しています。

  • 設定モデル (model.py): DeviceConfigDaqConfigSensorConfig など

  • 設定ローダー (loader.py): TOML ファイルの検索と読み込み

  • 環境変数オーバーライド: TOML ファイルの値を環境変数で上書き可能

基本的な使い方#

1. 設定ファイルの準備#

TOML 形式で hnw.toml を作成:

[device]
label = "OSECHI"
port = "/dev/cu.usbserial-140"
baudrate = 115200
timeout = 1.0

[daq]
label = "main"
workspace = "."
filename_prefix = "osechi_data"
filename_suffix = ".csv"
events_per_file = 10000
number_of_files = 10000
stream_mode = true

[sensors.ch1]
label = "top"
center = 512
nsteps = 10
step_size = 1
threshold = "none"

[sensors.ch2]
label = "mid"
center = 311
nsteps = 10
step_size = 1
threshold = "none"

[sensors.ch3]
label = "btm"
center = 420
nsteps = 10
step_size = 1
threshold = "none"

[scan]
label = "main"
workspace = "."
filename_prefix = "scan_data"
filename_suffix = ".csv"
events_per_file = 10000
number_of_files = 10
stream_mode = false
duration = 10.0
suppress_threshold = 1000
max_retry = 3

[mocker]
csv_path = null
shuffle = false
speed = 1.0
jitter = 0.0
loop = true

2. ConfigLoader で設定を読み込む#

from pathlib import Path
from haniwers.v1.config.loader import ConfigLoader

# 明示的にパスを指定
config_path = Path("custom.toml")
loader = ConfigLoader(config_path)
cfg = loader.config

# または、デフォルト検索パスから自動検出
loader = ConfigLoader()  # hnw.toml を自動検索
cfg = loader.config

# 設定にアクセス
print(cfg.device.port)           # "/dev/cu.usbserial-140"
print(cfg.device.label)          # "OSECHI_Main"
print(cfg.sensors["ch1"].center)  # 512
print(cfg.daq.workspace)         # "."

設定ファイルの検索順序#

ConfigLoader が get_default_config_path() で探す順序:

  1. ./hnw.toml(カレントディレクトリ)

  2. ./config.toml(カレントディレクトリ)

  3. ./config/*.toml(カレントディレクトリの config フォルダ、アルファベット順)

  4. ~/.config/haniwers/hnw.toml(ユーザーディレクトリ)

  5. ~/.config/haniwers/config.toml(ユーザーディレクトリ)

  6. ~/.config/haniwers/*.toml(ユーザーディレクトリ、アルファベット順)

最初にマッチしたファイルが使用されます。

プラットフォーム別ユーザー設定ディレクトリ#

  • macOS: ~/Library/Application Support/haniwers/

  • Linux: ~/.config/haniwers/

  • Windows: C:\Users\<username>\AppData\Roaming\haniwers\

環境変数オーバーライド#

設定ファイルの値を環境変数で上書きできます:

# シリアルポートをオーバーライド
export HANIWERS_DEVICE_PORT=/dev/cu.usbserial-999
export HANIWERS_DEVICE_BAUDRATE=9600
export HANIWERS_DEVICE_TIMEOUT=2.0

# ワークスペース(DAQ と Scan の両方)
export HANIWERS_WORKSPACE=/tmp/daq_data

# Python で使用
loader = ConfigLoader()
cfg = loader.config
print(cfg.device.port)  # "/dev/cu.usbserial-999"(TOML の値から上書き)

サポートされている環境変数#

環境変数

説明

HANIWERS_DEVICE_PORT

str

シリアルポート

HANIWERS_DEVICE_BAUDRATE

int

ボーレート

HANIWERS_DEVICE_TIMEOUT

float

タイムアウト(秒)

HANIWERS_WORKSPACE

str

DAQ と Scan の出力ディレクトリ

CLI での使用例#

v1 DAQ コマンド#

# 設定ファイルを指定
haniwers-v1 daq --config custom.toml

# または、デフォルト設定ファイルを自動検出
haniwers-v1 daq

環境変数で上書き#

export HANIWERS_DEVICE_PORT=/dev/cu.usbserial-999
haniwers-v1 daq  # 環境変数の値が使用される

コードでの使用パターン#

パターン 1: 最小限の使用#

from haniwers.v1.config.loader import ConfigLoader

loader = ConfigLoader()
cfg = loader.config

# デバイス設定を取得
port = cfg.device.port
baudrate = cfg.device.baudrate

パターン 2: エラーハンドリング#

from pathlib import Path
from haniwers.v1.config.loader import ConfigLoader

try:
    loader = ConfigLoader(Path("hnw.toml"))
    cfg = loader.config
except FileNotFoundError as e:
    print(f"設定ファイルが見つかりません: {e}")
    # フォールバック処理
except ValueError as e:
    print(f"設定ファイルが無効です: {e}")
    # エラー処理

パターン 3: センサー設定の反復#

from haniwers.v1.config.loader import ConfigLoader

loader = ConfigLoader()
cfg = loader.config

# すべてのセンサーを反復
for name, sensor in cfg.sensors.items():
    print(f"センサー: {name}")
    print(f"  ラベル: {sensor.label}")
    print(f"  スキャン範囲: {list(sensor.threshold_range())}")
    print(f"  しきい値: {sensor.threshold}")

パターン 4: DAQ デバイスの初期化#

from pathlib import Path
from haniwers.v1.config.loader import ConfigLoader
from haniwers.v1.daq.device import Device
from haniwers.v1.daq.mocker import RandomMocker

loader = ConfigLoader()
cfg = loader.config

# 実ハードウェア を使用
device = Device(
    port=cfg.device.port,
    baudrate=cfg.device.baudrate,
    timeout=cfg.device.timeout
)

# または、モック デバイス を使用(テスト用)
mock_device = RandomMocker(cfg.mocker, seed=42)

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

“No config file found in expected locations”#

設定ファイルが見つからない場合:

# 設定ファイルが存在することを確認
ls -la hnw.toml config.toml

# または、デフォルト検索パスを表示
haniwers-v1 --help  # ドキュメント参照

# 明示的にパスを指定
python script.py --config /path/to/hnw.toml

“Invalid configuration format”#

TOML ファイルの形式が無効な場合:

  1. TOML 構文を確認:[section] の形式、key = value の形式

  2. 必須フィールドをすべて記入したか確認

  3. 値の型が正しいか確認(例:baudrate は整数)

環境変数が反映されない#

# 環境変数が設定されているか確認
echo $HANIWERS_DEVICE_PORT

# Python スクリプトで直接確認
import os
print(os.environ.get("HANIWERS_DEVICE_PORT"))

設定クラスの詳細#

DeviceConfig#

OSECHI ハードウェアの接続設定:

  • label: デバイス名(“OSECHI_Main” など)

  • port: シリアルポート(“/dev/cu.usbserial-140” など)

  • baudrate: 通信速度(通常 115200)

  • timeout: タイムアウト(秒、通常 1.0)

SensorConfig#

センサーチャンネルのスキャン設定:

  • label: センサー名(“top”、“mid”、“btm”)

  • center: スキャンの中心値(1-1023)

  • nsteps: 中心からのステップ数

  • step_size: ステップサイズ(ADC単位)

  • threshold: 現在のしきい値(“none” または数値)

スキャン範囲の計算例:

sensor = cfg.sensors["ch1"]
# center=512, nsteps=10, step_size=1
# 範囲: [502, 503, 504, ..., 521, 522] (21 個の値)
scan_range = list(sensor.threshold_range())

DaqConfig#

データ取得出力の設定:

  • label: 設定名

  • workspace: 出力ディレクトリ

  • filename_prefix: ファイル名の前付け

  • filename_suffix: ファイル拡張子

  • events_per_file: ファイルあたりのイベント数

  • number_of_files: 作成する最大ファイル数

  • stream_mode: true でリアルタイム出力、false でバッファリング

ScanConfig#

閾値スキャン実験の設定:

  • 基本的には DaqConfig と同じ、加えて:

  • duration: 各閾値レベルでのデータ収集時間(秒)

  • suppress_threshold: ノイズフロア(デフォルト: 1000)

  • max_retry: 失敗時の最大リトライ回数(デフォルト: 3)

MockerConfig#

モックデバイスの設定:

  • csv_path: リプレイ用 CSV ファイルパス(null で ランダム生成)

  • shuffle: 再生前にイベントをシャッフル

  • speed: 再生速度倍率(1.0 = リアルタイム、2.0 = 2倍速)

  • jitter: タイミング変動(標準偏差、秒)

  • loop: CSV の終端に到達したらループ

ベストプラクティス#

推奨事項#

  1. プロジェクトルートに hnw.toml を置く - 常に最初に検出される

  2. 環境変数は一時的なオーバーライドに使用 - 恒久的な設定は TOML ファイルに

  3. エラーハンドリングを実装 - 設定ファイルが見つからない場合の処理

  4. 設定値をログ出力 - デバッグ時に何が読み込まれたか確認

例:安全な設定読み込み#

from pathlib import Path
from haniwers.v1.config.loader import ConfigLoader
from haniwers.v1.log.logger import logger

def load_config(config_path=None):
    """安全に設定を読み込む"""
    try:
        if config_path:
            logger.info(f"Loading config from: {config_path}")
            loader = ConfigLoader(Path(config_path))
        else:
            logger.info("Loading config from default search paths")
            loader = ConfigLoader()

        cfg = loader.config
        logger.info(f"Device: {cfg.device.label} on {cfg.device.port}")
        return cfg

    except FileNotFoundError as e:
        logger.error(f"Config not found: {e}")
        raise
    except ValueError as e:
        logger.error(f"Invalid config: {e}")
        raise

参考資料#