Nikon COOLPIX A1000をPCから操作できるか調べた
目次
COOLPIX A1000を持っているが、PCから画像を取り込んだりリモート撮影したりできるのか気になった。 Nikonの公式ソフトウェアはDSLR/Zシリーズ向けばかりで、コンパクトカメラは基本スマホのSnapBridgeに誘導される。
じゃあ自分で繋げばいいじゃん、ということでプロトコルレベルから調べてみた。
COOLPIX A1000の接続スペック
まず公式リファレンスマニュアル(p.226-228)から引っ張ってきた仕様。
| インターフェース | 仕様 |
|---|---|
| USB | Micro-USB(UC-E21)、Hi-Speed USB 2.0 |
| USBプロトコル | MTP / PTP / PictBridge |
| WiFi | IEEE 802.11b/g(2.4GHz、ch1-11) |
| WiFi認証 | Open / WPA2-PSK |
| WiFiモード | APモード(カメラがAP) / STAモード(既存ネットワーク参加) |
| Bluetooth | Bluetooth 4.1 + BLE |
注意点として、802.11nは非対応。サードパーティのスペックサイトでは対応と書かれていることがあるが、公式マニュアルにはb/gのみと明記されている。Bluetoothも4.1で、同時期の超望遠モデル(Pシリーズ)と比べると据え置き。A1000以降、Aシリーズの後継は出ていない。
Nikon公式ソフトウェアの対応状況
| ソフトウェア | A1000対応 | 備考 |
|---|---|---|
| NX Studio | o | 画像閲覧・編集・管理。ViewNX-iの後継 |
| ViewNX-i | o | レガシー。Windows 11非対応 |
| Camera Control Pro 2 | x | DSLR/Zシリーズ専用 |
| Nikon Webcam Utility | x | DSLR/Zシリーズ専用 |
| SnapBridge(モバイル) | o | iOS/Android。PC版は存在しない |
Camera Control Pro 2もWebcam UtilityもCOOLPIXは対象外。公式にPCからリモート操作する手段はない。 NX Studioは画像管理ソフトであって、カメラ制御はできない。
USB接続(MTP/PTP)
A1000をUSBで繋ぐと、OSからはMTP/PTPデバイスとして認識される。
macOSの ioreg -p IOUSB で確認した実機の情報はこうなった。
| 項目 | 値 |
|---|---|
| デバイス名 | NIKON DSC COOLPIX A1000 |
| Vendor ID | 0x04B0(Nikon) |
| Product ID | 0x036B |
| USB | Hi-Speed USB 2.0(480Mbps) |
| シリアル | 000021000717 |
| 消費電力 | 500mA |
なお、SwiftMTPのデバイスデータベースにはA1000のProduct IDが 0x4038 と登録されているが、実機は 0x036B だった。ファームウェアバージョンや地域で異なる可能性もあるが、少なくとも手元の個体はこの値。
gphoto2での認識
オープンソースのカメラ制御ライブラリlibgphoto2のソースコード(camlibs/ptp2/library.c)を調べた。
A1000は未登録。登録されているCOOLPIXモデルと比較するとこうなった。
| モデル | Product ID | キャプチャ対応 | フラグ |
|---|---|---|---|
| COOLPIX A900 | 0x019e | 制限あり | PTP_NIKON_BROKEN_CAP |
| COOLPIX B700 | 0x0231 | あり(プレビュー付き) | - |
| COOLPIX P1000 | 0x0232 | あり(プレビュー付き) | - |
| COOLPIX P1100 | 0x0234 | あり(プレビュー付き) | - |
| COOLPIX B500 | 0x0362 | 制限あり | PTP_NIKON_BROKEN_CAP |
| COOLPIX A1000 | 0x036B(実測) | 未登録 | - |
A900にはPTP_NIKON_BROKEN_CAPフラグがついていて、リモートキャプチャに問題があることを示している。
A1000はA900の後継なので、仮にlibgphoto2に追加しても同様の制限がある可能性が高い。
ただし、libgphoto2にはPTPクラスの汎用検出フォールバックがあるので、gphoto2 --auto-detectで繋いでみれば基本的なファイル転送は動くかもしれない。
macOSの罠
macOSはPTPデバイスを自動的にグラブする(PTPCameraプロセス)。gphoto2を使う場合は先にこれを殺す必要がある:
killall PTPCamera
gphoto2 --auto-detect
WiFi接続(PTP/IP)
ここからが本題。A1000のWiFi通信はPTP/IP(Picture Transfer Protocol over IP)を使っている。
PTP/IPの基本
PTP/IP(CIPA DC-X005-2005)はもともとNikonとFotoNationが共同開発した規格で、PTPコマンドをTCP/IPで運ぶ。
| 項目 | 値 |
|---|---|
| ポート | TCP 15740 |
| 接続数 | 2本(Command/Data + Event) |
| カメラIP | APモードでは通常 192.168.1.1 |
パケット構造
PTP/IPのパケットはすべて同じヘッダ構造を持つ:
[4バイト: パケット長][4バイト: タイプコード][ペイロード]
リトルエンディアン。主要なタイプコードをまとめた。
| コード | 方向 | 名前 | 内容 |
|---|---|---|---|
| 0x01 | Client→Camera | Init_Command_Request | 16バイトGUID + UTF-16クライアント名 |
| 0x02 | Camera→Client | Init_Command_Ack | セッションID + 16バイトGUID + UTF-16カメラ名 |
| 0x03 | Client→Camera | Init_Event_Request | セッションID(type 0x02から取得) |
| 0x04 | Camera→Client | Init_Event_Ack | - |
| 0x06 | Client→Camera | Cmd_Request | PTPコマンドコード + Transaction ID + 引数 |
| 0x07 | Camera→Client | Cmd_Response | PTPレスポンスコード + Transaction ID + 引数 |
| 0x09 | Either | Start_Data_Packet | データ転送開始 |
| 0x0A | Either | Data_Packet | データ本体 |
| 0x0C | Either | End_Data_Packet | データ転送終了 |
接続シーケンス
sequenceDiagram
participant PC as PC
participant Cam as COOLPIX A1000<br/>(192.168.1.1:15740)
Note over PC,Cam: Command/Dataチャネル(TCP接続1本目)
PC->>Cam: Init_Command_Request<br/>(GUID + クライアント名)
Cam->>PC: Init_Command_Ack<br/>(セッションID + GUID + カメラ名)
Note over PC,Cam: Eventチャネル(TCP接続2本目)
PC->>Cam: Init_Event_Request<br/>(セッションID)
Cam->>PC: Init_Event_Ack
Note over PC,Cam: PTPセッション開始
PC->>Cam: OpenSession (0x1002)
Cam->>PC: OK (0x2001)
PC->>Cam: GetDeviceInfo (0x1001)
Cam->>PC: DeviceInfo(対応コマンド一覧等)
Nikon固有のPTPオペコード
PTPの標準コマンド(0x1001〜0x101B)に加えて、Nikonは0x9000番台の独自コマンドを実装している。
libgphoto2のptp.hから主要なものを抜き出した。
| オペコード | 名前 | 機能 |
|---|---|---|
| 0x90C0 | InitiateCaptureRecInSdram | SDRAMにキャプチャ |
| 0x90C1 | AFDrive | AF駆動 |
| 0x90C2 | ChangeCameraMode | カメラモード切替 |
| 0x90C7 | CheckEvents | イベント取得 |
| 0x90C8 | DeviceReady | デバイス準備状態確認 |
| 0x9201 | StartLiveView | ライブビュー開始 |
| 0x9202 | EndLiveView | ライブビュー終了 |
| 0x9203 | GetLiveViewImg | ライブビュー画像取得 |
| 0x9207 | InitiateCaptureRecInMedia | メディアにキャプチャ |
| 0x920A | StartMovieRecInCard | 動画記録開始 |
| 0x920B | EndMovieRec | 動画記録終了 |
A1000がこれらのコマンドにどこまで応答するかは実機テストで確認する。COOLPIX系は一部コマンドが未実装だったり、エラーを返すケースがある。
BLE通信の実機テスト
BLEスキャン
PythonのbleakライブラリでBLEスキャンをかけた。カメラのメニューから「スマホと接続」画面を開いた状態でアドバタイズが飛ぶ。
A1000_21000717 addr=36C20FB9-... mfr={}
Service UUIDs: ['0000de00-3dd4-4255-8d62-6dc7b9bd5561']
SnapBridgeのサービスUUID 0000de00-3dd4-4255-8d62-6dc7b9bd5561 を確認。ただしManufacturer Dataは空で、Nikon Company ID(0x0399)はアドバタイズに含まれていなかった。Company IDやデバイス名でフィルタするとヒットしない場合がある。
WiFi SSID(A1000_21000717)がそのままBLEのデバイス名になっている。
アドバタイズの挙動
スキャン方法によって検出結果がかなりブレた。
BleakScanner.discover()(スナップショット型)だと検出できたりできなかったり不安定BleakScanner(detection_callback=...)(コールバック型)だと30秒間で50回以上検出
find_device_by_name() で名前指定検索すると20秒待ってもタイムアウトすることがあった。コールバックモードで拾ってから接続する方が確実。
GATT接続(認証前)
コールバックで見つけた瞬間に BleakClient で接続。MTU 185で繋がった。
Device Information Service (0x180A):
| Characteristic | 値 |
|---|---|
| Manufacturer Name (0x2A29) | Nikon |
| Model Number (0x2A24) | A1000 |
| Firmware Revision (0x2A26) | 1.2 |
| Hardware Revision (0x2A28) | 1.2 |
認証前はSnapBridge Service内の全Characteristicがゼロ返しだった。
Blowfish認証の実装と実行
OSSプロジェクトやネットワーク解析ツールで集めた情報をもとに、SnapBridgeのBLE認証をPythonで実装して実機に送った。
認証のプロトコルはBlowfish暗号ベースのチャレンジ・レスポンス方式で、5ステージで構成される。
sequenceDiagram
participant PC
participant A1000
PC->>A1000: Stage 1(ノンス + デバイスID)
A1000->>PC: Stage 2(カメラのノンス + Blowfishハッシュ)
Note over PC: ハッシュを検証してソルトインデックスを特定
PC->>A1000: Stage 3(自分のノンスで計算したハッシュ)
A1000->>PC: Stage 4(シリアル番号)
PC->>A1000: Stage 5(完了通知)
Blowfishの鍵とソルトテーブルはfurbleプロジェクトが公開している。
実行結果:
S1-2 OK salt=4
S3-4 OK serial='21000717'
S5 sent
No NOT1
POWER=03 VALID_WAKE
認証は通った。ソルトインデックスの特定、カメラのハッシュ検証、シリアル番号の取得まで成功。ただしステージ5の後に期待される成功通知(NOT1 = 0x2008 の [0x01, 0x00])が来なかった。これはBluetooth Classicのセキュアボンディングを待っている状態。
認証後のGATT Characteristicマップ
認証が通ると、それまでゼロだったCharacteristicにデータが入る。NikonのBLE仕様書は非公開だが、通信の観察とOSSの情報を突き合わせて各Characteristicの役割が判明した。
| UUID | 名称 | 認証後の値 | 備考 |
|---|---|---|---|
| 0x2000 | AUTHENTICATION | シリアル番号入り | 認証ステージの書き込み先 |
| 0x2001 | POWER_CONTROL | 03 | 3 = VALID_WAKE(カメラ起動中) |
| 0x2002 | CLIENT_DEVICE_NAME | (write-only) | 接続元デバイス名を書き込む |
| 0x2003 | SERVER_DEVICE_NAME | A1000_21000717 | カメラのSSID名 |
| 0x2004 | CONNECTION_CONFIGURATION | 0000 | WiFi設定(暗号化)。未接続時は空 |
| 0x2005 | CONNECTION_ESTABLISHMENT | 0000 | WiFi/BTC接続トリガー |
| 0x2006 | CURRENT_TIME | ea070411123a03 | 2026-04-17 18:58:03(JST) |
| 0x2007 | LOCATION_INFORMATION | 全ゼロ(41バイト) | GPS座標の書き込み先 |
| 0x2008 | LSS_CONTROL_POINT | 0000 | 制御フラグ(notify) |
| 0x2009 | LSS_FEATURE | fd030000 | 対応機能ビットフラグ |
| 0x200A | LSS_CABLE_ATTACHMENT | (notify-only) | ケーブル接続通知 |
| 0x200B | LSS_SERIAL_NUMBER | 21000717 | カメラのシリアル |
| 0x2A19 | BATTERY_LEVEL | 64 | バッテリー残量100% |
0x2009のLSS_FEATUREは0x03FDで、WiFi・BLE・時刻同期・位置情報など対応機能をビットフラグで示している。
WiFi AP起動の試み
認証後、WiFi APの起動を試みた。0x2005(CONNECTION_ESTABLISHMENT)にWiFi要求ビット0x01を書き込む。
>>> 0x2005 <- 0x01 (WiFi) <<<
Waiting 5s for AP...
CONN_CFG=0000 (2B)
CONN_EST=0000
書き込みはエラーなしで受け付けられたが、0x2004(WiFi設定)は空のまま、0x2005も即座に0000にリセットされた。WiFi APは起動しなかった。
0x03(WiFi + Bluetooth Classic両方のビット)も試したが結果は同じ。
なぜWiFi APが起動しないか
Bluetooth Classicのセキュアボンディングが完了していないため。SnapBridgeの接続フローを解析すると、以下の順序になっている。
graph TD
A[BLE接続] --> B[Blowfish認証<br/>ステージ1-5]
B --> C{NOT1成功通知?}
C -->|来ない| D[Bluetooth Classic<br/>セキュアボンディング待ち]
D --> E[ボンディング完了]
E --> F[NOT1 = 0x01,0x00]
F --> G[0x2005に0x01書き込み]
G --> H[WiFi AP起動]
H --> I[0x2004にSSID/パスワード<br/>Blowfishで暗号化]
C -->|0x01,0x00| G
style D fill:#f66,color:#fff
style E fill:#f66,color:#fff
Pythonのbleakライブラリ(BLE専用)ではBluetooth Classicのボンディングができない。furbleプロジェクトも同じ理由で「smart device pairing not fully functional」と断念している。
リモコンモードでの接続
カメラの「リモコンと接続」メニューからリモートモードに入ると、スマートデバイスモードでは見えなかったCharacteristic(0x2080〜0x2087)が出現した。
| UUID | Properties | 役割 |
|---|---|---|
| 0x2080 | read | リモート状態1 |
| 0x2082 | read, write | リモート設定 |
| 0x2083 | write | シャッター制御 |
| 0x2084 | indicate, read | カメラフィードバック |
| 0x2086 | read | リモート状態2 |
| 0x2087 | indicate, read, write | リモートペアリング |
リモートモードのペアリングはBlowfish不要のシンプルなハンドシェイクで、ステージ1-5の全レスポンスがゼロ固定。ペアリング自体は成功し、0x2082にモード設定データ(0202030320200000...)が現れた。
しかしシャッターコマンド(0x2083に[0x02, 0x02]書き込み)はエラーなしで受け付けられるものの、カメラは反応しなかった。A1000のリモートモードはfurbleが検証したB600とプロトコルが微妙に異なる可能性がある。
SnapBridgeの通信アーキテクチャ
SnapBridgeの通信をネットワーク解析ツールで観察すると、3層のプロトコルスタックが見えてくる。
graph TD
A[SnapBridge App] --> B[BLE<br/>常時接続・ペアリング・制御]
A --> C[Bluetooth Classic<br/>一部モデルでデータ転送]
A --> D[WiFi<br/>フルサイズ画像転送]
B --> E[PTP/MTP<br/>コマンドレイヤー<br/>ISO 15740 + Nikon拡張]
C --> E
D --> E
B --> F[GATT Service<br/>UUID: 0000de00-...<br/>Blowfish認証]
D --> G[PTP/IP<br/>TCP:15740<br/>GUIDハンドシェイク]
通常の利用フロー:
- BLE常時接続でバッテリー消費を抑えつつカメラとの接続を維持
- 撮影するとBLE経由で2MP縮小画像を自動転送
- フルサイズ画像が必要になるとBLEからWiFiにハンドオフ
- PTP/IPでフルサイズJPEGを転送
- 転送完了後、WiFiを切ってBLE常時接続に戻る
BLEからWiFiへのハンドオフについては、Foolographyの開発者が「BLE ClassicとBLEとWiFiの奇妙な組み合わせ」と表現している。今回の実機テストで、このフローの全体像がかなり見えてきた。
WiFi APが起動しない
カメラの「スマホと接続」画面ではWiFi SSID(A1000_21000717)とパスワード(NikonCoolpix — 機種共通の初期値)が表示される。しかしMac/Windows両方のWiFiスキャンにSSIDが出てこなかった。BLEアドバタイズは飛んでいるのにWiFi APは動いていない。
この画面でSSIDとパスワードが表示されるのは、ペアリング完了後にWiFi APが起動した際の接続情報を事前に見せているだけ。BLE認証後に0x2005(CONNECTION_ESTABLISHMENT)にWiFi要求を書き込んでも、Bluetooth Classicのセキュアボンディングが完了していないとカメラはリクエストを無視する。
使えそうなOSSツール
調査で見つかったツールのうち、A1000で試す価値がありそうなもの。
USB経由
| ツール | 言語 | 概要 |
|---|---|---|
| gphoto2 / libgphoto2 | C | 定番のカメラ制御ライブラリ。A1000未登録だが汎用PTP検出あり |
| python-gphoto2 | Python | libgphoto2のPythonバインディング |
| SwiftMTP | Swift | macOS向けMTP実装。A1000のデバイスプロファイルが登録済み |
| miniPtp | Python | 教育用の最小PTP実装。PyUSBベース |
WiFi経由(PTP/IP)
| ツール | 言語 | 概要 |
|---|---|---|
| ptpip-d5300 | Python | Nikon D5300向けPTP/IPクライアント。A1000で最も有望 |
| libpict | C | 汎用PTP実装。USB/IPデュアル対応。Nikon拡張は未実装 |
| ptp-ip (Go) | Go | PTP/IP実装。Fujifilm向けだが標準部分は共通 |
BLE経由
| ツール | 言語 | 概要 |
|---|---|---|
| furble | C++ (ESP32) | BLEリモートシャッター。COOLPIX B600で動作確認済み |
ptpip-d5300がWiFi経由での第一候補。D5300向けだがPTP/IPは標準規格なので、基本的なファイル転送やデバイス情報取得は動く可能性がある。
pip install ptpip
from ptpip import PtpIpConnection
# A1000のWiFi APに接続した状態で
conn = PtpIpConnection("192.168.1.1", 15740)
conn.open_session()
device_info = conn.get_device_info()
print(device_info)
SnapBridgeアプリの権限
SnapBridge(com.nikon.snapbridge.cmru v2.13.3)がAndroidで要求するパーミッションも確認した。
Exodus Privacyのレポートから、注目すべき権限を抜き出した。
| パーミッション | 用途 |
|---|---|
CHANGE_WIFI_MULTICAST_STATE | マルチキャストでのデバイス探索 |
NFC | NFC対応カメラ向け(A1000はNFC非搭載) |
RECEIVE_BOOT_COMPLETED | 起動時のBLE常時接続復帰 |
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS | BLE常時接続の維持 |
FOREGROUND_SERVICE_CONNECTED_DEVICE | BLEデバイス接続のフォアグラウンドサービス |
トラッカーはAdobe Experience Cloudが1件。通信の中身としてはPTP/MTPコマンドのラッパーなので、データ漏洩リスクは低い。
Bluetooth Classicペアリング
BLE認証だけではWiFi APが起動しない。Bluetooth Classicのセキュアボンディングが必要。
Classic BTの発見
macOSのBluetooth Classicスキャン(blueutil --inquiry)では、BLE接続中にカメラのClassicデバイスは見えない。BLE認証後にBluetoothを再起動(off→on)すると、カメラが別のMACアドレスでClassicデバイスとして出現する。
| 接続方式 | MACアドレス |
|---|---|
| BLE | 毎回変わる(macOSがランダム化) |
| Bluetooth Classic | 3C:E1:A1:16:13:79(固定) |
ペアリングの成功
macOSのシステム設定(Bluetooth)から手動でNumeric Comparisonペアリングを実施。両側で同じ6桁の数字を確認してOKを押す方式。
ポイントはMac側を先にOK→すぐにカメラ側のOKの順序。逆だとタイムアウトする。blueutilやexpectでの自動化ではタイミングが合わず、macOS標準UIからの手動操作で初めて成功した。
カメラのClassic BTサービス
ペアリング後にSDP(Service Discovery Protocol)クエリで取得したカメラのサービス一覧。
| サービス名 | RFCOMM Channel | UUID |
|---|---|---|
| SPP Service | Channel 1 | 0x1101(Serial Port Profile) |
| iAP Service | Channel 2 | 独自UUID |
| GATT over L2CAP | PSM 31 | 0x1800 / 0x1801 |
SPP Serviceが存在し、macOS上に/dev/tty.A1000_21000717としてシリアルポートが出現した。
フリーズ問題
Classicペアリング成功後、カメラが「接続処理中」でフリーズする問題が発生した。Mac側にSnapBridgeのSPPサーバーがないため、カメラがRFCOMM接続を試みて永遠に待つ状態になる。電源ボタンも効かず、バッテリー抜きでしか復帰しない。
Mac側の確認タイミングとカメラ側のOK操作の順序を調整することで、フリーズせずにペアリングを完了できるケースがあった。撮影モードに戻り、BT接続を維持した状態でカメラが動作する。位置情報の設定ダイアログまで出てきたので、カメラはMacをSnapBridgeデバイスとして認識している。
写真撮影後のフラグ変化
Classicペアリング済み・BT接続維持中に写真を撮影すると、BLEの0x2008(LSS_CONTROL_POINT)が0x0000から0x0001に変化した。カメラが画像転送を要求している状態だと思われる。
しかしBLE認証(Blowfishハンドシェイク)がClassicと別セッションのため、WiFiトリガー(0x2005への書き込み)は受け付けられない。
残っている壁
SnapBridgeはBLE認証→Classicボンディング→WiFi AP起動を同一セッション内で行う。今回の実験ではBLE認証後にBluetooth再起動が必要で、セッションが分断される。
macOSではBLE接続中にClassicペアリングを同時実行する方法が見つかっていない。Androidでは同一BTスタック上で両方を処理できるが、macOSのCoreBluetooth(BLE)とIOBluetooth(Classic)は別レイヤーで動作する。
現状と次のステップ
できたこと
- USB: macOSでMTP/PTPデバイスとして認識、Product ID
0x036Bを実測 - BLE: Blowfish認証を完全実装・実行、ソルトインデックス特定、シリアル番号取得
- BLE: 全GATT Characteristicの役割を解明(13種)
- BLE: リモートモードのCharacteristic(
0x2080〜0x2087)発見とペアリング - Classic BT: macOSシステム設定からのNumeric Comparisonペアリング成功
- Classic BT: カメラのSPP/iAPサービスのSDP情報取得
- Classic BT:
/dev/tty.A1000_21000717シリアルポート出現確認 - プロトコル解析: WiFi AP起動フロー、BLE→Classic→WiFiの3段階ゲートの全容解明
突破できなかった壁
- BLE認証とClassicボンディングの同一セッション化(macOSの制約)
- WiFi APの起動(Classicボンディング後のBLE再認証でNOT1が来ない)
- RFCOMMシリアルポート経由のPTP通信(カメラが応答しない)
次に試すこと
- BLE認証時のdevice IDを固定値にして、Classicペアリング後のBLE再認証で同一デバイスとして認識させる
- Classicペアリングの手順をスクリプト化(Mac先にOK→カメラOK、タイミング調整済み)
- macOS IOBluetooth APIでBLE接続中のClassicペアリングをプログラマティックに実行
- SPPサーバーをClassicペアリング前に起動してカメラのRFCOMM接続を受け入れる
SnapBridgeはBLE→Bluetooth Classic→WiFiの3段階ゲートキーパーとして機能している。BLE認証もClassicペアリングも個別には突破できた。カメラはMacをSnapBridgeデバイスとして認識し、写真撮影後に転送フラグも立てている。残る課題は「同一セッション内での両方の完了」のみ。