swbt-python 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. swbt_python-0.1.0/AGENTS.md +176 -0
  2. swbt_python-0.1.0/LICENSE +21 -0
  3. swbt_python-0.1.0/PKG-INFO +122 -0
  4. swbt_python-0.1.0/README.md +96 -0
  5. swbt_python-0.1.0/examples/hardware_bringup.py +115 -0
  6. swbt_python-0.1.0/examples/pairing_probe.py +98 -0
  7. swbt_python-0.1.0/examples/tap_a.py +103 -0
  8. swbt_python-0.1.0/pyproject.toml +149 -0
  9. swbt_python-0.1.0/spec/complete/unit_001/M0_PROTOCOL_CORE.md +158 -0
  10. swbt_python-0.1.0/spec/complete/unit_002/M1_SWITCH_GAMEPAD_FAKE_TRANSPORT.md +173 -0
  11. swbt_python-0.1.0/spec/complete/unit_003/M2_BUMBLE_HID_TRANSPORT.md +171 -0
  12. swbt_python-0.1.0/spec/complete/unit_004/M3_PAIRING_L2CAP.md +168 -0
  13. swbt_python-0.1.0/spec/complete/unit_005/M4_SUBCOMMAND_RESPONDER_HARDWARE.md +189 -0
  14. swbt_python-0.1.0/spec/complete/unit_006/M5_INPUT_OPERATION_API.md +206 -0
  15. swbt_python-0.1.0/spec/complete/unit_007/M6_RECONNECT_KEYSTORE_DIAGNOSTICS.md +236 -0
  16. swbt_python-0.1.0/spec/complete/unit_008/M7_PACKAGING_EXAMPLES_CLI.md +203 -0
  17. swbt_python-0.1.0/spec/complete/unit_009/PORTING_SOURCE_AUDIT.md +151 -0
  18. swbt_python-0.1.0/spec/complete/unit_010/DIAGNOSTICS_TRACE_SCHEMA.md +158 -0
  19. swbt_python-0.1.0/spec/complete/unit_011/HARDWARE_TEST_LOG_MATRIX.md +148 -0
  20. swbt_python-0.1.0/spec/complete/unit_012/INITIAL_RELEASE_GATE.md +174 -0
  21. swbt_python-0.1.0/spec/complete/unit_013/POST_M5_INPUT_SEMANTIC_CHARACTERIZATION.md +176 -0
  22. swbt_python-0.1.0/spec/complete/unit_014/DEVICE_CLOSE_GRACEFUL_DISCONNECT.md +211 -0
  23. swbt_python-0.1.0/spec/complete/unit_015/CONTEXT_MANAGER_RESOURCE_SCOPE.md +156 -0
  24. swbt_python-0.1.0/spec/complete/unit_016/JSON_KEY_STORE_CURRENT_PREVIOUS.md +188 -0
  25. swbt_python-0.1.0/spec/complete/unit_017/SWITCH_GAMEPAD_API_HARDENING.md +206 -0
  26. swbt_python-0.1.0/spec/complete/unit_018/KEY_STORE_TRANSPORT_BOUNDARY.md +160 -0
  27. swbt_python-0.1.0/spec/complete/unit_019/TRANSPORT_RECONNECT_CONTRACT.md +129 -0
  28. swbt_python-0.1.0/spec/complete/unit_020/STRUCTURAL_REFACTOR_BOUNDARIES.md +423 -0
  29. swbt_python-0.1.0/spec/complete/unit_021/SWITCH_GAMEPAD_INPUT_API_CONTRACT.md +186 -0
  30. swbt_python-0.1.0/spec/complete/unit_022/PUBLIC_API_USAGE_HARDWARE_DOCS.md +180 -0
  31. swbt_python-0.1.0/spec/complete/unit_023/MKDOCS_DOCUMENTATION_SITE.md +209 -0
  32. swbt_python-0.1.0/spec/complete/unit_024/STICK_INPUT_SHORTHAND_API.md +191 -0
  33. swbt_python-0.1.0/spec/complete/unit_025/IMU_INPUT_SHORTHAND_API.md +197 -0
  34. swbt_python-0.1.0/spec/complete/unit_026/LINUX_MACOS_ADAPTER_EXPERIMENTAL.md +203 -0
  35. swbt_python-0.1.0/spec/dev-journal.md +23 -0
  36. swbt_python-0.1.0/spec/initial/README.md +138 -0
  37. swbt_python-0.1.0/spec/initial/api.md +435 -0
  38. swbt_python-0.1.0/spec/initial/architecture.md +222 -0
  39. swbt_python-0.1.0/spec/initial/lifecycle.md +205 -0
  40. swbt_python-0.1.0/spec/initial/naming.md +159 -0
  41. swbt_python-0.1.0/spec/initial/protocol.md +244 -0
  42. swbt_python-0.1.0/spec/initial/risks.md +238 -0
  43. swbt_python-0.1.0/spec/initial/roadmap.md +324 -0
  44. swbt_python-0.1.0/spec/initial/testing.md +277 -0
  45. swbt_python-0.1.0/spec/initial/transport-bumble.md +243 -0
  46. swbt_python-0.1.0/src/swbt/__init__.py +37 -0
  47. swbt_python-0.1.0/src/swbt/diagnostics.py +202 -0
  48. swbt_python-0.1.0/src/swbt/errors.py +33 -0
  49. swbt_python-0.1.0/src/swbt/gamepad/__init__.py +14 -0
  50. swbt_python-0.1.0/src/swbt/gamepad/connection.py +222 -0
  51. swbt_python-0.1.0/src/swbt/gamepad/core.py +697 -0
  52. swbt_python-0.1.0/src/swbt/gamepad/output.py +73 -0
  53. swbt_python-0.1.0/src/swbt/gamepad/transport_factory.py +22 -0
  54. swbt_python-0.1.0/src/swbt/input.py +550 -0
  55. swbt_python-0.1.0/src/swbt/probe.py +150 -0
  56. swbt_python-0.1.0/src/swbt/protocol/__init__.py +1 -0
  57. swbt_python-0.1.0/src/swbt/protocol/input_report.py +77 -0
  58. swbt_python-0.1.0/src/swbt/protocol/output_report.py +58 -0
  59. swbt_python-0.1.0/src/swbt/protocol/profile.py +221 -0
  60. swbt_python-0.1.0/src/swbt/protocol/rumble.py +21 -0
  61. swbt_python-0.1.0/src/swbt/protocol/spi.py +37 -0
  62. swbt_python-0.1.0/src/swbt/protocol/subcommand.py +102 -0
  63. swbt_python-0.1.0/src/swbt/py.typed +1 -0
  64. swbt_python-0.1.0/src/swbt/report_loop.py +115 -0
  65. swbt_python-0.1.0/src/swbt/state_store.py +60 -0
  66. swbt_python-0.1.0/src/swbt/transport/__init__.py +3 -0
  67. swbt_python-0.1.0/src/swbt/transport/_bumble_acl.py +33 -0
  68. swbt_python-0.1.0/src/swbt/transport/_bumble_hidp.py +34 -0
  69. swbt_python-0.1.0/src/swbt/transport/_bumble_key_store.py +220 -0
  70. swbt_python-0.1.0/src/swbt/transport/_bumble_lifecycle.py +311 -0
  71. swbt_python-0.1.0/src/swbt/transport/_bumble_sdp.py +203 -0
  72. swbt_python-0.1.0/src/swbt/transport/base.py +81 -0
  73. swbt_python-0.1.0/src/swbt/transport/bumble.py +709 -0
  74. swbt_python-0.1.0/src/swbt/transport/fake.py +315 -0
  75. swbt_python-0.1.0/tests/conftest.py +39 -0
  76. swbt_python-0.1.0/tests/hardware/README.md +16 -0
  77. swbt_python-0.1.0/tests/hardware/test_bumble_transport.py +65 -0
  78. swbt_python-0.1.0/tests/hardware/test_close_disconnect.py +302 -0
  79. swbt_python-0.1.0/tests/hardware/test_context_manager_resource_scope.py +57 -0
  80. swbt_python-0.1.0/tests/hardware/test_input_operations.py +1018 -0
  81. swbt_python-0.1.0/tests/hardware/test_pairing_l2cap.py +224 -0
  82. swbt_python-0.1.0/tests/hardware/test_reconnect_keystore.py +313 -0
  83. swbt_python-0.1.0/tests/integration/test_examples.py +71 -0
  84. swbt_python-0.1.0/tests/integration/test_switch_gamepad_fake_transport.py +1654 -0
  85. swbt_python-0.1.0/tests/unit/fixtures/source_audit/switch_protocol_values.toml +312 -0
  86. swbt_python-0.1.0/tests/unit/test_bumble_acl.py +56 -0
  87. swbt_python-0.1.0/tests/unit/test_bumble_hidp.py +11 -0
  88. swbt_python-0.1.0/tests/unit/test_bumble_key_store_metadata.py +51 -0
  89. swbt_python-0.1.0/tests/unit/test_bumble_lifecycle.py +83 -0
  90. swbt_python-0.1.0/tests/unit/test_bumble_sdp.py +18 -0
  91. swbt_python-0.1.0/tests/unit/test_bumble_transport.py +1941 -0
  92. swbt_python-0.1.0/tests/unit/test_ci_workflow.py +39 -0
  93. swbt_python-0.1.0/tests/unit/test_diagnostics.py +67 -0
  94. swbt_python-0.1.0/tests/unit/test_docs_workflow.py +68 -0
  95. swbt_python-0.1.0/tests/unit/test_gamepad_connection_workflow.py +62 -0
  96. swbt_python-0.1.0/tests/unit/test_gamepad_output_dispatcher.py +47 -0
  97. swbt_python-0.1.0/tests/unit/test_gamepad_transport_factory.py +53 -0
  98. swbt_python-0.1.0/tests/unit/test_hardware_test_log_docs.py +73 -0
  99. swbt_python-0.1.0/tests/unit/test_input_report.py +112 -0
  100. swbt_python-0.1.0/tests/unit/test_input_state.py +299 -0
  101. swbt_python-0.1.0/tests/unit/test_mkdocs_site.py +44 -0
  102. swbt_python-0.1.0/tests/unit/test_output_report.py +33 -0
  103. swbt_python-0.1.0/tests/unit/test_package_import.py +27 -0
  104. swbt_python-0.1.0/tests/unit/test_package_metadata.py +45 -0
  105. swbt_python-0.1.0/tests/unit/test_probe_cli.py +148 -0
  106. swbt_python-0.1.0/tests/unit/test_protocol_boundary.py +32 -0
  107. swbt_python-0.1.0/tests/unit/test_protocol_profile.py +21 -0
  108. swbt_python-0.1.0/tests/unit/test_public_api_boundary.py +329 -0
  109. swbt_python-0.1.0/tests/unit/test_public_api_docstrings.py +117 -0
  110. swbt_python-0.1.0/tests/unit/test_public_docs.py +247 -0
  111. swbt_python-0.1.0/tests/unit/test_publish_workflow.py +146 -0
  112. swbt_python-0.1.0/tests/unit/test_readme_docs.py +106 -0
  113. swbt_python-0.1.0/tests/unit/test_release_gate_docs.py +20 -0
  114. swbt_python-0.1.0/tests/unit/test_report_loop.py +52 -0
  115. swbt_python-0.1.0/tests/unit/test_rumble_state.py +16 -0
  116. swbt_python-0.1.0/tests/unit/test_source_audit_fixtures.py +202 -0
  117. swbt_python-0.1.0/tests/unit/test_subcommand_responder.py +79 -0
  118. swbt_python-0.1.0/tests/unit/test_virtual_spi_flash.py +29 -0
