プロジェクト

全般

プロフィール

機能 #185

完了

機能 #162: OBS連携機能

【OBS連携】心拍数表示

機能 #185: 【OBS連携】心拍数表示

エージェント ちゃん さんが23日前に追加. 22日前に更新.

ステータス:
完了
優先度:
通常
担当者:
対象バージョン:
開始日:
2026/06/13
期日:
進捗率:

100%

予定工数:

説明

親: #162

概要

OBS オーバーレイに心拍数(HR)を表示する将来要望。配信者の心拍をオーバーレイに出し、緊張感を可視化する。

現状としての着手(#182 側)

  • 今回の #182 overlay デザインで**心拍数表示用の予約枠(ブロック)**をレイアウト上に用意済み(既定非表示)。本チケットでデータ源と表示を有効化する。

検討事項(未着手)

  • データ源: 心拍センサーの連携方法。例:Pulsoid / HypeRate の WebSocket/HTTP API、あるいは OS の BLE 心拍デバイス。beatoraja 本体が取得して /state.json に乗せるか、overlay.js が直接外部 API を叩くかを決める。
  • /state.json 拡張案: heartRate: { bpm: 142, zone: "..." } 等。overlay 側は heartRate.bpm を data-field で受ける予定。
  • localhost 固定・低頻度更新の方針は #162 を踏襲。

マイルストーン

未定(将来)。今回は予約枠のみ。


関連するチケット 2 (1件未完了1件完了)

関連している 個人開発 - 機能 #29: BLEで心拍数をOBSに直接送れるやつ作る却下いづ さん2026/02/25

操作
関連している Ferrhythm - 機能 #370: 【OBS連携】心拍数表示の移植未着手いづ さん2026/06/21

操作

いづ さん さんが23日前に更新 操作 #1

CooSpoのHW706心拍計アームバンドがあるので、BLEでいけるはず。
現在の心拍数と、過去何分間かのグラフがあるといいかも

いづ さん さんが23日前に更新 操作 #2

  • 題名【OBS連携】心拍数表示(将来要望) から 【OBS連携】心拍数表示 に変更

エージェント ちゃん さんが23日前に更新 操作 #3

  • ステータス未着手 から 実装中 に変更
  • 進捗率0 から 10 に変更

詳細設計(2026-06-13)/実装着手

ユーザー方針確認の結果:データ源=本体が直接BLE取得経路=本体が取得し /state.json に乗せる表示=現在BPM+過去数分グラフ

技術調査の結論

  • Windows 上の純Java で BLE 心拍計を読む実用手段は無い(OSS の純Java BLE は Linux/BlueZ 専用、Windows 対応は商用 IPWorks のみ)。
  • 「本体が直接BLE(クラウド非経由)」を保つため、小さなネイティブ BLE ブリッジを同梱する方式を採用(ユーザー承認済み)。

アーキテクチャ

HW706 (BLE GATT 0x180D/0x2A37)
  │ BLE notify
  ▼
hrm-bridge (Rust+btleplug, 単一バイナリ)  ── stdout NDJSON {"bpm":142} ──►  beatoraja本体
   ▲ heartRateEnabled 時に子プロセス起動                 HeartRateService(子プロセス管理/stdout読取/再接続)
                                                          └ ObsState: 1秒サンプリングのリングバッファ+ゾーン算出
                                                          └ /state.json: heartRate{...}
                                                              ▲ overlay 1秒ポーリング
                                                          overlay: #heartrate 値+#hrgraph 折れ線+ゾーン色

ネイティブブリッジ tools/hrm-bridge/(Rust + btleplug)

  • btleplug(MIT/Apache, WinRT/CoreBluetooth/BlueZ をラップ)で 0x180D を広告する HRM をスキャン→接続→0x2A37 を購読。
  • 0x2A37 の先頭フラグバイト bit0 で UINT8/UINT16(LE) を判別して bpm を抽出。
  • stdout に1行1JSON({"bpm":142} / 診断用 {"event":"connected|disconnected|error",...})。切断時はバックオフ再接続、stdin EOF / SIGTERM で終了。
  • デバイス選択:既定は最初に見つけた HRM。--name/--address フィルタ任意。
  • CI に Rust を入れず、既存 natives/*.dll と同様にプリビルドバイナリを natives/ にコミット(Windows 版は実機 Windows で cargo build --release)。tools/hrm-bridge/README にビルド手順。

本体 Java 側

  • 設定追加(Config/ConfigPersistenceDto):heartRateEnabled=falseheartRateMaxHr=190(ゾーン算出用)、heartRateDeviceFilter=""(任意)、heartRateBridgePath=""(空=OS/arch から natives/ 自動解決)。
  • 新規 HeartRateServicestream/obs):ブリッジ子プロセスの起動/監視/再起動、stdout 読取→bpm 解析→ObsState.setHeartRate(bpm)。バイナリ不在時は警告ログのみで no-op(グレースフル)。
  • ObsState:心拍を Snapshot に保持。1秒ティックで最新 bpm をリングバッファ(既定180サンプル=3分)へ。10秒以上更新が無ければ stale→heartRate=null。ゾーンは maxHr に対する%で Z1..Z5。
  • /state.json 拡張:"heartRate": null | { "bpm":142, "zone":"Z3", "zoneIndex":3, "min":120, "max":150, "sampleSec":1, "history":[...] }(history は古い→新しい順の bpm 整数列、x軸は sampleSec で暗黙)。
  • 起動条件:obsEnabled && heartRateEnabledObsController.start()/dispose() で起動/破棄。無効時ゼロ影響。
  • 設定 UI:既存 OBS 設定と同じ PlayConfigurationView(+FXML, i18n) に「心拍数表示」「最大心拍数」「デバイスフィルタ」を追加。

オーバーレイ(web)

  • 予約枠 #heartrate の数値表示を有効化(heartRate.bpm 既存バインド)。zoneIndex で色分け(CSS変数 Z1..Z5)。
  • 新規 #hrgraphheartRate.history を依存ライブラリ無しの inline SVG/canvas で折れ線描画(差分時のみ再描画、min/max/現在値ラベル)。?blocks= トグル対応。テーマは既存 control deck HUD に統一。
  • README のブロック説明を「予約枠」→ライブ機能に更新、state.sample.json に heartRate サンプル追加。

テスト/検証

  • Java 単体:heartRate の JSON 形(null/充填)、ゾーン境界、リングバッファ上限/stale、ブリッジ stdout 行解析(不正行は無視)。xvfb-run -a ./gradlew test
  • ブリッジ:0x2A37 フラグ解析(UINT8/UINT16 LE)の Rust 単体テスト。
  • オーバーレイ:node --check + DOM シムで history→グラフ点の契約検証(#182 と同方式)。
  • BLE 実機(HW706→ブリッジ→グラフ)は Windows ホスト+実機でのみ検証可能。コンテナでは Java compile/test・overlay 静的検査・ダミーブリッジ({"bpm":...} 出力)での end-to-end を担保。

本コメントは詳細設計であり実装着手の記録。作業ブランチ feature/185-heart-rate

エージェント ちゃん さんが23日前に更新 操作 #4

実装・レビュー完了(ブランチ feature/185-heart-rate を push 済み)

コミット2本:

  • b33f75db バックエンド+BLE ブリッジ(Codex 実装→Claude レビュー:ObsState の snapshot 更新を単一ロックで直列化し、非同期心拍スレッドと changeState スレッドの lost-update を修正済み)
  • 88e383f5 オーバーレイ UI(AGY ブリッジ実装→Claude レビュー・仕上げ:vector-effect 修正・サンプル整合)

成果物

  • tools/hrm-bridge:Rust+btleplug の BLE ブリッジ(0x180D スキャン→接続→0x2A37 購読→stdout に {"bpm":N}、再接続/終了処理、フラグ解析の単体テスト)
  • HeartRateService:ブリッジ子プロセスの起動/stdout読取/1秒サンプリング/バックオフ再起動、バイナリ不在時は no-op
  • ObsState//state.jsonheartRate{bpm,zone,zoneIndex,min,max,sampleSec,history[]}(null/stale 復帰・リングバッファ・ゾーン算出、Java 単体テストあり)
  • 設定 UI:PlayConfigurationView に心拍表示/最大心拍数/デバイスフィルタ(i18n 日英)
  • overlay:#heartrate で現在BPM+MIN/MAX+ゾーン色(Z1寒色〜Z5暖色)+inline SVG 折れ線グラフ(差分再描画・null/空で例外なし)。README/state.sample.json 更新

検証

  • xvfb-run -a ./gradlew compileJava testBUILD SUCCESSFUL(並行性修正後に再検証)
  • overlay:node --check・JSON parse・CSS ブレース整合・DOM シムの契約テスト(bpm/zone/polyline/null/単一点/空 history)全通過

残作業(ユーザー側)

  • ネイティブバイナリ未同梱:WinRT 依存のため Windows バイナリは実機 Windows でビルドが必要。cd tools/hrm-bridge && cargo build --releasetarget/release/hrm-bridge.exenatives/hrm-bridge-win-x64.exe としてコミット。それまでは HeartRateService は警告ログのみで no-op。
  • BLE 実機動作確認(HW706→ブリッジ→overlay グラフ)は Windows ホストで実施

MR はユーザー承認後に作成予定。

エージェント ちゃん さんが22日前に更新 操作 #5

MR 作成

実装・レビュー・実機確認(CooSpo HW706 + Windows)完了につき MR を作成しました。

実装概要

本体が BLE 心拍計(標準 GATT 0x180D/0x2A37)にネイティブブリッジ(Rust+btleplug, natives/ に同梱)経由で直接接続し、/state.jsonheartRate{bpm,zone,zoneIndex,min,max,sampleSec,history[]} に乗せて overlay が現在BPM+直近数分グラフを表示(クラウド非経由・obsEnabled=false 時ゼロ影響)。設定 UI(有効/最大心拍数/デバイスフィルタ)追加。

テスト

xvfb-run -a ./gradlew test → BUILD SUCCESSFUL、Rust フラグ解析単体テスト、overlay の DOM シム契約テスト、実機動作確認。

補足

  • Windows バイナリは WinRT 依存のため実機 Windows でビルド・コミット済み。Linux/Mac 版は未同梱(将来)。
  • 配色は overlay の他ブロックと同一テーマ色に統一。

MR 承認・マージ後に 完了 へ移行予定。

エージェント ちゃん さんが22日前に更新 操作 #6

  • ステータス実装中 から 完了 に変更
  • 進捗率10 から 100 に変更

MR !27 承認・develop へマージ完了につき完了。

実装サマリ(OBS連携 心拍数表示)

beatoraja 本体が BLE 心拍計(標準 GATT Heart Rate Service 0x180D / Measurement 0x2A37、例:CooSpo HW706)に、同梱ネイティブブリッジ(Rust+btleplug)経由で直接接続し、/state.jsonheartRate{bpm,zone,zoneIndex,min,max,sampleSec,history[]} に乗せて OBS オーバーレイが現在 BPM ⊕ 直近数分の推移グラフを表示。クラウド非経由、obsEnabled=false 時ゼロ影響。

  • ブリッジ:tools/hrm-bridge(スキャン→接続→0x2A37購読→フラグ解析→stdout NDJSON、再接続/終了処理)。Windows バイナリ natives/hrm-bridge-win-x64.exe を同梱。
  • 本体:HeartRateService(子プロセス管理/1秒サンプリング/バックオフ再起動/不在時 no-op)、ObsState 拡張(リングバッファ3分・ゾーン算出・stale復帰・snapshot 単一ロック直列化)。
  • 設定:心拍表示有効 / 最大心拍数 / デバイスフィルタ(PlayConfigurationView + i18n)。
  • overlay:#heartrate に BPM ⊕ MIN/MAX ⊕ SVG 折れ線グラフ。配色は他ブロックと同一テーマ色に統一。

テスト:xvfb-run -a ./gradlew test 成功、Rust フラグ解析単体テスト、overlay DOM シム契約テスト、実機(HW706 + Windows)動作確認済み。

今後の余地:Linux/Mac 版ブリッジバイナリの同梱、heartRate.zone/zoneIndex を用いたテーマ別のゾーン色分け(データは既に /state.json に存在)。

いづ さん さんが22日前に更新 操作 #7

  • 対象バージョン1.0.1 にセット

いづ さん さんが22日前に更新 操作 #8

  • 関連している 機能 #29: BLEで心拍数をOBSに直接送れるやつ作る を追加

いづ さん さんが15日前に更新 操作 #9

  • 関連している 機能 #370: 【OBS連携】心拍数表示の移植 を追加

他の形式にエクスポート: PDF Atom