用 SSH 控制 Android 手機:從 Termux 安裝到遠端拍照的完整踩坑記錄
ASUS Ascent GX10控制的第三台: Android 手機
這台 vivo(V2248,Android 15)原本只是口袋裡的電話。今天把它變成 AI fleet 的第 4 台成員:GX10 可以透過 Tailscale 直接 SSH 進去,甚至叫它用後鏡頭拍一張照回傳,再用 AI 分析畫面——全部不經過任何雲端服務。
過程比預期長,踩了 7 個坑。全部記錄如下。
一、目標架構
GX10 (100.69.83.97)
│ ssh u0_a343@100.117.225.79 -p 8022 (Tailnet, WireGuard 加密)
▼
vivo 手機 (Termux + openssh + termux-api)
│ termux-camera-photo
▼
實體相機 → 拍照 → scp 回 GX10 → AI 視覺分析
核心思路:Android 沒有正式的「SSH server」,但 Termux 可以跑一套完整的 Linux 環境,裡面直接裝 openssh,就成了。加上 Tailscale,手機永遠是固定 IP、免開埠、任何網路可達——跟 Pi 3 同一套玩法。
二、手機端安裝(3 個 app)
| App | 來源 | 用途 |
|---|---|---|
| Termux(主程式) | F-Droid 或 GitHub(⚠️ 不能用 Play Store 版,已棄置) | Linux 環境 |
| Termux:API | 同上 | 相機/麥克風/感測器等硬體橋接 |
| Tailscale | 任何 store 都可以 | 加密私有網路 |
⚠️ 前兩個必須同來源(F-Droid 裝主程式+副程式,GitHub 也成對裝)——簽名金鑰不同就互相拒絕通訊,這是 Termux 生態最常見的坑。
三、踩坑總表(7 個,依發生順序)
坑 1:ssh-host-config: command not found
- 現象:pkg install openssh 成功、主機金鑰都生好了,但這支腳本找不到
- 真相:openssh 10.x 的 Termux 封裝裡,
ssh-host-config是獨立套件的一部分,沒裝上不影響 sshd 本身 - 解法:根本不需要這支——手動把金鑰放進
~/.ssh/authorized_keys就行,sshd 預設就讀那裡
坑 2:sv enable sshd / sv start sshd 全部失敗
- 現象:
unable to change to service directory: …/service: No such file or directory,錯誤路徑裡還雜訊亂入字元(「y」) - 真相:Termux 的開源版本沒有預設的 service 骨架;「雜訊字元」是手機輸入法在長命令黏貼時拆行掉字
- 解法:繞過 sv——用
nohup背景跑 + 自己寫 boot script(見第五節)
坑 3:長命令黏貼全部變調
- 現象:
rm -f file報missing operand、nohup … & sleep 2報Extra argument: sleep、ls -ld ~變unknown option -- -、-e參數被吞……同一台手機、同一條命令,重貼 3-5 次才有一次成功 - 真相:黏貼是這次最大坑。長命令經過輸入法層時會拆字、吞引號、吞
-參數 - 解法:(a) 命令盡量拆短、一詞一詞手打;(b) 需要放檔案時改用「GX10 開 mini HTTP + 手機 curl 拉取」——完全免黏貼(坑 5 的核心解法)
坑 4:Connection refused × 2
- 現象:每次我連都拒接
- 真相:第一次是 sshd 沒啟動;第二次是跑 sshd 的前台視窗被關掉了——Android 的記憶體管理會清掉「看起來背景」的行程
- 解法:最後用純前台
sshd -p 8022 -D -e跑通(螢幕上一直能看到Server listening on :: port 8022);常駐方案見第五節
坑 5:金鑰 92 bytes vs 93 bytes,連 3 次 Permission denied(★最終坑★)
- 現象:sshd 在聽、埠通、權限 700/600 都對了,但所有金鑰都被拒;root、u0_a123 也試過都不對
- 真相:我貼進去的公鑰少了一個字元(92 vs 93)——又是坑 3 的輸入法拆字,只是這次是內容被吃而不是命令,完全無從對齊
- 解法(妙手):GX10 上一行命令開
python3 -m http.server 8931,手機上一行 curl 從尾網直接拉取:
curl -o ~/.ssh/authorized_keys http://100.69.83.97:8931/id_ed25519.pub
然後雙邊 sha256 校驗(f3498230…995e67d 逐字一致)→ 下一次 SSH 一次過。這是整篇文章最重要的一課:凡是「長字串跨機器」,永遠走傳輸驗證,不要靠手貼。
坑 6:termux-camera-photo: missing file argument / unknown option -f
- 真相:這台裝的是老版 Termux:API(0.60 代號,官方已 0.53 重編),語法跟線上文件不符——老版用位置參數、沒有
-f - 解法:直接
cat那支 sh 腳本看 usage,一行就知道:termux-camera-photo <output文件路徑>(絕對路徑)
坑 7:閃光燈 = 軟體層沒打開
- 硬體:✅ 有(
termux-camera-info顯示ON_ALWAYS_FLASH能力) - 軟體:❌ 翻完 Termux:API 原始碼(CameraPhotoAPI.java)確認:接收器只讀
file和camera兩個參數,沒有 FLASH_MODE - 嘗試:
am start -a android.media.action.IMAGE_CAPTURE --ei android.intent.extra.FLASH_MODE 1→ vivo 相機 App 的相容性問題,照片不落盤 - 結論:A 方案(原生相機 App 手動設「閃光燈常亮」+ Intent 跳轉)最實際;B 方案(自己寫 Camera2 小程序)成本高;C 方案(等上游加參數)最被動
四、最終就緒的連線方式
# 從 GX10(或任何尾網成員, 包含你的筆記本/iPhone 如果裝了 Tailscale):
ssh u0_a343@100.117.225.79 -p 8022
# 免密、公鑰登入 (ed25519: hermes-gx10, 93 bytes, sha256 已校驗)
五、常駐設定(重開機不死)
| 檔 | 作用 |
|---|---|
~/sshd-start |
一鍵重啟:pkill→nohup sshd -p 8022 -D→ps 自我檢查,報 SSHd-OK 或完整錯誤 |
~/.termux/boot-script.sh |
調 ~/sshd-start,Termux 重開機時自動觸發 |
| 電池優化(手動設) | 設定→應用程式→Termux→電池→不受限(不設的話 Android 幾個小時後會殺 sshd) |
| 自動重啟(手動設) | Termux 選單→「自動啟動」打開 |
⚠️ 實測發現:sv 這套在 Termux 開源版不好使(~/.sv 不存在、$PREFIX/var/service 也找不到),所以用上面的手動 boot script 方案,穩定且可控。
六、手機資源盤點(連上後第一時間拿的)
| 項目 | 值 |
|---|---|
| 型號 | vivo V2248 |
| Android | 15 (API 35) |
| SoC | 聯發科 MT6833 (Dimensity 700) |
| CPU | 8 核 aarch64 |
| RAM | 7.4 GB(可用 ~3.2 GB) |
| 內部儲存 | 228 GB,已用 129 GB(57%) |
| Termux 套件 | 86 個 |
| 尾網 IP | 100.117.225.79(固定, 永不变) |
七、遠端相機——已驗證成功的命令
# 從 GX10 遠端叫拍照 (手機後鏡頭):
ssh u0_a343@100.117.225.79 -p 8022 \
'termux-camera-photo /data/data/com.termux/files/home/shot.jpg'
# 拉回來 (照片 3060×4080, 940KB~2MB):
scp -P 8022 u0_a343@100.117.225.79:/data/data/com.termux/files/home/shot.jpg ./
# 前置鏡頭:
ssh … 'termux-camera-photo -c 1 /path/to/front.jpg'
已實拍兩張驗證:第一張 940K,第二張 2.0M(客廳夜景、沙發上有人的場景)。
七.5、遠端聲音——打雷、TTS 中文朗讀(實測通過)
同一條 SSH 通道,手機喇叭也能被遠端控制,有兩招都實測成功:
招一:遠端播放音效
1. GX10 上用 Python 合成一段 8 秒低頻滾雷 WAV(布朗噪聲 + 三記指數衰減包絡,352KB)
2. scp -P 8022 thunder.wav u0_a343@100.117.225.79:thunder.wav
3. ssh … 'termux-media-player play ~/thunder.wav' → 手機喇叭響「轟——隆隆隆」三記雷聲
4. 已重播兩次,兩次都 rc=0,用戶親耳確認
招二:遠端 TTS 中文朗讀
ssh u0_a343@100.117.225.79 -p 8022 'termux-tts-speak "張瑞琪,起床了"'
→ 手機喇叭直接念中文繁體(用 Android 系統 TTS 引擎),一詞 rc=0。
附帶能力:termux-volume 可遠端讀/改六條音軌(ring/music/alarm/notification/system/call)的音量;配合 cron 可做「定時叫起床」「遠端報時」「警報推送」。
⚠️ 小坑:
– termux-media-player 要寫 play <檔案> 子命令,直接帶檔案會報 Invalid cmd
– SCP 落點要用相對家目錄(如 u0_a343@…:thunder.wav),用絕對路徑 /sdcard/ 在 Termux 環境會落錯位置
– TTS 要送繁體——手機端的引擎對簡體轉換不一定準確(「張」送成「张」聲母會跑)
八、總結
最難的不是 sshd 本身——Termux 把它包得很完整。
真正難的有兩個:
1. 輸入法黏貼長字串會掉字——任何跨機器的金鑰/設定,都應該走檔案傳輸 + 雜湊校驗,不要靠手貼
2. Android 的「活著」需要主動維持——電池優化、自動重啟、boot script 三件事都要做到,sshd 才會像你 Pi 3 的 pm2 一樣穩定常駐
這台 vivo 現在是 fleet 的第 4 台:GX10(大腦)、Pi 5(GPIO 控制)、Pi 3(鏡面)、手機(行動終端 + 遠端相機)——同一個 Tailscale,同一套 SSH key,任何一台上都能跳進另外三台。
沒有留言:
張貼留言