Add currency core configuration (#53541)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Franck Nijhof 2021-07-28 08:55:58 +02:00 committed by GitHub
parent 514d97f144
commit 1968b95829
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 210 additions and 2 deletions

View file

@ -43,6 +43,7 @@ from homeassistant.helpers.system_info import async_get_system_info
_LOGGER = logging.getLogger(__name__)
ATTR_BASE_URL = "base_url"
ATTR_CURRENCY = "currency"
ATTR_EXTERNAL_URL = "external_url"
ATTR_INTERNAL_URL = "internal_url"
ATTR_LOCATION_NAME = "location_name"
@ -195,6 +196,7 @@ class APIDiscoveryView(HomeAssistantView):
# always needs authentication
ATTR_REQUIRES_API_PASSWORD: True,
ATTR_VERSION: __version__,
ATTR_CURRENCY: None,
}
with suppress(NoURLAvailableError):

View file

@ -46,6 +46,7 @@ class CheckConfigView(HomeAssistantView):
vol.Optional("time_zone"): cv.time_zone,
vol.Optional("external_url"): vol.Any(cv.url, None),
vol.Optional("internal_url"): vol.Any(cv.url, None),
vol.Optional("currency"): cv.currency,
}
)
async def websocket_update_config(hass, connection, msg):

View file

@ -28,6 +28,7 @@ from homeassistant.const import (
CONF_ALLOWLIST_EXTERNAL_URLS,
CONF_AUTH_MFA_MODULES,
CONF_AUTH_PROVIDERS,
CONF_CURRENCY,
CONF_CUSTOMIZE,
CONF_CUSTOMIZE_DOMAIN,
CONF_CUSTOMIZE_GLOB,
@ -238,6 +239,7 @@ CORE_CONFIG_SCHEMA = CUSTOMIZE_CONFIG_SCHEMA.extend(
# pylint: disable=no-value-for-parameter
vol.Optional(CONF_MEDIA_DIRS): cv.schema_with_slug_keys(vol.IsDir()),
vol.Optional(CONF_LEGACY_TEMPLATES): cv.boolean,
vol.Optional(CONF_CURRENCY): cv.currency,
}
)
@ -520,6 +522,7 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: dict) -> Non
CONF_UNIT_SYSTEM,
CONF_EXTERNAL_URL,
CONF_INTERNAL_URL,
CONF_CURRENCY,
)
):
hac.config_source = SOURCE_YAML
@ -533,6 +536,7 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: dict) -> Non
(CONF_EXTERNAL_URL, "external_url"),
(CONF_MEDIA_DIRS, "media_dirs"),
(CONF_LEGACY_TEMPLATES, "legacy_templates"),
(CONF_CURRENCY, "currency"),
):
if key in config:
setattr(hac, attr, config[key])

View file

