Create hotspot

- add IP method "shared"
- new WiFi parameters "band" and "channel"

NetworkManager provides the magic
This commit is contained in:
Jack Thomasson 2025-01-26 12:03:42 -05:00
parent 3bc55c054a
commit e7273157b5
8 changed files with 58 additions and 6 deletions

View File

@ -12,6 +12,8 @@ from ..const import (
ATTR_ACCESSPOINTS, ATTR_ACCESSPOINTS,
ATTR_ADDRESS, ATTR_ADDRESS,
ATTR_AUTH, ATTR_AUTH,
ATTR_BAND,
ATTR_CHANNEL,
ATTR_CONNECTED, ATTR_CONNECTED,
ATTR_DNS, ATTR_DNS,
ATTR_DOCKER, ATTR_DOCKER,
@ -52,7 +54,7 @@ from ..host.configuration import (
VlanConfig, VlanConfig,
WifiConfig, WifiConfig,
) )
from ..host.const import AuthMethod, InterfaceType, WifiMode from ..host.const import AuthMethod, InterfaceType, WifiBand, WifiMode
from .utils import api_process, api_validate from .utils import api_process, api_validate
_SCHEMA_IPV4_CONFIG = vol.Schema( _SCHEMA_IPV4_CONFIG = vol.Schema(
@ -79,6 +81,8 @@ _SCHEMA_WIFI_CONFIG = vol.Schema(
vol.Optional(ATTR_AUTH): vol.Coerce(AuthMethod), vol.Optional(ATTR_AUTH): vol.Coerce(AuthMethod),
vol.Optional(ATTR_SSID): str, vol.Optional(ATTR_SSID): str,
vol.Optional(ATTR_PSK): str, vol.Optional(ATTR_PSK): str,
vol.Optional(ATTR_BAND): vol.Coerce(WifiBand),
vol.Optional(ATTR_CHANNEL): vol.Coerce(int),
} }
) )
@ -112,6 +116,8 @@ def wifi_struct(config: WifiConfig) -> dict[str, Any]:
ATTR_AUTH: config.auth, ATTR_AUTH: config.auth,
ATTR_SSID: config.ssid, ATTR_SSID: config.ssid,
ATTR_SIGNAL: config.signal, ATTR_SIGNAL: config.signal,
ATTR_BAND: config.band,
ATTR_CHANNEL: config.channel,
} }
@ -227,6 +233,8 @@ class APINetwork(CoreSysAttributes):
config.get(ATTR_AUTH, AuthMethod.OPEN), config.get(ATTR_AUTH, AuthMethod.OPEN),
config.get(ATTR_PSK, None), config.get(ATTR_PSK, None),
None, None,
config.get(ATTR_BAND, None),
config.get(ATTR_CHANNEL, None),
) )
elif key == ATTR_ENABLED: elif key == ATTR_ENABLED:
interface.enabled = config interface.enabled = config

View File

@ -119,6 +119,7 @@ ATTR_BACKUP_POST = "backup_post"
ATTR_BACKUP_PRE = "backup_pre" ATTR_BACKUP_PRE = "backup_pre"
ATTR_BACKUPS = "backups" ATTR_BACKUPS = "backups"
ATTR_BACKUPS_EXCLUDE_DATABASE = "backups_exclude_database" ATTR_BACKUPS_EXCLUDE_DATABASE = "backups_exclude_database"
ATTR_BAND = "band"
ATTR_BLK_READ = "blk_read" ATTR_BLK_READ = "blk_read"
ATTR_BLK_WRITE = "blk_write" ATTR_BLK_WRITE = "blk_write"
ATTR_BOARD = "board" ATTR_BOARD = "board"

View File

@ -204,6 +204,7 @@ class InterfaceMethod(StrEnum):
MANUAL = "manual" MANUAL = "manual"
DISABLED = "disabled" DISABLED = "disabled"
LINK_LOCAL = "link-local" LINK_LOCAL = "link-local"
SHARED = "shared"
class ConnectionType(StrEnum): class ConnectionType(StrEnum):

View File

@ -33,6 +33,8 @@ class WirelessProperties:
assigned_mac: str | None assigned_mac: str | None
mode: str | None mode: str | None
powersave: int | None powersave: int | None
band: str | None
channel: int | None
@dataclass(slots=True) @dataclass(slots=True)

