mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-28 03:26:32 +00:00
Merge 9a1f7543e7c42b90a046d398ea56263604aca301 into 606db3585cb07a7e04a309fbfd540403da1a4e86
This commit is contained in:
commit
4bbef0a4f8
@ -12,6 +12,8 @@ from ..const import (
|
||||
ATTR_ACCESSPOINTS,
|
||||
ATTR_ADDRESS,
|
||||
ATTR_AUTH,
|
||||
ATTR_BAND,
|
||||
ATTR_CHANNEL,
|
||||
ATTR_CONNECTED,
|
||||
ATTR_DNS,
|
||||
ATTR_DOCKER,
|
||||
@ -52,7 +54,7 @@ from ..host.configuration import (
|
||||
VlanConfig,
|
||||
WifiConfig,
|
||||
)
|
||||
from ..host.const import AuthMethod, InterfaceType, WifiMode
|
||||
from ..host.const import AuthMethod, InterfaceType, WifiBand, WifiMode
|
||||
from .utils import api_process, api_validate
|
||||
|
||||
_SCHEMA_IPV4_CONFIG = vol.Schema(
|
||||
@ -79,6 +81,8 @@ _SCHEMA_WIFI_CONFIG = vol.Schema(
|
||||
vol.Optional(ATTR_AUTH): vol.Coerce(AuthMethod),
|
||||
vol.Optional(ATTR_SSID): 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_SSID: config.ssid,
|
||||
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_PSK, None),
|
||||
None,
|
||||
config.get(ATTR_BAND, None),
|
||||
config.get(ATTR_CHANNEL, None),
|
||||
)
|
||||
elif key == ATTR_ENABLED:
|
||||
interface.enabled = config
|
||||
|
@ -119,6 +119,7 @@ ATTR_BACKUP_POST = "backup_post"
|
||||
ATTR_BACKUP_PRE = "backup_pre"
|
||||
ATTR_BACKUPS = "backups"
|
||||
ATTR_BACKUPS_EXCLUDE_DATABASE = "backups_exclude_database"
|
||||
ATTR_BAND = "band"
|
||||
ATTR_BLK_READ = "blk_read"
|
||||
ATTR_BLK_WRITE = "blk_write"
|
||||
ATTR_BOARD = "board"
|
||||
|
@ -204,6 +204,7 @@ class InterfaceMethod(StrEnum):
|
||||
MANUAL = "manual"
|
||||
DISABLED = "disabled"
|
||||
LINK_LOCAL = "link-local"
|
||||
SHARED = "shared"
|
||||
|
||||
|
||||
class ConnectionType(StrEnum):
|
||||
|
@ -33,6 +33,8 @@ class WirelessProperties:
|
||||
assigned_mac: str | None
|
||||
mode: str | None
|
||||
powersave: int | None
|
||||
band: str | None
|
||||
channel: int | None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
|
@ -48,6 +48,8 @@ CONF_ATTR_802_WIRELESS_MODE = "mode"
|
||||
CONF_ATTR_802_WIRELESS_ASSIGNED_MAC = "assigned-mac-address"
|
||||
CONF_ATTR_802_WIRELESS_SSID = "ssid"
|
||||
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_KEY_MGMT = "key-mgmt"
|
||||
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_MODE),
|
||||
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:
|
||||
|
@ -15,6 +15,8 @@ from . import (
|
||||
CONF_ATTR_802_ETHERNET_ASSIGNED_MAC,
|
||||
CONF_ATTR_802_WIRELESS,
|
||||
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_POWERSAVE,
|
||||
CONF_ATTR_802_WIRELESS_SECURITY,
|
||||
@ -50,6 +52,19 @@ if TYPE_CHECKING:
|
||||
from ....host.configuration import Interface
|
||||
|
||||
|
||||
def _get_address_data(ipv4setting) -> Variant:
|
||||
address_data = []
|
||||
for address in ipv4setting.address:
|
||||
address_data.append(
|
||||
{
|
||||
"address": Variant("s", str(address.ip)),
|
||||
"prefix": Variant("u", int(address.with_prefixlen.split("/")[-1])),
|
||||
}
|
||||
)
|
||||
|
||||
return Variant("aa{sv}", address_data)
|
||||
|
||||
|
||||
def _get_ipv4_connection_settings(ipv4setting) -> dict:
|
||||
ipv4 = {}
|
||||
if not ipv4setting or ipv4setting.method == InterfaceMethod.AUTO:
|
||||
@ -58,19 +73,12 @@ def _get_ipv4_connection_settings(ipv4setting) -> dict:
|
||||
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "disabled")
|
||||
elif ipv4setting.method == InterfaceMethod.STATIC:
|
||||
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "manual")
|
||||
|
||||
address_data = []
|
||||
for address in ipv4setting.address:
|
||||
address_data.append(
|
||||
{
|
||||
"address": Variant("s", str(address.ip)),
|
||||
"prefix": Variant("u", int(address.with_prefixlen.split("/")[-1])),
|
||||
}
|
||||
)
|
||||
|
||||
ipv4[CONF_ATTR_IPV4_ADDRESS_DATA] = Variant("aa{sv}", address_data)
|
||||
ipv4[CONF_ATTR_IPV4_ADDRESS_DATA] = _get_address_data(ipv4setting)
|
||||
if ipv4setting.gateway:
|
||||
ipv4[CONF_ATTR_IPV4_GATEWAY] = Variant("s", str(ipv4setting.gateway))
|
||||
elif ipv4setting.method == InterfaceMethod.SHARED:
|
||||
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "shared")
|
||||
ipv4[CONF_ATTR_IPV4_ADDRESS_DATA] = _get_address_data(ipv4setting)
|
||||
else:
|
||||
raise RuntimeError("Invalid IPv4 InterfaceMethod")
|
||||
|
||||
@ -199,13 +207,21 @@ def get_connection_from_interface(
|
||||
elif interface.type == InterfaceType.WIRELESS:
|
||||
wireless = {
|
||||
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 and interface.wifi.mode) or "infrastructure"
|
||||
),
|
||||
CONF_ATTR_802_WIRELESS_POWERSAVE: Variant("i", 1),
|
||||
}
|
||||
if interface.wifi and interface.wifi.ssid:
|
||||
wireless[CONF_ATTR_802_WIRELESS_SSID] = Variant(
|
||||
"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
|
||||
|
||||
|
@ -12,7 +12,7 @@ from ..dbus.const import (
|
||||
)
|
||||
from ..dbus.network.connection import NetworkConnection
|
||||
from ..dbus.network.interface import NetworkInterface
|
||||
from .const import AuthMethod, InterfaceMethod, InterfaceType, WifiMode
|
||||
from .const import AuthMethod, InterfaceMethod, InterfaceType, WifiBand, WifiMode
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@ -55,6 +55,8 @@ class WifiConfig:
|
||||
auth: AuthMethod
|
||||
psk: str | None
|
||||
signal: int | None
|
||||
band: WifiBand | None
|
||||
channel: int | None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@ -191,6 +193,7 @@ class Interface:
|
||||
NMInterfaceMethod.DISABLED: InterfaceMethod.DISABLED,
|
||||
NMInterfaceMethod.MANUAL: InterfaceMethod.STATIC,
|
||||
NMInterfaceMethod.LINK_LOCAL: InterfaceMethod.DISABLED,
|
||||
NMInterfaceMethod.SHARED: InterfaceMethod.SHARED,
|
||||
}
|
||||
|
||||
return mapping.get(method, InterfaceMethod.DISABLED)
|
||||
@ -237,6 +240,12 @@ class Interface:
|
||||
if 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
|
||||
if inet.wireless and inet.wireless.active:
|
||||
signal = inet.wireless.active.strength
|
||||
@ -249,10 +258,12 @@ class Interface:
|
||||
auth,
|
||||
psk,
|
||||
signal,
|
||||
band,
|
||||
channel,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _map_nm_vlan(inet: NetworkInterface) -> WifiConfig | None:
|
||||
def _map_nm_vlan(inet: NetworkInterface) -> VlanConfig | None:
|
||||
"""Create mapping to nm vlan property."""
|
||||
if inet.type != DeviceType.VLAN or not inet.settings:
|
||||
return None
|
||||
|
@ -13,6 +13,7 @@ class InterfaceMethod(StrEnum):
|
||||
DISABLED = "disabled"
|
||||
STATIC = "static"
|
||||
AUTO = "auto"
|
||||
SHARED = "shared"
|
||||
|
||||
|
||||
class InterfaceType(StrEnum):
|
||||
@ -31,6 +32,13 @@ class AuthMethod(StrEnum):
|
||||
WPA_PSK = "wpa-psk"
|
||||
|
||||
|
||||
class WifiBand(StrEnum):
|
||||
"""Wifi band."""
|
||||
|
||||
A = "a"
|
||||
BG = "bg"
|
||||
|
||||
|
||||
class WifiMode(StrEnum):
|
||||
"""Wifi mode."""
|
||||
|
||||
|
@ -276,6 +276,31 @@ async def test_api_network_interface_update_wifi_error(api_client: TestClient):
|
||||
)
|
||||
|
||||
|
||||
async def test_api_network_interface_update_wifi_bad_channel(api_client: TestClient):
|
||||
"""Test network interface WiFi API error handling for bad channel."""
|
||||
# Simulate frontend WiFi interface edit where the user selects a bad channel.
|
||||
resp = await api_client.post(
|
||||
f"/network/interface/{TEST_INTERFACE_WLAN_NAME}/update",
|
||||
json={
|
||||
"enabled": True,
|
||||
"ipv4": {
|
||||
"method": "shared",
|
||||
"address": ["10.42.0.1/24"],
|
||||
},
|
||||
"ipv6": {
|
||||
"method": "auto",
|
||||
},
|
||||
"wifi": {"mode": "ap", "ssid": "HotSpot", "band": "bg", "channel": 17},
|
||||
},
|
||||
)
|
||||
result = await resp.json()
|
||||
assert result["result"] == "error"
|
||||
assert (
|
||||
result["message"]
|
||||
== "Can't create config and activate wlan0: 802-11-wireless.channel: '17' is not a valid channel"
|
||||
)
|
||||
|
||||
|
||||
async def test_api_network_interface_update_remove(api_client: TestClient):
|
||||
"""Test network manager api."""
|
||||
resp = await api_client.post(
|
||||
|
@ -240,6 +240,15 @@ class NetworkManager(DBusServiceMock):
|
||||
"org.freedesktop.NetworkManager.Device.InvalidConnection",
|
||||
"A 'wireless' setting with a valid SSID is required if no AP path was given.",
|
||||
)
|
||||
if (
|
||||
"channel" in connection["802-11-wireless"]
|
||||
and connection["802-11-wireless"]["channel"].value > 14
|
||||
):
|
||||
raise DBusError(
|
||||
"org.freedesktop.NetworkManager.Device.InvalidConnection",
|
||||
# this is the actual error from NetworkManager
|
||||
f"802-11-wireless.channel: '{connection['802-11-wireless']['channel'].value}' is not a valid channel",
|
||||
)
|
||||
|
||||
return [
|
||||
"/org/freedesktop/NetworkManager/Settings/1",
|
||||
|
Loading…
x
Reference in New Issue
Block a user