dbus 控制wifi功能
原理:ubuntu系统自带的NetworkManager 守护进程专门接管了系统网络的功能,避免了用户手动写代码调用系统函数驱动来间接操作硬件。
所以有这个NetworkManager来管理这个这部分网络功能,并且提供dbus通信,让各个应用来共享该功能,避免了各个不同的应用都控制该功能导致冲突。

⚠️ 重要前提:

  • 你的系统使用 NetworkManager(检查:systemctl is-active NetworkManager 应为 active)
  • 你有无线网卡,设备名如 wlan0(可通过 ip linknmcli device 查看,但后者是工具,我们尽量不用)
  • 所有命令需在终端以普通用户或 root 执行(部分需 root,我会标注)

🎯 1. 开启 WiFi(启用无线射频)

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager \
  org.freedesktop.DBus.Properties.Set \
  string:"org.freedesktop.NetworkManager" \
  string:"WirelessEnabled" \
  variant:boolean:true

🎯 2. 关闭 WiFi(禁用无线射频)

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager \
  org.freedesktop.DBus.Properties.Set \
  string:"org.freedesktop.NetworkManager" \
  string:"WirelessEnabled" \
  variant:boolean:false

🎯 3. 连接指定的 WiFi(SSID + 密码)

这需要 3 步

Step 1️⃣:扫描 WiFi(可选,确保目标 AP 可见)

该命令行相当于查看当前的网络设备有哪些

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager \
  org.freedesktop.NetworkManager.GetDevices

从返回结果中找到你的无线设备路径,比如:/org/freedesktop/NetworkManager/Devices/3

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager/Devices/7 \
  org.freedesktop.DBus.Properties.Get \
  string:"org.freedesktop.NetworkManager.Device" \
  string:"Interface"

它会告诉你 /Devices/7 对应的名字(比如 docker0 或 virbr0)。

方法 2:用 dbus-send 查类型


dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager/Devices/3 \
  org.freedesktop.DBus.Properties.Get \
  string:"org.freedesktop.NetworkManager.Device" \
  string:"DeviceType"


# 返回值是一个数字:
| 数字 | 类型                                                  |
| -- | --------------------------------------------------- |
| 0  | Unknown                                             |
| 1  | Ethernet                                            |
| 2  | Wi-Fi (802.11 wireless LAN)                         |
| 3  | Unused (保持兼容)                                       |
| 5  | Bridge                                              |
| 6  | VLAN                                                |
| 7  | Modem (GSM/UMTS/LTE, CDMA, etc.) ← 📡 就是 4G/USB 上网卡 |
| 8  | Infiniband                                          |
| 9  | Bond                                                |
| 10 | Veth                                                |
| 11 | Macvlan                                             |
| 12 | VXLAN                                               |
| 13 | VethPair                                            |
| 14 | Tun/Tap                                             |
|| 其他虚拟设备类型                                            |

# 等等

然后请求扫描:
RequestScan 只是触发扫描,不返回结果(dbus会扫到wifi会增加对应的AccessPoint的路径对象,每个都表示一个wifi)

 # 无问题
 busctl call \
  org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager/Devices/3 \
  org.freedesktop.NetworkManager.Device.Wireless \
  RequestScan \
  a{sv} 0

Step 2️⃣:获取目标 AP 的对象路径

等待几秒(5s)让扫描完成。(会触发信号当扫描到wifi的时候)

# 监听信号
dbus-monitor --system "interface='org.freedesktop.NetworkManager.Device.Wireless'"

获取对应的AccessPoint 与SSId的输出

for ap in $(dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager/Devices/3 \
  org.freedesktop.NetworkManager.Device.Wireless.GetAllAccessPoints \
  | grep object | awk '{print $3}' | tr -d '"'); do

  ssid=$(dbus-send --system --print-reply \
    --dest=org.freedesktop.NetworkManager \
    $ap \
    org.freedesktop.DBus.Properties.Get \
    string:"org.freedesktop.NetworkManager.AccessPoint" \
    string:"Ssid" \
)
  if [ -n "$ssid" ]; then
    echo "$ap"
    echo "$ssid"
    echo ""
  fi

done