View File

@ -48,6 +48,8 @@ CONF_ATTR_802_WIRELESS_MODE = "mode"
CONF_ATTR_802_WIRELESS_ASSIGNED_MAC = "assigned-mac-address" CONF_ATTR_802_WIRELESS_ASSIGNED_MAC = "assigned-mac-address"
CONF_ATTR_802_WIRELESS_SSID = "ssid" CONF_ATTR_802_WIRELESS_SSID = "ssid"
CONF_ATTR_802_WIRELESS_POWERSAVE = "powersave" CONF_ATTR_802_WIRELESS_POWERSAVE = "powersave"
CONF_ATTR_802_WIRELESS_BAND = "band"
CONF_ATTR_802_WIRELESS_CHANNEL = "channel"
CONF_ATTR_802_WIRELESS_SECURITY_AUTH_ALG = "auth-alg" CONF_ATTR_802_WIRELESS_SECURITY_AUTH_ALG = "auth-alg"
CONF_ATTR_802_WIRELESS_SECURITY_KEY_MGMT = "key-mgmt" CONF_ATTR_802_WIRELESS_SECURITY_KEY_MGMT = "key-mgmt"
CONF_ATTR_802_WIRELESS_SECURITY_PSK = "psk" CONF_ATTR_802_WIRELESS_SECURITY_PSK = "psk"
@ -234,6 +236,8 @@ class NetworkSetting(DBusInterface):
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_ASSIGNED_MAC), data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_ASSIGNED_MAC),
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_MODE), data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_MODE),
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_POWERSAVE), data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_POWERSAVE),
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_BAND),
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_CHANNEL),
) )
if CONF_ATTR_802_WIRELESS_SECURITY in data: if CONF_ATTR_802_WIRELESS_SECURITY in data:

View File