@@ -0,0 +1,176 @@
1
+ # swbt-python Agent Guide
2
+
3
+ ## 対話
4
+
5
+ - ユーザとの対話は日本語で行う。
6
+ - 技術文書と回答は事実ベースで簡潔に書く。
7
+ - 事実、仮説、提案、未検証事項を分けて扱う。
8
+ - 実機未検証、Bumble の挙動未確認、Bluetooth adapter や Switch firmware に依存する観測は明示する。
9
+
10
+ ## プロジェクト概要
11
+
12
+ `swbt-python` は、Python から Nintendo Switch 向けの仮想入力デバイスを扱うためのライブラリである。
13
+
14
+ 主な前提は次の通り。
15
+
16
+ | 種別 | 名称 |
17
+ |---|---|
18
+ | 公開 package | `swbt-python` |
19
+ | Python module root | `swbt` |
20
+ | 主要公開 class | `SwitchGamepad` |
21
+ | 主な利用面 | Python object API |
22
+
23
+ 初期設計の正本は `spec/initial/` に置く。実装や仕様を変更する場合は、関連する設計文書との整合を確認する。
24
+
25
+ ## 初期対象
26
+
27
+ - 単一の仮想 Switch 入力デバイス。
28
+ - Pro Controller 相当の HID report。
29
+ - button、stick、neutral 入力。
30
+ - Switch からの主要 subcommand への応答。
31
+ - fake transport を使う実機なしの protocol / API 検証。
32
+ - Bumble を使う Bluetooth Classic HID Device transport。
33
+ - 実機接続時の diagnostics と trace。
34
+
35
+ 初期対象外:
36
+
37
+ - 常駐 daemon の再実装。
38
+ - 既存 JSON Lines IPC の完全互換。
39
+ - 複数 controller 同時接続。
40
+ - amiibo、NFC、IR camera の意味的実装。
41
+ - 高水準 rumble API。
42
+ - GUI。
43
+ - Switch 以外の host 対応。
44
+
45
+ ## アーキテクチャ境界
46
+
47
+ - Public API は `SwitchGamepad` に集約する。
48
+ - 入力状態は immutable な `InputState` として扱う。
49
+ - periodic report 送信は `ReportLoop` が担当する。
50
+ - Switch HID report の生成と parse は protocol 層が担当する。
51
+ - Bumble 依存は `swbt.transport.bumble` に閉じ込める。
52
+ - protocol core は Bumble、Bluetooth adapter、Switch 実機なしで単体テストできるようにする。
53
+ - public API に Bumble の object 型や callback 型を露出しない。
54
+
55
+ 参照すべき設計文書:
56
+
57
+ - `spec/initial/README.md`
58
+ - `spec/initial/architecture.md`
59
+ - `spec/initial/api.md`
60
+ - `spec/initial/protocol.md`
61
+ - `spec/initial/transport-bumble.md`
62
+ - `spec/initial/lifecycle.md`
63
+ - `spec/initial/testing.md`
64
+ - `spec/initial/roadmap.md`
65
+ - `spec/initial/risks.md`
66
+ - `spec/initial/naming.md`
67
+
68
+ ## Spec / Work Tracking
69
+
70
+ この repo は `spec/wip` 型を基本にしつつ、作業単位、根拠監査、TDD 状態、実機条件を仕様書内で追跡する。
71
+
72
+ | 目的 | path |
73
+ |---|---|
74
+ | 着手中の作業仕様 | `spec/wip/unit_XXX/FEATURE_NAME.md` |
75
+ | 完了した作業仕様 | `spec/complete/unit_XXX/FEATURE_NAME.md` |
76
+ | 小さな観測と先送り判断 | `spec/dev-journal.md` |
77
+ | 実機観測 | `docs/hardware-test-log.md` |
78
+ | 初期設計 | `spec/initial/` |
79
+
80
+ 作業仕様には、対象範囲、対象外、関連 docs、根拠監査、TDD Test List、検証、実機実行条件、先送り事項、チェックリストを含める。
81
+
82
+ 複数の作業仕様から参照する安定した判断は、既存の `spec/initial/` を更新するか、必要に応じて `spec/` 配下へ分ける。未確定の観測は `spec/dev-journal.md` に置く。
83
+
84
+ ## Agent Skills
85
+
86
+ repo-local skill は `.agents/skills` を正本として管理する。`.github/skills` には重複配置しない。
87
+
88
+ 主な skill:
89
+
90
+ - `agentic-sdd`: `spec/initial` と `spec/wip` から次の作業単位を選び、plan、実装、gate へ進める。
91
+ - `agentic-self-review`: 仕様変更、実装、PR 前に gate 結果と未検証リスクを整理する。
92
+ - `spec-format`: `spec/wip` / `spec/complete` の作業仕様を作成、更新、完了移動する。
93
+ - `dev-journal`: 小さい設計観測や先送り事項を `spec/dev-journal.md` に記録する。
94
+ - `source-audit`: Switch HID、Bumble、既存実装、実機ログ由来の値を根拠分類して記録する。
95
+ - `hardware-harness`: Bumble adapter、Bluetooth dongle、Switch 実機を使う検証の承認境界と記録項目を確認する。
96
+ - `tdd-workflow`: TDD Test List から red / green / refactor を進める。
97
+ - `tdd-test-list`: 振る舞いベースの TDD Test List を作成、更新する。
98
+ - `tdd-one-cycle`: TDD Test List の 1 項目だけを red / green / refactor で進める。
99
+ - `refactor-after-green`: green 後に観測可能な振る舞いを変えず構造を整える。
100
+ - `tidy-first`: 振る舞い変更と構造変更を分ける。
101
+ - `test-desiderata-review`: Test Desiderata に基づきテスト価値と trade-off を確認する。
102
+ - `pr-merge-cleanup`: remote 設定後に PR 作成、merge、default branch 同期、branch cleanup を行う。
103
+ - `pypi-release`: PyPI / TestPyPI 公開、version bump、release PR、publish workflow、公開後 smoke check を扱う。publish workflow / runbook が未整備の場合は release 実行前に停止する。
104
+
105
+ ## Python
106
+
107
+ - Python 実行と依存管理は `uv` 経由に統一する。
108
+ - Python script は `python ...` ではなく `uv run python ...` で実行する。
109
+ - 依存追加は `uv add <package>`、開発依存は `uv add --dev <package>` を使う。
110
+ - 型注釈は Python 3.12+ の構文を使う。
111
+ - ランタイムに不要な型 import は `if TYPE_CHECKING:` に置く。
112
+ - `from __future__ import annotations` は、実行時評価を遅延する必要がある場合だけ使う。
113
+
114
+ ## テストと検証
115
+
116
+ 標準 gate は次を基本にする。
117
+
118
+ ```console
119
+ uv sync --dev
120
+ uv run ruff format --check .
121
+ uv run ruff check .
122
+ uv run ty check --no-progress
123
+ uv run pytest tests/unit
124
+ ```
125
+
126
+ 対象となる integration test tree がある変更では、`uv run pytest tests/integration` も実行する。対象 tree がまだない場合、該当 gate は未実行理由を報告する。
127
+
128
+ pytest marker:
129
+
130
+ - `@pytest.mark.bumble`: USB Bluetooth dongle と Bumble adapter open が必要な検証。
131
+ - `@pytest.mark.hardware`: Nintendo Switch 実機、pairing、HID advertising、report loop が必要な検証。
132
+
133
+ CI で必須にする対象は、static type check、lint、unit tests、fake transport integration tests とする。Bumble adapter tests と hardware tests は CI 必須にしない。
134
+
135
+ ## 実機安全境界
136
+
137
+ 次は人間の明示承認なしに実行しない。
138
+
139
+ - USB Bluetooth dongle を Bumble から開く処理。
140
+ - Switch pairing。
141
+ - HID Device advertising。
142
+ - periodic input report loop。
143
+ - Switch-facing output report / subcommand handling。
144
+ - `bumble` または `hardware` marker のテスト。
145
+
146
+ 実機または dongle を使う command について、環境変数による実行遮断は採用しない。承認境界は、会話上の明示承認、対象 adapter、実行する command、Switch-facing 動作の範囲、cleanup plan を確認することで管理する。
147
+
148
+ 実機観測には OS、driver、dongle identity、adapter string、Bumble version、Python version、Switch model / firmware、command、result、cleanup を記録する。
149
+
150
+ ## 根拠監査
151
+
152
+ 次を追加または変更する前に `source-audit` を使う。
153
+
154
+ - HID descriptor bytes。
155
+ - input / output report ID と byte layout。
156
+ - button bit、stick packing、IMU frame。
157
+ - subcommand ID と reply payload。
158
+ - SPI flash address と返却 data。
159
+ - rumble packet layout。
160
+ - report period の default。
161
+ - Bumble HID Device / SDP / L2CAP に関する仮定。
162
+ - WinUSB / libusb / OS driver に関する仮定。
163
+
164
+ 根拠は、source fact、implementation fact、hardware observation、inference、unverified hypothesis に分ける。
165
+
166
+ ## Git / PR
167
+
168
+ - 変更を伴う作業では開始時に branch と `git status --short` を確認する。
169
+ - default branch への直接 commit は、ユーザの明示指示がある場合を除き避ける。
170
+ - Conventional Commits に準拠する。
171
+
172
+ ```text
173
+ <type>(<scope>): <subject>
174
+ ```
175
+
176
+ type は `feat` / `fix` / `docs` / `style` / `refactor` / `perf` / `test` / `build` / `ci` / `chore` / `revert` を使う。subject は日本語で記述し、末尾句点は付けない。
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 niart120
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: swbt-python
3
+ Version: 0.1.0
4
+ Summary: Python library for presenting an NX-compatible virtual Bluetooth HID input device.
5
+ Keywords: bluetooth,bluetooth-hid,controller,gamepad,hid,nx
6
+ Author: niart120
7
+ Author-email: niart120 <38847256+niart120@users.noreply.github.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 2 - Pre-Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: MacOS
14
+ Classifier: Operating System :: Microsoft :: Windows
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Typing :: Typed
21
+ Requires-Dist: bumble>=0.0.230,<0.0.231
22
+ Maintainer: niart120
23
+ Maintainer-email: niart120 <38847256+niart120@users.noreply.github.com>
24
+ Requires-Python: >=3.12
25
+ Description-Content-Type: text/markdown
26
+
27
+ # swbt-python
28
+
29
+ NX 向けの仮想 Bluetooth HID 入力デバイスを Python から扱うためのライブラリです。
30
+
31
+ 本ライブラリは pre-alpha 版です。実機での動作は Bluetooth adapter、driver、対象機器の firmware に依存します。
32
+
33
+ ## 必要なもの
34
+
35
+ - Python 3.12 以降
36
+ - uv
37
+ - Bumble が利用可能な専用 USB Bluetooth dongle
38
+
39
+ ## インストール
40
+
41
+ ```powershell
42
+ pip install swbt-python
43
+ ```
44
+
45
+ ソースから動かす場合は次を使います。
46
+
47
+ ```powershell
48
+ uv sync --dev
49
+ ```
50
+
51
+ ## ドキュメント
52
+
53
+ [公開ドキュメント](https://niart120.github.io/swbt-python/) には API、利用例、実機準備、AI エージェント向け要約があります。
54
+
55
+ - API 仕様: [API Reference](https://niart120.github.io/swbt-python/api/)
56
+ - 利用例: [Usage Guide](https://niart120.github.io/swbt-python/usage/)
57
+ - 実機構成と troubleshooting: [Hardware Guide](https://niart120.github.io/swbt-python/hardware/)
58
+ - AI エージェント向け要約: [Agent Brief](https://niart120.github.io/swbt-python/agent-brief/)
59
+
60
+ リポジトリを checkout している場合、同じ内容は `docs/` 配下でも確認できます。
61
+
62
+ ## 利用例
63
+
64
+ ```python
65
+ import asyncio
66
+ from swbt import Button, SwitchGamepad
67
+
68
+
69
+ async def main() -> None:
70
+ async with SwitchGamepad(
71
+ adapter="usb:0",
72
+ key_store_path="switch-bond.json",
73
+ ) as pad:
74
+ await pad.connect(
75
+ timeout=30.0,
76
+ allow_pairing=True,
77
+ )
78
+ await pad.tap(Button.A)
79
+ await pad.neutral()
80
+
81
+
82
+ asyncio.run(main())
83
+ ```
84
+
85
+ この例は専用 Bluetooth adapter を使い、HID advertising、pairing または reconnect、periodic report loop、入力送信を行います。専用 USB Bluetooth dongle と接続情報のファイルパスを指定し、終了時は neutral を送ってから接続を閉じます。
86
+
87
+ 接続方法、`key_store_path`、入力 API の使い分けは [Usage Guide](https://niart120.github.io/swbt-python/usage/) にあります。
88
+
89
+ ## 実機検証
90
+
91
+ 実機接続には、PC の通常 Bluetooth 機能と共有しない専用 USB Bluetooth dongle と、OS ごとの driver 準備が必要です。Windows では、[Zadig](https://zadig.akeo.ie/) などで専用 dongle に WinUSB / libwdi driver を入れてから adapter 名を確認します。
92
+
93
+ driver 準備、adapter 名の確認、troubleshooting は [Hardware Guide](https://niart120.github.io/swbt-python/hardware/) にあります。実機ログの正本は [hardware-test-log](https://niart120.github.io/swbt-python/hardware-test-log/) です。
94
+
95
+ ### 確認済み構成
96
+
97
+ 2026-07-04 時点では、Windows 11 / CSR8510 A10 / WinUSB / Switch 2 firmware 22.1.0 で、pairing、reconnect、Button A、D-pad、left / right stick、neutral 後の入力残りなしを確認済みです。adapter 名の例は `usb:0` です。
98
+
99
+ ### 試験的構成
100
+
101
+ Linux / macOS は experimental です。手順は Hardware Guide に整備されていますが、動作検証されていないことに留意してください。adapter が開けるか、pairing できるか、入力が反映されるかは未確認です。
102
+
103
+ CSR8510 A10 以外の Bluetooth dongle、Switch 2 firmware 22.1.0 以外の対象機器は確認済み構成に含めていません。
104
+
105
+ ## 開発
106
+
107
+ ```powershell
108
+ uv sync --dev
109
+ uv run ruff format --check .
110
+ uv run ruff check .
111
+ uv run ty check --no-progress
112
+ uv run pytest tests/unit
113
+ uv run pytest tests/integration
114
+ ```
115
+
116
+ ## ライセンス
117
+
118
+ MIT ライセンスです。全文は [LICENSE](https://github.com/niart120/swbt-python/blob/main/LICENSE) にあります。
119
+
120
+ ## 注記
121
+
122
+ このプロジェクトは、対象機器や関連商標の権利者から承認、後援、提携を受けたものではありません。
@@ -0,0 +1,96 @@
1
+ # swbt-python
2
+
3
+ NX 向けの仮想 Bluetooth HID 入力デバイスを Python から扱うためのライブラリです。
4
+
5
+ 本ライブラリは pre-alpha 版です。実機での動作は Bluetooth adapter、driver、対象機器の firmware に依存します。
6
+
7
+ ## 必要なもの
8
+
9
+ - Python 3.12 以降
10
+ - uv
11
+ - Bumble が利用可能な専用 USB Bluetooth dongle
12
+
13
+ ## インストール
14
+
15
+ ```powershell
16
+ pip install swbt-python
17
+ ```
18
+
19
+ ソースから動かす場合は次を使います。
20
+
21
+ ```powershell
22
+ uv sync --dev
23
+ ```
24
+
25
+ ## ドキュメント
26
+
27
+ [公開ドキュメント](https://niart120.github.io/swbt-python/) には API、利用例、実機準備、AI エージェント向け要約があります。
28
+
29
+ - API 仕様: [API Reference](https://niart120.github.io/swbt-python/api/)
30
+ - 利用例: [Usage Guide](https://niart120.github.io/swbt-python/usage/)
31
+ - 実機構成と troubleshooting: [Hardware Guide](https://niart120.github.io/swbt-python/hardware/)
32
+ - AI エージェント向け要約: [Agent Brief](https://niart120.github.io/swbt-python/agent-brief/)
33
+
34
+ リポジトリを checkout している場合、同じ内容は `docs/` 配下でも確認できます。
35
+
36
+ ## 利用例
37
+
38
+ ```python
39
+ import asyncio
40
+ from swbt import Button, SwitchGamepad
41
+
42
+
43
+ async def main() -> None:
44
+ async with SwitchGamepad(
45
+ adapter="usb:0",
46
+ key_store_path="switch-bond.json",
47
+ ) as pad:
48
+ await pad.connect(
49
+ timeout=30.0,
50
+ allow_pairing=True,
51
+ )
52
+ await pad.tap(Button.A)
53
+ await pad.neutral()
54
+
55
+
56
+ asyncio.run(main())
57
+ ```
58
+
59
+ この例は専用 Bluetooth adapter を使い、HID advertising、pairing または reconnect、periodic report loop、入力送信を行います。専用 USB Bluetooth dongle と接続情報のファイルパスを指定し、終了時は neutral を送ってから接続を閉じます。
60
+
61
+ 接続方法、`key_store_path`、入力 API の使い分けは [Usage Guide](https://niart120.github.io/swbt-python/usage/) にあります。
62
+
63
+ ## 実機検証
64
+
65
+ 実機接続には、PC の通常 Bluetooth 機能と共有しない専用 USB Bluetooth dongle と、OS ごとの driver 準備が必要です。Windows では、[Zadig](https://zadig.akeo.ie/) などで専用 dongle に WinUSB / libwdi driver を入れてから adapter 名を確認します。
66
+
67
+ driver 準備、adapter 名の確認、troubleshooting は [Hardware Guide](https://niart120.github.io/swbt-python/hardware/) にあります。実機ログの正本は [hardware-test-log](https://niart120.github.io/swbt-python/hardware-test-log/) です。
68
+
69
+ ### 確認済み構成
70
+
71
+ 2026-07-04 時点では、Windows 11 / CSR8510 A10 / WinUSB / Switch 2 firmware 22.1.0 で、pairing、reconnect、Button A、D-pad、left / right stick、neutral 後の入力残りなしを確認済みです。adapter 名の例は `usb:0` です。
72
+
73
+ ### 試験的構成
74
+
75
+ Linux / macOS は experimental です。手順は Hardware Guide に整備されていますが、動作検証されていないことに留意してください。adapter が開けるか、pairing できるか、入力が反映されるかは未確認です。
76
+
77
+ CSR8510 A10 以外の Bluetooth dongle、Switch 2 firmware 22.1.0 以外の対象機器は確認済み構成に含めていません。
78
+
79
+ ## 開発
80
+
81
+ ```powershell
82
+ uv sync --dev
83
+ uv run ruff format --check .
84
+ uv run ruff check .
85
+ uv run ty check --no-progress
86
+ uv run pytest tests/unit
87
+ uv run pytest tests/integration
88
+ ```
89
+
90
+ ## ライセンス
91
+
92
+ MIT ライセンスです。全文は [LICENSE](https://github.com/niart120/swbt-python/blob/main/LICENSE) にあります。
93
+
94
+ ## 注記
95
+
96
+ このプロジェクトは、対象機器や関連商標の権利者から承認、後援、提携を受けたものではありません。
@@ -0,0 +1,115 @@
1
+ """Hardware bring-up example for a connect, tap, neutral, and close path.
2
+
3
+ Running this file opens the configured Bluetooth adapter and sends input reports.
4
+ Use it only after explicit approval covers the adapter, target screen, trace
5
+ path, timeout, input action, and cleanup plan.
6
+ """
7
+
8
+ import argparse
9
+ import asyncio
10
+ from collections.abc import Sequence
11
+ from pathlib import Path
12
+ from typing import TextIO
13
+
14
+ from swbt import Button, DiagnosticsConfig, SwitchGamepad
15
+
16
+
17
+ async def run(
18
+ *,
19
+ adapter: str,
20
+ key_store_path: str | None,
21
+ trace_path: Path,
22
+ connect_timeout: float,
23
+ tap_duration: float,
24
+ ) -> None:
25
+ """Run one approved hardware bring-up path.
26
+
27
+ Args:
28
+ adapter: Bumble adapter moniker, such as ``"usb:0"``.
29
+ key_store_path: Optional pairing key store path.
30
+ trace_path: JSON Lines diagnostics trace output path.
31
+ connect_timeout: Seconds to wait for reconnect or pairing.
32
+ tap_duration: Seconds to keep Button A pressed.
33
+ """
34
+ trace_path.parent.mkdir(parents=True, exist_ok=True)
35
+ with trace_path.open("w", encoding="utf-8") as trace_writer:
36
+ await _bring_up_with_trace(
37
+ adapter=adapter,
38
+ key_store_path=key_store_path,
39
+ connect_timeout=connect_timeout,
40
+ tap_duration=tap_duration,
41
+ trace_writer=trace_writer,
42
+ )
43
+
44
+
45
+ async def _bring_up_with_trace(
46
+ *,
47
+ adapter: str,
48
+ key_store_path: str | None,
49
+ connect_timeout: float,
50
+ tap_duration: float,
51
+ trace_writer: TextIO,
52
+ ) -> None:
53
+ diagnostics = DiagnosticsConfig(trace_writer=trace_writer)
54
+ async with SwitchGamepad(
55
+ adapter=adapter,
56
+ key_store_path=key_store_path,
57
+ diagnostics=diagnostics,
58
+ ) as pad:
59
+ await pad.connect(
60
+ timeout=connect_timeout,
61
+ allow_pairing=True,
62
+ )
63
+ await pad.tap(Button.A, duration=tap_duration)
64
+ await pad.neutral()
65
+
66
+
67
+ def build_parser() -> argparse.ArgumentParser:
68
+ """Build the example argument parser.
69
+
70
+ Returns:
71
+ argparse.ArgumentParser: Parser for this example script.
72
+ """
73
+ parser = argparse.ArgumentParser(
74
+ description=(
75
+ "Run hardware bring-up after explicit approval. The approval scope must "
76
+ "include cleanup."
77
+ ),
78
+ )
79
+ parser.add_argument("--adapter", default="usb:0", help="Bumble adapter moniker")
80
+ parser.add_argument("--key-store", dest="key_store_path", help="pairing key store path")
81
+ parser.add_argument("--trace", required=True, type=Path, help="JSON Lines trace output path")
82
+ parser.add_argument("--timeout", default=30.0, type=float, help="connection timeout seconds")
83
+ parser.add_argument(
84
+ "--tap-duration",
85
+ default=0.08,
86
+ type=float,
87
+ help="Button A press duration seconds",
88
+ )
89
+ return parser
90
+
91
+
92
+ def main(argv: Sequence[str] | None = None) -> int:
93
+ """Run the example.
94
+
95
+ Args:
96
+ argv: Optional argument vector. ``None`` reads arguments from ``sys.argv``.
97
+
98
+ Returns:
99
+ int: Process exit code.
100
+ """
101
+ args = build_parser().parse_args(argv)
102
+ asyncio.run(
103
+ run(
104
+ adapter=args.adapter,
105
+ key_store_path=args.key_store_path,
106
+ trace_path=args.trace,
107
+ connect_timeout=args.timeout,
108
+ tap_duration=args.tap_duration,
109
+ )
110
+ )
111
+ return 0
112
+
113
+
114
+ if __name__ == "__main__":
115
+ raise SystemExit(main())
@@ -0,0 +1,98 @@
1
+ """Pairing probe example with diagnostics trace output.
2
+
3
+ Running this file opens the configured Bluetooth adapter, starts HID advertising,
4
+ and waits for a host connection. Use it only after explicit approval covers the
5
+ adapter, target screen, trace path, timeout, and cleanup plan.
6
+ """
7
+
8
+ import argparse
9
+ import asyncio
10
+ from collections.abc import Sequence
11
+ from pathlib import Path
12
+ from typing import TextIO
13
+
14
+ from swbt import DiagnosticsConfig, SwitchGamepad
15
+
16
+
17
+ async def run(
18
+ *,
19
+ adapter: str,
20
+ key_store_path: str | None,
21
+ trace_path: Path,
22
+ pair_timeout: float,
23
+ ) -> None:
24
+ """Run one approved pairing probe.
25
+
26
+ Args:
27
+ adapter: Bumble adapter moniker, such as ``"usb:0"``.
28
+ key_store_path: Optional pairing key store path.
29
+ trace_path: JSON Lines diagnostics trace output path.
30
+ pair_timeout: Seconds to wait for a host connection.
31
+ """
32
+ trace_path.parent.mkdir(parents=True, exist_ok=True)
33
+ with trace_path.open("w", encoding="utf-8") as trace_writer:
34
+ await _pair_with_trace(
35
+ adapter=adapter,
36
+ key_store_path=key_store_path,
37
+ pair_timeout=pair_timeout,
38
+ trace_writer=trace_writer,
39
+ )
40
+
41
+
42
+ async def _pair_with_trace(
43
+ *,
44
+ adapter: str,
45
+ key_store_path: str | None,
46
+ pair_timeout: float,
47
+ trace_writer: TextIO,
48
+ ) -> None:
49
+ diagnostics = DiagnosticsConfig(trace_writer=trace_writer)
50
+ async with SwitchGamepad(
51
+ adapter=adapter,
52
+ key_store_path=key_store_path,
53
+ diagnostics=diagnostics,
54
+ ) as pad:
55
+ await pad.pair(timeout=pair_timeout)
56
+
57
+
58
+ def build_parser() -> argparse.ArgumentParser:
59
+ """Build the example argument parser.
60
+
61
+ Returns:
62
+ argparse.ArgumentParser: Parser for this example script.
63
+ """
64
+ parser = argparse.ArgumentParser(
65
+ description=(
66
+ "Run a pairing probe after explicit approval. The approval scope must include cleanup."
67
+ ),
68
+ )
69
+ parser.add_argument("--adapter", default="usb:0", help="Bumble adapter moniker")
70
+ parser.add_argument("--key-store", dest="key_store_path", help="pairing key store path")
71
+ parser.add_argument("--trace", required=True, type=Path, help="JSON Lines trace output path")
72
+ parser.add_argument("--timeout", default=30.0, type=float, help="pairing timeout seconds")
73
+ return parser
74
+
75
+
76
+ def main(argv: Sequence[str] | None = None) -> int:
77
+ """Run the example.
78
+
79
+ Args:
80
+ argv: Optional argument vector. ``None`` reads arguments from ``sys.argv``.
81
+
82
+ Returns:
83
+ int: Process exit code.
84
+ """
85
+ args = build_parser().parse_args(argv)
86
+ asyncio.run(
87
+ run(
88
+ adapter=args.adapter,
89
+ key_store_path=args.key_store_path,
90
+ trace_path=args.trace,
91
+ pair_timeout=args.timeout,
92
+ )
93
+ )
94
+ return 0
95
+
96
+
97
+ if __name__ == "__main__":
98
+ raise SystemExit(main())