利用可能なシリアルポート一覧を取得する

Recipe ID: hw-002

PC に接続されているシリアルポートデバイスの一覧(USBシリアル変換アダプタなどを含む)を取得する方法です。

1. コマンドの実装

serialport::available_ports() を使用します。

#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
struct SerialPortInfo {
    port_name: String,
    port_type: String, // "USB" or "PCI" or "Bluetooth" etc
}

#[tauri::command]
fn list_ports() -> Result<Vec<SerialPortInfo>, String> {
    let ports = serialport::available_ports().map_err(|e| e.to_string())?;
    
    let result = ports.into_iter().map(|p| {
        let port_type = match p.port_type {
            serialport::SerialPortType::UsbPort(info) => {
                format!("USB (VID:{:04x} PID:{:04x})", info.vid, info.pid)
            },
            serialport::SerialPortType::PciPort => "PCI".to_string(),
            serialport::SerialPortType::BluetoothPort => "Bluetooth".to_string(),
            _ => "Unknown".to_string(),
        };

        SerialPortInfo {
            port_name: p.port_name,
            port_type,
        }
    }).collect();

    Ok(result)
}

作成したコマンドを src-tauri/src/lib.rs で登録することを忘れないでください。

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![list_ports])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

2. フロントエンドでの表示

import { invoke } from '@tauri-apps/api/core';

type SerialPortInfo = {
    portName: string;
    portType: string;
};

// リスト取得
const ports = await invoke<SerialPortInfo[]>('list_ports');
ports.forEach(p => console.log(p.portName)); 
// Windows: "COM1", "COM3"
// macOS: "/dev/tty.usbserial-XXXX"
// Linux: "/dev/ttyUSB0"

この一覧をプルダウンメニューなどでユーザーに選択させ、接続ボタンを押したときにポート名をバックエンドに送るのが一般的なUIパターンです。