@ -15,6 +15,8 @@ from . import (
CONF_ATTR_802_ETHERNET_ASSIGNED_MAC, CONF_ATTR_802_ETHERNET_ASSIGNED_MAC,
CONF_ATTR_802_WIRELESS, CONF_ATTR_802_WIRELESS,
CONF_ATTR_802_WIRELESS_ASSIGNED_MAC, CONF_ATTR_802_WIRELESS_ASSIGNED_MAC,
CONF_ATTR_802_WIRELESS_BAND,
CONF_ATTR_802_WIRELESS_CHANNEL,
CONF_ATTR_802_WIRELESS_MODE, CONF_ATTR_802_WIRELESS_MODE,
CONF_ATTR_802_WIRELESS_POWERSAVE, CONF_ATTR_802_WIRELESS_POWERSAVE,
CONF_ATTR_802_WIRELESS_SECURITY, CONF_ATTR_802_WIRELESS_SECURITY,
@ -56,8 +58,12 @@ def _get_ipv4_connection_settings(ipv4setting) -> dict:
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "auto") ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "auto")
elif ipv4setting.method == InterfaceMethod.DISABLED: elif ipv4setting.method == InterfaceMethod.DISABLED:
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "disabled") ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "disabled")
elif ipv4setting.method == InterfaceMethod.STATIC: elif ipv4setting.method in {InterfaceMethod.STATIC, InterfaceMethod.SHARED}:
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "manual") ipv4[CONF_ATTR_IPV4_METHOD] = (
Variant("s", "manual")
if ipv4setting.method == InterfaceMethod.STATIC
else Variant("s", "shared")
)
address_data = [] address_data = []
for address in ipv4setting.address: for address in ipv4setting.address:
@ -199,13 +205,24 @@ def get_connection_from_interface(
elif interface.type == InterfaceType.WIRELESS: elif interface.type == InterfaceType.WIRELESS:
wireless = { wireless = {
CONF_ATTR_802_WIRELESS_ASSIGNED_MAC: Variant("s", "preserve"), CONF_ATTR_802_WIRELESS_ASSIGNED_MAC: Variant("s", "preserve"),
CONF_ATTR_802_WIRELESS_MODE: Variant("s", "infrastructure"), CONF_ATTR_802_WIRELESS_MODE: Variant(
"s",
interface.wifi.mode
if interface.wifi and interface.wifi.mode
else "infrastructure",
),
CONF_ATTR_802_WIRELESS_POWERSAVE: Variant("i", 1), CONF_ATTR_802_WIRELESS_POWERSAVE: Variant("i", 1),
} }
if interface.wifi and interface.wifi.ssid: if interface.wifi and interface.wifi.ssid:
wireless[CONF_ATTR_802_WIRELESS_SSID] = Variant( wireless[CONF_ATTR_802_WIRELESS_SSID] = Variant(
"ay", interface.wifi.ssid.encode("UTF-8") "ay", interface.wifi.ssid.encode("UTF-8")
) )
if interface.wifi and interface.wifi.band:
wireless[CONF_ATTR_802_WIRELESS_BAND] = Variant("s", interface.wifi.band)
if interface.wifi and interface.wifi.channel:
wireless[CONF_ATTR_802_WIRELESS_CHANNEL] = Variant(
"u", interface.wifi.channel
)
conn[CONF_ATTR_802_WIRELESS] = wireless conn[CONF_ATTR_802_WIRELESS] = wireless

View File

@ -12,7 +12,7 @@ from ..dbus.const import (
) )
from ..dbus.network.connection import NetworkConnection from ..dbus.network.connection import NetworkConnection
from ..dbus.network.interface import NetworkInterface from ..dbus.network.interface import NetworkInterface
from .const import AuthMethod, InterfaceMethod, InterfaceType, WifiMode from .const import AuthMethod, InterfaceMethod, InterfaceType, WifiBand, WifiMode
@dataclass(slots=True) @dataclass(slots=True)
@ -55,6 +55,8 @@ class WifiConfig:
auth: AuthMethod auth: AuthMethod
psk: str | None psk: str | None
signal: int | None signal: int | None
band: WifiBand | None
channel: int | None
@dataclass(slots=True) @dataclass(slots=True)
@ -191,6 +193,7 @@ class Interface:
NMInterfaceMethod.DISABLED: InterfaceMethod.DISABLED, NMInterfaceMethod.DISABLED: InterfaceMethod.DISABLED,
NMInterfaceMethod.MANUAL: InterfaceMethod.STATIC, NMInterfaceMethod.MANUAL: InterfaceMethod.STATIC,
NMInterfaceMethod.LINK_LOCAL: InterfaceMethod.DISABLED, NMInterfaceMethod.LINK_LOCAL: InterfaceMethod.DISABLED,
NMInterfaceMethod.SHARED: InterfaceMethod.SHARED,
} }
return mapping.get(method, InterfaceMethod.DISABLED) return mapping.get(method, InterfaceMethod.DISABLED)
@ -237,6 +240,12 @@ class Interface:
if inet.settings.wireless.mode: if inet.settings.wireless.mode:
mode = WifiMode(inet.settings.wireless.mode) mode = WifiMode(inet.settings.wireless.mode)
# Band and Channel
band = channel = None
if mode == WifiMode.AP:
band = WifiBand(inet.settings.wireless.band)
channel = inet.settings.wireless.channel
# Signal # Signal
if inet.wireless and inet.wireless.active: if inet.wireless and inet.wireless.active:
signal = inet.wireless.active.strength signal = inet.wireless.active.strength
@ -249,10 +258,12 @@ class Interface:
auth, auth,
psk, psk,
signal, signal,
band,
channel,
) )
@staticmethod @staticmethod
def _map_nm_vlan(inet: NetworkInterface) -> WifiConfig | None: def _map_nm_vlan(inet: NetworkInterface) -> VlanConfig | None:
"""Create mapping to nm vlan property.""" """Create mapping to nm vlan property."""
if inet.type != DeviceType.VLAN or not inet.settings: if inet.type != DeviceType.VLAN or not inet.settings:
return None return None

View File

@ -13,6 +13,7 @@ class InterfaceMethod(StrEnum):
DISABLED = "disabled" DISABLED = "disabled"
STATIC = "static" STATIC = "static"
AUTO = "auto" AUTO = "auto"
SHARED = "shared"
class InterfaceType(StrEnum): class InterfaceType(StrEnum):
@ -31,6 +32,13 @@ class AuthMethod(StrEnum):
WPA_PSK = "wpa-psk" WPA_PSK = "wpa-psk"
class WifiBand(StrEnum):
"""Wifi band."""
A = "a"
BG = "bg"
class WifiMode(StrEnum): class WifiMode(StrEnum):
"""Wifi mode.""" """Wifi mode."""