LinuxのNetworkManagerでWi-FiのAPを切り替え

PCのLinuxは仮にリモート操作で何かやらかしてもモニターを見ながらキーボード・マウスでローカル操作することで大抵は解決できる。
シングルボードコンピュータの場合はそもそもモニターを接続できないのも多いので、リモート操作でネットワークの設定をやらかすなどするとシリアル接続にするかストレージになってるmicroSDカードを抜いてPCにつないで直接書き換えるかなどしないといけないことがある。しかし、最近のLinuxではNetworkManagerで設定するようになってる、USB OTGでシリアル接続できない、microSDをPCにつないでも直接触れないとかいろいろ解決が面倒な場合がある。各種シングルボード用にDebian, Ubuntuを提供しているarmbianでは簡易設定用にarmbian-configなるツールが提供されているのだが、Wi-Fiの設定について言えばarmbian-configは中途半端すぎて使い物にならない。同じLANにある別のSSIDのAPに切り替えたいという至極単純な欲求があったとしてもそれすら満足に叶えてくれない。
そこで、今回はNetworkManagerで別のAPに接続替えを行うという簡単なことのメモ。

やりたいこと: Wi-Fi接続中のLinuxコンピュータをリモートから別のAPに切り替える(NetworkManagerで)

$ nmcli device wifi list
IN-USE  SSID     MODE   CHAN  RATE        SIGNAL  BARS      SECURITY  
*       old-ap   Infra  1     130 Mbit/s  62      ▂▄▆__  WPA1 WPA2 
        new-ap   Infra  1     270 Mbit/s  100     ▂▄▆█  WPA1 WPA2 

まず、周囲で動いている (電波を出している) APのリストを表示する。
SSIDがold-apの方が現在使用しているAPで、new-apはこれから使いたいAP。

$ sudo nmcli device wifi connect new-ap password new-apのpsk
Error: Connection activation failed: (7) Secrets were required, but not provided.
エラーにはなってるけど、これでnew-apのAP情報(プロファイル)自体は登録出来ている。DHCPクライアント用ならプロファイルはこれだけでいい。
このコマンドだとプロファイルのconnection.idとssidが同じになる筈なので扱いやすい。
$ nmcli connection show
NAME                UUID                                  TYPE      DEVICE 
old-ap              e8937948-72fd-414e-91c3-e60c72c3bb55  wifi      wlan0  
new-ap              5d3719fc-f59c-4a09-93a9-5e89bbe72432  wifi      --     
Wired connection 1  2ab1b4e8-2763-376c-84cd-008007b62597  ethernet  --     
old-apとnew-apの両方が登録されていて、old-apがwlan0で使われていて、new-apが使われていないことが判る。
$ sudo nmcli c down old-ap && sudo nmcli c up new-ap && nmcli c s
Connection 'old-ap' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/3)
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/4)
NAME                UUID                                  TYPE      DEVICE 
new-ap              5d3719fc-f59c-4a09-93a9-5e89bbe72432  wifi      wlan0  
old-ap              e8937948-72fd-414e-91c3-e60c72c3bb55  wifi      --     
Wired connection 1  2ab1b4e8-2763-376c-84cd-008007b62597  ethernet  --     
nmcli cのcはconnectionの省略形。今回は長くならないように省略形で書いた。showもsに省略できる。
ここで、old-apとの接続をダウンさせてnew-apとの接続をアップさせるコマンドを連続する形で実行する。old-apとの接続をダウンだけを実行してしまうとその時点でお手上げになることがある。電源ブッチで再度システムを起動すればold-ap(またはnew-ap)との接続が行われるとは思うけどあまり良くない。
$ sudo nmcli connection delete id old-ap
Connection 'old-ap' (e8937948-72fd-414e-91c3-e60c72c3bb55) successfully deleted.
old-apのプロファイルを削除する。
$ nmcli connection show
NAME                UUID                                  TYPE      DEVICE 
new-ap              5d3719fc-f59c-4a09-93a9-5e89bbe72432  wifi      wlan0  
Wired connection 1  2ab1b4e8-2763-376c-84cd-008007b62597  ethernet  --

new-apの登録だけになっている筈。動作としては確実なので接続したいAPのプロファイルだけ登録した状態にするのがオススメ。

$ sudo nmcli connection modify new-ap connection.autoconnect no
または
$ sudo nmcli connection modify new-ap connection.autoconnect yes
登録済みのプロファイルは1つだけにするのがオススメとは書いたが、そうはできないこともある。
オートコネクトをyesにすると次回のシステム起動時などに自動的にそのAPに接続する。自動接続して欲しくないAPのプロファイルはオートコネクトをnoにしておく。
$ nmcli -p connection show new-ap
===============================================================================
                     Connection profile details (new-ap)
===============================================================================
connection.id:                          new-ap
connection.uuid:                        5d3719fc-f59c-4a09-93a9-5e89bbe72432
connection.stable-id:                   --
connection.type:                        802-11-wireless
connection.interface-name:              --
connection.autoconnect:                 yes
connection.autoconnect-priority:        0
connection.autoconnect-retries:         -1 (default)
connection.multi-connect:               0 (default)
connection.auth-retries:                -1
connection.timestamp:                   1597841023
connection.read-only:                   no
connection.permissions:                 --
connection.zone:                        --
connection.master:                      --
connection.slave-type:                  --
connection.autoconnect-slaves:          -1 (default)
connection.secondaries:                 --
connection.gateway-ping-timeout:        0
connection.metered:                     unknown
connection.lldp:                        default
connection.mdns:                        -1 (default)
connection.llmnr:                       -1 (default)
-------------------------------------------------------------------------------
802-11-wireless.ssid:                   new-ap
802-11-wireless.mode:                   infrastructure
802-11-wireless.band:                   --
802-11-wireless.channel:                0
802-11-wireless.bssid:                  --
802-11-wireless.rate:                   0
802-11-wireless.tx-power:               0
後略 (結構大量に表示される)
connection.autoconnectが指定した値 yes or no になっていることを確認する。(上の例ではyes)

簡単だけど意外と面倒。