# 获取可连接的wifi 上面扫描完成之后 会增加AccessPoint的对象这里,列出来所有的可连接的wifi

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager/Devices/3 \
  org.freedesktop.NetworkManager.Device.Wireless.GetAccessPoints

# 包括不可访问的wifi
dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager/Devices/3 \
  org.freedesktop.NetworkManager.Device.Wireless.GetAllAccessPoints

在返回列表中找到你要连接的 SSID 对应的路径,如:/org/freedesktop/NetworkManager/AccessPoint/123


Step 3️⃣:创建并激活连接

先创建一个临时连接配置(一次性,不保存):
用命令行很难做出来,这里给出python调用dbus功能连接指定的wifi
wifi名字叫gt 密码是12345678
python 连接指定的wifi

#!/usr/bin/env python3
import dbus
import uuid
import sys

SSID = "gt"
PASSWORD = "12345678"

bus = dbus.SystemBus()
NM_BUS_NAME = "org.freedesktop.NetworkManager"
NM_OBJECT_PATH = "/org/freedesktop/NetworkManager"

nm_proxy = bus.get_object(NM_BUS_NAME, NM_OBJECT_PATH)
nm_iface = dbus.Interface(nm_proxy, NM_BUS_NAME)

# 1️⃣ 找到无线设备
devices = nm_iface.GetDevices()
wifi_device = None
interface_name = None

for dev_path in devices:
    dev_proxy = bus.get_object(NM_BUS_NAME, dev_path)
    dev_props = dbus.Interface(dev_proxy, "org.freedesktop.DBus.Properties")
    dev_type = dev_props.Get("org.freedesktop.NetworkManager.Device", "DeviceType")
    if dev_type == 2:  # wireless
        wifi_device = dev_path
        interface_name = dev_props.Get("org.freedesktop.NetworkManager.Device", "Interface")
        print("wireless path:", wifi_device, "| type:", type(wifi_device))
        print("interface_name:", interface_name, "| type:", type(interface_name))
        break

if wifi_device is None:
    print("没有找到无线设备")
    sys.exit(1)

# 2️⃣ 构造连接字典
connection = {
    'connection': dbus.Dictionary({
        'id': dbus.String(SSID),
        'type': dbus.String('802-11-wireless'),
        'uuid': dbus.String(str(uuid.uuid4())),
        'interface-name': dbus.String(interface_name)
    }, signature='sv'),
    '802-11-wireless': dbus.Dictionary({
        'ssid': dbus.ByteArray(SSID.encode())
    }, signature='sv'),
    '802-11-wireless-security': dbus.Dictionary({
        'key-mgmt': dbus.String('wpa-psk'),
        'psk': dbus.String(PASSWORD)
    }, signature='sv')
}

# 3️⃣ 调用 AddAndActivateConnection
conn_path, active_path = nm_iface.AddAndActivateConnection(
    connection,
    dbus.ObjectPath(wifi_device),
    dbus.ObjectPath("/")  # 不指定 AP, 自动选择
)

print("连接成功!")
print("Connection path:", conn_path)
print("Active path:", active_path)

✅ 此时 WiFi 应该已连接。


🎯 4. 断开当前 WiFi 连接

获取当前激活的连接:

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager \
  org.freedesktop.NetworkManager.GetActiveConnections

找到返回中类型为 802-11-wireless 的连接路径,如:/org/freedesktop/NetworkManager/ActiveConnection/5

然后停用它:

busctl call org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager \
  org.freedesktop.NetworkManager DeactivateConnection \
  o /org/freedesktop/NetworkManager/ActiveConnection/5

🎯 5. 创建并打开 WiFi 热点(AP 模式)

Step 1:创建热点连接配置

Step 2:激活热点

#!/usr/bin/env python3
import dbus

# -------------------------------
# 配置热点信息
SSID = b"MyHotspot"      # 热点名称(Byte)
PASSWORD = "12345678"    # 热点密码
# -------------------------------

# 连接到系统总线
bus = dbus.SystemBus()

# 获取 NetworkManager 对象
nm_proxy = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager')
nm_iface = dbus.Interface(nm_proxy, 'org.freedesktop.NetworkManager')

