From cfa042ccacaa00acf594b6e9b22dc28ac033cfb4 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 17 Apr 2025 16:34:13 +0200 Subject: [PATCH] Add country to Supervisor info Similar to timezone also add country information to the Supervisor info. This is useful to set country specific configurations such as Wireless radio regulatory setting. This is also useful for add-ons which need country information but only have hassio API access. --- supervisor/api/supervisor.py | 6 ++++++ supervisor/config.py | 15 +++++++++++++++ supervisor/const.py | 1 + supervisor/validate.py | 2 ++ tests/api/test_supervisor.py | 15 +++++++++++++++ 5 files changed, 39 insertions(+) diff --git a/supervisor/api/supervisor.py b/supervisor/api/supervisor.py index c17037e1f78..294451507ae 100644 --- a/supervisor/api/supervisor.py +++ b/supervisor/api/supervisor.py @@ -17,6 +17,7 @@ ATTR_BLK_WRITE, ATTR_CHANNEL, ATTR_CONTENT_TRUST, + ATTR_COUNTRY, ATTR_CPU_PERCENT, ATTR_DEBUG, ATTR_DEBUG_BLOCK, @@ -76,6 +77,7 @@ vol.Optional(ATTR_FORCE_SECURITY): vol.Boolean(), vol.Optional(ATTR_AUTO_UPDATE): vol.Boolean(), vol.Optional(ATTR_DETECT_BLOCKING_IO): vol.Coerce(DetectBlockingIO), + vol.Optional(ATTR_COUNTRY): str, } ) @@ -109,6 +111,7 @@ async def info(self, request: web.Request) -> dict[str, Any]: ATTR_DIAGNOSTICS: self.sys_config.diagnostics, ATTR_AUTO_UPDATE: self.sys_updater.auto_update, ATTR_DETECT_BLOCKING_IO: blockbuster_enabled(), + ATTR_COUNTRY: self.sys_config.country, # Depricated ATTR_WAIT_BOOT: self.sys_config.wait_boot, ATTR_ADDONS: [ @@ -147,6 +150,9 @@ async def options(self, request: web.Request) -> None: if ATTR_CHANNEL in body: self.sys_updater.channel = body[ATTR_CHANNEL] + if ATTR_COUNTRY in body: + self.sys_config.country = body[ATTR_COUNTRY] + if ATTR_DEBUG in body: self.sys_config.debug = body[ATTR_DEBUG] diff --git a/supervisor/config.py b/supervisor/config.py index ac6ee1a4b00..ee643322413 100644 --- a/supervisor/config.py +++ b/supervisor/config.py @@ -10,6 +10,7 @@ from .const import ( ATTR_ADDONS_CUSTOM_LIST, + ATTR_COUNTRY, ATTR_DEBUG, ATTR_DEBUG_BLOCK, ATTR_DETECT_BLOCKING_IO, @@ -93,6 +94,20 @@ async def set_timezone(self, value: str) -> None: None, get_time_zone, value ) + @property + def country(self) -> str | None: + """Return supervisor country. + + The format follows what Home Assistant Core provides, which today is + ISO 3166-1 alpha-2. + """ + return self._data.get(ATTR_COUNTRY) + + @country.setter + def country(self, value: str | None) -> None: + """Set supervisor country.""" + self._data[ATTR_COUNTRY] = value + @property def version(self) -> AwesomeVersion: """Return supervisor version.""" diff --git a/supervisor/const.py b/supervisor/const.py index 5769b63c4aa..13504d80b26 100644 --- a/supervisor/const.py +++ b/supervisor/const.py @@ -140,6 +140,7 @@ ATTR_CONTAINERS = "containers" ATTR_CONTENT = "content" ATTR_CONTENT_TRUST = "content_trust" +ATTR_COUNTRY = "country" ATTR_CPE = "cpe" ATTR_CPU_PERCENT = "cpu_percent" ATTR_CRYPTO = "crypto" diff --git a/supervisor/validate.py b/supervisor/validate.py index 0bfcf16b70b..bfbfa79d4ac 100644 --- a/supervisor/validate.py +++ b/supervisor/validate.py @@ -13,6 +13,7 @@ ATTR_CHANNEL, ATTR_CLI, ATTR_CONTENT_TRUST, + ATTR_COUNTRY, ATTR_DEBUG, ATTR_DEBUG_BLOCK, ATTR_DETECT_BLOCKING_IO, @@ -164,6 +165,7 @@ def validate_repository(repository: str) -> str: vol.Optional(ATTR_DEBUG_BLOCK, default=False): vol.Boolean(), vol.Optional(ATTR_DIAGNOSTICS, default=None): vol.Maybe(vol.Boolean()), vol.Optional(ATTR_DETECT_BLOCKING_IO, default=False): vol.Boolean(), + vol.Optional(ATTR_COUNTRY): str, }, extra=vol.REMOVE_EXTRA, ) diff --git a/tests/api/test_supervisor.py b/tests/api/test_supervisor.py index b2a5634fa2d..064c2c65844 100644 --- a/tests/api/test_supervisor.py +++ b/tests/api/test_supervisor.py @@ -252,6 +252,21 @@ async def test_api_supervisor_options_timezone( assert coresys.timezone == "Europe/Zurich" +async def test_api_supervisor_options_country(api_client: TestClient, coresys: CoreSys): + """Test setting supervisor country via API.""" + assert coresys.config.country is None + + resp = await api_client.post("/supervisor/options", json={"country": "CH"}) + assert resp.status == 200 + + assert coresys.config.country == "CH" + + resp = await api_client.get("/supervisor/info") + assert resp.status == 200 + body = await resp.json() + assert body["data"]["country"] == "CH" + + @pytest.mark.parametrize( ("blockbuster", "option_value", "config_value"), [("no_blockbuster", "on", False), ("no_blockbuster", "on_at_startup", True)],