|
| 1 | +#!/usr/bin/env python |
| 2 | +# SPDX-License-Identifier: LGPL-2.1-or-later |
| 3 | +# |
| 4 | +# Example to create a new WiFi-PSK network connection profile: |
| 5 | +# |
| 6 | +# $ add-wifi-psk-connection.py --help |
| 7 | +# usage: add-wifi-psk-connection.py [-h] [-c CONN_ID] [-s SSID] [-p PSK] |
| 8 | +# [-i INTERFACE_NAME] [-a] [--save] |
| 9 | +# |
| 10 | +# Optional arguments have example values: |
| 11 | +# |
| 12 | +# optional arguments: |
| 13 | +# -h, --help show this help message and exit |
| 14 | +# -c CONN_ID Connection Id |
| 15 | +# -s SSID WiFi SSID |
| 16 | +# -p PSK WiFi PSK |
| 17 | +# -i INTERFACE_NAME WiFi device |
| 18 | +# -a autoconnect |
| 19 | +# --save Save |
| 20 | +# |
| 21 | +# $ add-wifi-psk-connection.py |
| 22 | +# New unsaved connection profile created, show it with: |
| 23 | +# nmcli connection show "MyConnectionExample"|grep -v -e -- -e default |
| 24 | +# Settings used: |
| 25 | +# {'connection': {'id': ('s', 'MyConnectionExample'), |
| 26 | +# 'uuid': ('s', '90e3bcc8-d3a5-4725-a363-abb788fd47bf'), |
| 27 | +# 'type': ('s', '802-11-wireless'), |
| 28 | +# 'autoconnect': ('b', False)}, |
| 29 | +# '802-11-wireless': {'mode': ('s', 'infrastructure'), |
| 30 | +# 'security': ('s', '802-11-wireless-security'), |
| 31 | +# 'ssid': ('ay', b'CafeSSID')}, |
| 32 | +# '802-11-wireless-security': {'key-mgmt': ('s', 'wpa-psk'), |
| 33 | +# 'auth-alg': ('s', 'open'), |
| 34 | +# 'psk': ('s', 'Coffee!!')}, |
| 35 | +# 'ipv4': {'method': ('s', 'auto')}, |
| 36 | +# 'ipv6': {'method': ('s', 'auto')}} |
| 37 | +# |
| 38 | +# Connection Profile settings are described at: |
| 39 | +# https://networkmanager.dev/docs/api/latest/ref-settings.html |
| 40 | +# |
| 41 | +# Note: By default, it uses add_connection_unsaved() to add a temporary |
| 42 | +# memory-only connection which is not saved to the system-connections folder: |
| 43 | +# For reference, see: https://networkmanager.dev/docs/api/latest/spec.html |
| 44 | +# -> org.freedesktop.NetworkManager.Settings (Settings Profile Manager) |
| 45 | + |
| 46 | +import asyncio |
| 47 | +import functools |
| 48 | +import pprint |
| 49 | +import sdbus |
| 50 | +import uuid |
| 51 | +from argparse import ArgumentParser, Namespace |
| 52 | +from sdbus_async.networkmanager import NetworkManagerSettings |
| 53 | +from sdbus_async.networkmanager import NetworkManagerConnectionProperties |
| 54 | + |
| 55 | + |
| 56 | +async def add_wifi_psk_connection_profile_async(args: Namespace) -> None: |
| 57 | + """Add a temporary (not yet saved) network connection profile""" |
| 58 | + |
| 59 | + # If we add many connections passing the same id, things get messy. Check: |
| 60 | + if await NetworkManagerSettings().get_connections_by_id(args.conn_id): |
| 61 | + print(f'Connection "{args.conn_id}" exists, remove it first') |
| 62 | + print(f'Run: nmcli connection delete "{args.conn_id}"') |
| 63 | + return |
| 64 | + |
| 65 | + properties: NetworkManagerConnectionProperties = { |
| 66 | + "connection": { |
| 67 | + "id": ("s", args.conn_id), |
| 68 | + "uuid": ("s", str(uuid.uuid4())), |
| 69 | + "type": ("s", "802-11-wireless"), |
| 70 | + "autoconnect": ("b", args.auto), |
| 71 | + }, |
| 72 | + "802-11-wireless": { |
| 73 | + "mode": ("s", "infrastructure"), |
| 74 | + "security": ("s", "802-11-wireless-security"), |
| 75 | + "ssid": ("ay", args.ssid.encode("utf-8")), |
| 76 | + }, |
| 77 | + "802-11-wireless-security": { |
| 78 | + "key-mgmt": ("s", "wpa-psk"), |
| 79 | + "auth-alg": ("s", "open"), |
| 80 | + "psk": ("s", args.psk), |
| 81 | + }, |
| 82 | + "ipv4": {"method": ("s", "auto")}, |
| 83 | + "ipv6": {"method": ("s", "auto")}, |
| 84 | + } |
| 85 | + |
| 86 | + # To bind the new connection to a specific interface, use this: |
| 87 | + if args.interface_name: |
| 88 | + properties["connection"]["interface-name"] = ("s", args.interface_name) |
| 89 | + |
| 90 | + networkmanager_settings = NetworkManagerSettings() |
| 91 | + if args.save: |
| 92 | + await networkmanager_settings.add_connection(properties) |
| 93 | + print("New connection profile created and saved, show it with:") |
| 94 | + else: |
| 95 | + await networkmanager_settings.add_connection_unsaved(properties) |
| 96 | + print("New unsaved connection profile created, show it with:") |
| 97 | + |
| 98 | + print(f'nmcli connection show "{args.conn_id}"|grep -v -e -- -e default') |
| 99 | + print("Settings used:") |
| 100 | + functools.partial(pprint.pprint, sort_dicts=False)(properties) |
| 101 | + |
| 102 | + |
| 103 | +if __name__ == "__main__": |
| 104 | + p = ArgumentParser(description="Optional arguments have example values:") |
| 105 | + conn_id = "MyConnectionExample" |
| 106 | + p.add_argument("-c", dest="conn_id", default=conn_id, help="Connection Id") |
| 107 | + p.add_argument("-s", dest="ssid", default="CafeSSID", help="WiFi SSID") |
| 108 | + p.add_argument("-p", dest="psk", default="Coffee!!", help="WiFi PSK") |
| 109 | + p.add_argument("-i", dest="interface_name", default="", help="WiFi device") |
| 110 | + p.add_argument("-a", dest="auto", action="store_true", help="autoconnect") |
| 111 | + p.add_argument("--save", dest="save", action="store_true", help="Save") |
| 112 | + args = p.parse_args() |
| 113 | + sdbus.set_default_bus(sdbus.sd_bus_open_system()) |
| 114 | + asyncio.run(add_wifi_psk_connection_profile_async(args)) |
0 commit comments