@ -1545,6 +1545,7 @@ class Config:
self.units: UnitSystem = METRIC_SYSTEM
self.internal_url: str | None = None
self.external_url: str | None = None
self.currency: str = "EUR"
self.config_source: str = "default"
@ -1650,6 +1651,7 @@ class Config:
"state": self.hass.state.value,
"external_url": self.external_url,
"internal_url": self.internal_url,
"currency": self.currency,
}
def set_time_zone(self, time_zone_str: str) -> None:
@ -1676,6 +1678,7 @@ class Config:
# pylint: disable=dangerous-default-value # _UNDEFs not modified
external_url: str | dict | None = _UNDEF,
internal_url: str | dict | None = _UNDEF,
currency: str | None = None,
) -> None:
"""Update the configuration from a dictionary."""
self.config_source = source
@ -1698,6 +1701,8 @@ class Config:
self.external_url = cast(Optional[str], external_url)
if internal_url is not _UNDEF:
self.internal_url = cast(Optional[str], internal_url)
if currency is not None:
self.currency = currency
async def async_update(self, **kwargs: Any) -> None:
"""Update the configuration from a dictionary."""
@ -1723,6 +1728,7 @@ class Config:
time_zone=data.get("time_zone"),
external_url=data.get("external_url", _UNDEF),
internal_url=data.get("internal_url", _UNDEF),
currency=data.get("currency"),
)
async def async_store(self) -> None:
@ -1736,6 +1742,7 @@ class Config:
"time_zone": self.time_zone,
"external_url": self.external_url,
"internal_url": self.internal_url,
"currency": self.currency,
}
store = self.hass.helpers.storage.Store(

View file

@ -1269,3 +1269,167 @@ ACTION_TYPE_SCHEMAS: dict[str, Callable[[Any], dict]] = {
SCRIPT_ACTION_WAIT_FOR_TRIGGER: _SCRIPT_WAIT_FOR_TRIGGER_SCHEMA,
SCRIPT_ACTION_VARIABLES: _SCRIPT_SET_SCHEMA,
}
# Validate currencies adopted by countries
currency = vol.In(
{
"AED",
"AFN",
"ALL",
"AMD",
"ANG",
"AOA",
"ARS",
"AUD",
"AWG",
"AZN",
"BAM",
"BBD",
"BDT",
"BGN",
"BHD",
"BIF",
"BMD",
"BND",
"BOB",
"BRL",
"BSD",
"BTN",
"BWP",
"BYR",
"BZD",
"CAD",
"CDF",
"CHF",
"CLP",
"CNY",
"COP",
"CRC",
"CUP",
"CVE",
"CZK",
"DJF",
"DKK",
"DOP",
"DZD",
"EGP",
"ERN",
"ETB",
"EUR",
"FJD",
"FKP",
"GBP",
"GEL",
"GHS",
"GIP",
"GMD",
"GNF",
"GTQ",
"GYD",
"HKD",
"HNL",
"HRK",
"HTG",
"HUF",
"IDR",
"ILS",
"INR",
"IQD",
"IRR",
"ISK",
"JMD",
"JOD",
"JPY",
"KES",
"KGS",
"KHR",
"KMF",
"KPW",
"KRW",
"KWD",
"KYD",
"KZT",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
"LTL",
"LYD",
"MAD",
"MDL",
"MGA",
"MKD",
"MMK",
"MNT",
"MOP",
"MRO",
"MUR",
"MVR",
"MWK",
"MXN",
"MYR",
"MZN",
"NAD",
"NGN",
"NIO",
"NOK",
"NPR",
"NZD",
"OMR",
"PAB",
"PEN",
"PGK",
"PHP",
"PKR",
"PLN",
"PYG",
"QAR",
"RON",
"RSD",
"RUB",
"RWF",
"SAR",
"SBD",
"SCR",
"SDG",
"SEK",
"SGD",
"SHP",
"SLL",
"SOS",
"SRD",
"SSP",
"STD",
"SYP",
"SZL",
"THB",
"TJS",
"TMT",
"TND",
"TOP",
"TRY",
"TTD",
"TWD",
"TZS",
"UAH",
"UGX",
"USD",
"UYU",
"UZS",
"VEF",
"VND",
"VUV",
"WST",
"XAF",
"XCD",
"XOF",
"XPF",
"YER",
"ZAR",
"ZMK",
"ZWL",
},
msg="invalid ISO 4217 formatted currency",
)

View file

@ -1,4 +1,4 @@
"""Test hassbian config."""
"""Test core config."""
from unittest.mock import patch
import pytest
@ -60,6 +60,7 @@ async def test_websocket_core_update(hass, client):
assert hass.config.time_zone != "America/New_York"
assert hass.config.external_url != "https://www.example.com"
assert hass.config.internal_url != "http://example.com"
assert hass.config.currency == "EUR"
with patch("homeassistant.util.dt.set_default_time_zone") as mock_set_tz:
await client.send_json(
@ -74,6 +75,7 @@ async def test_websocket_core_update(hass, client):
"time_zone": "America/New_York",
"external_url": "https://www.example.com",
"internal_url": "http://example.local",
"currency": "USD",
}
)
@ -89,6 +91,7 @@ async def test_websocket_core_update(hass, client):
assert hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL
assert hass.config.external_url == "https://www.example.com"
assert hass.config.internal_url == "http://example.local"
assert hass.config.currency == "USD"
assert len(mock_set_tz.mock_calls) == 1
assert mock_set_tz.mock_calls[0][1][0] == dt_util.get_time_zone("America/New_York")

