v1.6.0 (2025-11-02)#
このリリースは、ESP32フラッシュ診断機能の追加と、CLIオプションの一貫性向上に焦点を当てた重要なアップデートです。 OSECHI検出器のESP32マイコンへのファームウェア書き込みトラブルシューティングを大幅に改善し、開発者とユーザーの両方にとってより使いやすいシステムを実現しました。
✨ v1.6.0 での改善点#
このマイルストーンは、以下を実現します。
ESP32フラッシュ診断機能: esptoolを統合した包括的な診断ツール
自動異常検出: フラッシュチップ通信失敗の自動検出と対処法提案
CLIオプション統合: 重複オプション削除と一貫性のある設計
ボーレート設定改善: 標準値(115200)とセンシブルなデフォルト値の設定
CI/CD最適化: ローカル専用テストのスキップによる実行時間短縮
🎯 User Story 1 - ESP32フラッシュ診断機能#
新機能: port diagnose コマンド#
# ESP32フラッシュチップの包括的な診断
haniwers-v1 port diagnose /dev/ttyUSB0
# フラッシュ情報のみ表示
haniwers-v1 port diagnose /dev/ttyUSB0 --flash-id
# チップ情報のみ表示
haniwers-v1 port diagnose /dev/ttyUSB0 --chip-id
# カスタムボーレート指定
haniwers-v1 port diagnose COM3 --baudrate 9600
esptool統合の特徴#
Pythonモジュールとして統合: サブプロセス不要で高速・安定動作
import esptool # ESPチップに接続 esp = esptool.detect_chip(port=device, baud=baudrate, connect_attempts=3) # スタブフラッシャーをアップロード(高速・安定化) esp = esp.run_stub() # フラッシュ情報を取得 esptool.flash_id(esp)
自動異常検出:
ff/ffff検出時に電源状態を診断✗ Flash chip communication failed Possible causes: - OSECHI power switch is OFF - Device not powered - Hardware connection issue Flash voltage is 1.8V (should be 3.3V) - Check OSECHI power switch - GPIO12 may be floating
選択的情報表示: 必要な情報のみを表示
--flash-id: Manufacturer, Device, Size, Voltage--chip-id: Chip type, Features, Crystal, MAC address--summary: eFuse summary(今後実装予定)
FlashInfo データクラス#
from haniwers.v1.cli.port import FlashInfo
# フラッシュ情報を型安全に管理
info = FlashInfo(
manufacturer="20", # XMC製造ID
device="4017", # デバイスID
flash_size="8MB", # フラッシュサイズ
flash_voltage="3.3V", # フラッシュ電圧
chip_type="ESP32-D0WD-V3",
crystal="40MHz",
mac_address="24:6f:28:xx:xx:xx"
)
# ヘルスチェック
if info.is_healthy():
print("✓ Flash chip communication successful")
else:
print(info.get_diagnosis())
🎯 User Story 2 - CLIオプションの統合と一貫性向上#
SuppressOptions の統合#
重複削除:
--suppress-thresholdを ThresholdOptions に統合# v1.5.0以前: 3箇所で定義 # - options.py: SuppressOptions # - options.py: ThresholdOptions # - 各CLIコマンド: 個別定義 # v1.6.0: 単一箇所で定義 @dataclass class ThresholdOptions: """Threshold management options.""" suppress_threshold: int = typer.Option( None, help="Suppress events below this threshold (1-1023)", )
一貫性の向上: すべてのコマンドで同じオプション名・説明を使用
Baudrate の標準化#
標準値の採用: 115200 bps をデフォルトに設定
# v1.5.0以前 baudrate: int = 9600 # 非標準値 # v1.6.0 baudrate: int = 115200 # OSECHI標準値
妥当性検証: min=1200 で異常な低速値を防止
DeviceOptions の一貫性#
中央集権化: すべてのコマンドで
DeviceOptionsを使用# 統一されたデバイスオプション from haniwers.v1.cli.options import DeviceOptions @app.command() def test( device: str = typer.Argument(...), device_opts: DeviceOptions = typer.Option(...), ): # device_opts.baudrate, device_opts.timeout が利用可能
🎯 User Story 3 - CI/CD最適化とテスト改善#
ローカル専用テストのスキップ#
.gitlab-ci.yml修正:pytest-fullジョブで-m "not local"を追加# v1.5.0以前 pytest-full: script: - poetry run pytest tests/v1/ -m "" --cov # すべて実行 # v1.6.0 pytest-full: script: - poetry run pytest tests/v1/ -m "not local" --cov # local除外
実行時間短縮: 時間がかかる・環境依存のテストをスキップ
ハードウェア依存テスト
統計的テスト(確率的に失敗する可能性)
ベンチマークテスト
テストマーカーの活用#
# ローカル環境でのみ実行すべきテスト
@pytest.mark.local
def test_missing_port_error():
"""Test error when port is not specified."""
# 環境依存のConfigLoader動作をテスト
🧪 テスト強化#
ユニットテストの追加#
テストスイート |
状態 |
詳細 |
|---|---|---|
FlashInfo dataclass |
✅ 100% |
正常時・異常時の診断メッセージ |
port diagnose コマンド |
✅ 統合テスト |
esptool実行フロー検証 |
v1 ユニットテスト全体 |
✅ パス |
346 passed, 9 skipped |
コード品質 |
✅ Pass |
ruff format, pre-commit OK |
テストカバレッジ |
✅ 54% |
port.py: 58%(診断機能含む) |
新規テストファイル#
tests/v1/unit/cli/port/test_flash_info.py: FlashInfo診断ロジックのテストdef test_flash_info_healthy(): """Test diagnosis message for healthy flash chip.""" info = FlashInfo( manufacturer="20", device="4017", flash_size="8MB", flash_voltage="3.3V", ) assert info.is_healthy() is True def test_flash_info_unhealthy(): """Test diagnosis message for unhealthy flash chip.""" info = FlashInfo( manufacturer="ff", device="ffff", flash_size="Unknown", flash_voltage="1.8V", ) assert info.is_healthy() is False assert "OSECHI power switch is OFF" in info.get_diagnosis()
🔧 内部実装の改善#
Dependencies#
esptool >= 4.8.1: ESP32フラッシュ診断
[tool.poetry.dependencies] esptool = ">=4.8.1"
進捗ログの充実#
トラブルシューティング記録:
docs/progress/entries/2025-11-02-esp32-flash-troubleshooting.md根本原因分析: OSECHI電源スイッチOFF → GPIO12フローティング
ESP32フラッシュ電圧判定メカニズムの詳細解説
Arduino IDE設定の確認結果(QIO/DIO両対応)
GPIO12とフラッシュ電圧の関係
診断コマンドの使用例
今後の予防策チェックリスト
コード品質の向上#
統一されたオプション定義: DRY原則に準拠
型安全性の向上: dataclass活用とOptional型の適切な使用
ドキュメンテーション強化: docstringの充実とコード内コメント
📊 主要な統計#
変更内容#
新規ファイル: 2ファイル
tests/v1/unit/cli/port/test_flash_info.py(46 lines)docs/progress/entries/2025-11-02-esp32-flash-troubleshooting.md(210 lines)
変更ファイル: 3ファイル
pyproject.toml(+1 dependency)poetry.lock(+esptool and dependencies)src/haniwers/v1/cli/port.py(+185 lines).gitlab-ci.yml(pytest-full修正)
コミット数: 3 commits
feat(port): add ESP32 flash diagnostics with esptool integrationci: skip local-marked tests in pytest-full jobbump: version 1.5.0 → 1.6.0
🛠️ トラブルシューティング実例#
問題: ESP32ファームウェア書き込み失敗#
TypeError: argument of type 'NoneType' is not iterable
WARNING: Failed to communicate with the flash chip
Packet content transfer stopped
診断プロセス#
# 1. フラッシュ情報取得
$ haniwers-v1 port diagnose /dev/cu.usbserial-110
# 異常値検出
Manufacturer: ff
Device: ffff
Detected flash size: Unknown
Flash voltage: 1.8V
✗ Flash chip communication failed
Possible causes:
- OSECHI power switch is OFF ← 原因特定
解決#
# OSECHIスイッチをONにする
$ haniwers-v1 port diagnose /dev/cu.usbserial-110
# 正常値確認
Manufacturer: 20 (XMC)
Device: 4017
Detected flash size: 8MB
Flash voltage: 3.3V ← 正常化
✓ Flash chip communication successful
学習事項#
GPIO12の役割: ESP32起動時にフラッシュ電圧(1.8V/3.3V)を判定
電源の重要性: OSECHI電源OFFではGPIO12がフローティング状態
診断の有効性:
ff/ffffは通信失敗を示す明確な指標
📦 インストール#
pip install haniwers==1.6.0
または最新版:
pip install --upgrade haniwers
🔗 関連リンク#
完全な変更ログ
リリース担当: shotakaha リリース日: 2025-11-02 バージョン: 1.6.0 (MINOR update) 実装期間: 1日 (2025-11-02)