# 获取 NetworkManager 设置接口
settings_proxy = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager/Settings')
settings_iface = dbus.Interface(settings_proxy, 'org.freedesktop.NetworkManager.Settings')

# 获取所有设备,找到第一个无线设备
device_paths = nm_iface.GetDevices()
wifi_device_path = None
wifi_iface_name = None
for path in device_paths:
    dev_proxy = bus.get_object('org.freedesktop.NetworkManager', path)
    dev_props = dbus.Interface(dev_proxy, 'org.freedesktop.DBus.Properties')
    dev_type = dev_props.Get('org.freedesktop.NetworkManager.Device', 'DeviceType')
    # DeviceType 2 = Wi-Fi
    if dev_type == 2:
        wifi_device_path = path
        wifi_iface_name = dev_props.Get('org.freedesktop.NetworkManager.Device', 'Interface')
        break

if not wifi_device_path:
    raise RuntimeError("未找到无线设备,请检查你的网络接口。")

print(f"使用无线接口: {wifi_iface_name}")

# 构造热点连接配置
connection = {
    'connection': {
        'id': 'MyHotspot',
        'type': '802-11-wireless',
        'interface-name': wifi_iface_name,
        'autoconnect': False,
    },
    '802-11-wireless': {
        'ssid': dbus.ByteArray(SSID),
        'mode': 'ap',
    },
    '802-11-wireless-security': {
        'key-mgmt': 'wpa-psk',
        'psk': PASSWORD,
    },
}

# 调用 AddConnection 添加热点
connection_path = settings_iface.AddConnection(connection)
print("连接已添加,路径:", connection_path)

# 激活热点(使用 ActivateConnection)
active_path = nm_iface.ActivateConnection(connection_path, wifi_device_path, '/')
print("热点已激活,Active path:", active_path)
print(f"SSID: {SSID.decode()}, Password: {PASSWORD}")



✅ 热点已启动!


🎯 6. 关闭热点

和“断开 WiFi”一样:

如之前使用了打开热点的的时候输出的内容:

使用无线接口: wlp7s0 连接已添加,路径: /org/freedesktop/NetworkManager/Settings/15 热点已激活,Active path: /org/freedesktop/NetworkManager/ActiveConnection/12 SSID: MyHotspot, Password: 12345678

或着找到类型为 802-11-wireless 且模式是 ap 的连接路径,如:/org/freedesktop/NetworkManager/ActiveConnection/6 关键要想办法得到这个ActiveConnection

然后:

busctl call org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager \
  org.freedesktop.NetworkManager DeactivateConnection \
  o /org/freedesktop/NetworkManager/ActiveConnection/12


📌 附录:如何获取设备路径(不用 nmcli)

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager \
  org.freedesktop.NetworkManager.GetDevices

遍历返回的设备路径,对每个设备查询设备类型:

dbus-send --system --print-reply \
  --dest=org.freedesktop.NetworkManager \
  /org/freedesktop/NetworkManager/Devices/3 \
  org.freedesktop.DBus.Properties.Get \
  string:"org.freedesktop.NetworkManager.Device" \
  string:"DeviceType"

返回值 2 表示无线设备(NM_DEVICE_TYPE_WIFI)。


✅ 总结命令表(纯 dbus-send)

功能 命令摘要
开启 WiFi Set WirelessEnabled true
关闭 WiFi Set WirelessEnabled false
连接 WiFi AddConnection + ActivateConnection(需 SSID 字节数组)
断开 WiFi DeactivateConnection(需 ActiveConnection 路径)
打开热点 AddConnection(mode=ap) + ActivateConnection
关闭热点 DeactivateConnection(找 AP 类型的 ActiveConnection)

💡 温馨提示:

  • 使用 dbus-send busctl操作 NetworkManager 极其繁琐,参数结构复杂,错误难调试。
  • 生产环境或脚本中强烈建议使用 nmcli
  • 如果想要更详细的控制就调用dbus的功能通信,nmcli 也是这么做的
  • 如果你是为了学习 D-Bus 或嵌入式定制系统,这些命令非常有价值。
    (可以用命令先跑通,然后再转换具体的代码)

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