View file

@ -1085,3 +1085,18 @@ def test_whitespace():
for value in (" ", " "):
assert schema(value)
def test_currency():
"""Test currency validator."""
schema = vol.Schema(cv.currency)
for value in (
None,
"BTC",
):
with pytest.raises(vol.MultipleInvalid):
schema(value)
for value in ("EUR", "USD"):
assert schema(value)

View file

@ -193,6 +193,7 @@ def test_core_config_schema():
{"longitude": -181},
{"external_url": "not an url"},
{"internal_url": "not an url"},
{"currency", 100},
{"customize": "bla"},
{"customize": {"light.sensor": 100}},
{"customize": {"entity_id": []}},
@ -208,6 +209,7 @@ def test_core_config_schema():
"external_url": "https://www.example.com",
"internal_url": "http://example.local",
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
"currency": "USD",
"customize": {"sensor.temperature": {"hidden": True}},
}
)
@ -360,6 +362,7 @@ async def test_loading_configuration_from_storage(hass, hass_storage):
"unit_system": "metric",
"external_url": "https://www.example.com",
"internal_url": "http://example.local",
"currency": "EUR",
},
"key": "core.config",
"version": 1,
@ -376,6 +379,7 @@ async def test_loading_configuration_from_storage(hass, hass_storage):
assert hass.config.time_zone == "Europe/Copenhagen"
assert hass.config.external_url == "https://www.example.com"
assert hass.config.internal_url == "http://example.local"
assert hass.config.currency == "EUR"
assert len(hass.config.allowlist_external_dirs) == 3
assert "/etc" in hass.config.allowlist_external_dirs
assert hass.config.config_source == SOURCE_STORAGE
@ -423,6 +427,7 @@ async def test_updating_configuration(hass, hass_storage):
"unit_system": "metric",
"external_url": "https://www.example.com",
"internal_url": "http://example.local",
"currency": "BTC",
},
"key": "core.config",
"version": 1,
@ -431,12 +436,14 @@ async def test_updating_configuration(hass, hass_storage):
await config_util.async_process_ha_core_config(
hass, {"allowlist_external_dirs": "/etc"}
)
await hass.config.async_update(latitude=50)
await hass.config.async_update(latitude=50, currency="USD")
new_core_data = copy.deepcopy(core_data)
new_core_data["data"]["latitude"] = 50
new_core_data["data"]["currency"] = "USD"
assert hass_storage["core.config"] == new_core_data
assert hass.config.latitude == 50
assert hass.config.currency == "USD"
async def test_override_stored_configuration(hass, hass_storage):
@ -484,6 +491,7 @@ async def test_loading_configuration(hass):
"internal_url": "http://example.local",
"media_dirs": {"mymedia": "/usr"},
"legacy_templates": True,
"currency": "EUR",
},
)
@ -501,6 +509,7 @@ async def test_loading_configuration(hass):
assert hass.config.media_dirs == {"mymedia": "/usr"}
assert hass.config.config_source == config_util.SOURCE_YAML
assert hass.config.legacy_templates is True
assert hass.config.currency == "EUR"
async def test_loading_configuration_temperature_unit(hass):
@ -528,6 +537,7 @@ async def test_loading_configuration_temperature_unit(hass):
assert hass.config.external_url == "https://www.example.com"
assert hass.config.internal_url == "http://example.local"
assert hass.config.config_source == config_util.SOURCE_YAML
assert hass.config.currency == "EUR"
async def test_loading_configuration_default_media_dirs_docker(hass):

View file

@ -912,6 +912,7 @@ def test_config_defaults():
assert config.media_dirs == {}
assert config.safe_mode is False
assert config.legacy_templates is False
assert config.currency == "EUR"
def test_config_path_with_file():
@ -952,6 +953,7 @@ def test_config_as_dict():
"state": "RUNNING",
"external_url": None,
"internal_url": None,
"currency": "EUR",
}
assert expected == config.as_dict()