From 78f857f8f94fed9f04912534ad52515e6b7ec5ec Mon Sep 17 00:00:00 2001 From: thekiwismarthome Date: Sun, 9 Aug 2026 09:45:33 +1200 Subject: [PATCH 1/4] feat: add custom regions support --- .../shopping_list_manager/__init__.py | 8 ++ .../shopping_list_manager/const.py | 1 + .../shopping_list_manager/storage.py | 39 ++++++++ .../websocket/handlers.py | 97 +++++++++++++++++-- 4 files changed, 135 insertions(+), 10 deletions(-) diff --git a/custom_components/shopping_list_manager/__init__.py b/custom_components/shopping_list_manager/__init__.py index a3069c1..21dff19 100644 --- a/custom_components/shopping_list_manager/__init__.py +++ b/custom_components/shopping_list_manager/__init__.py @@ -242,6 +242,14 @@ async def _async_register_websocket_handlers( hass, handlers.websocket_set_country, ) + websocket_api.async_register_command( + hass, + handlers.websocket_create_custom_region, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_delete_custom_region, + ) # Backup / Restore handlers websocket_api.async_register_command( diff --git a/custom_components/shopping_list_manager/const.py b/custom_components/shopping_list_manager/const.py index 1d2b898..d4424f6 100644 --- a/custom_components/shopping_list_manager/const.py +++ b/custom_components/shopping_list_manager/const.py @@ -10,6 +10,7 @@ STORAGE_KEY_ITEMS = f"{DOMAIN}.items" STORAGE_KEY_PRODUCTS = f"{DOMAIN}.products" STORAGE_KEY_CATEGORIES = f"{DOMAIN}.categories" STORAGE_KEY_LOYALTY_CARDS = f"{DOMAIN}.loyalty_cards" +STORAGE_KEY_CUSTOM_REGIONS = f"{DOMAIN}.custom_regions" # WebSocket Commands - Lists WS_TYPE_LISTS_GET_ALL = f"{DOMAIN}/lists/get_all" diff --git a/custom_components/shopping_list_manager/storage.py b/custom_components/shopping_list_manager/storage.py index 1d271f1..4b20ca0 100644 --- a/custom_components/shopping_list_manager/storage.py +++ b/custom_components/shopping_list_manager/storage.py @@ -17,6 +17,7 @@ from .const import ( STORAGE_KEY_PRODUCTS, STORAGE_KEY_CATEGORIES, STORAGE_KEY_LOYALTY_CARDS, + STORAGE_KEY_CUSTOM_REGIONS, IMAGES_LOCAL_DIR, LEGACY_IMAGES_LOCAL_DIR, LOCAL_IMAGE_URL_PREFIX, @@ -48,12 +49,14 @@ class ShoppingListStorage: self._store_products = Store(hass, STORAGE_VERSION, STORAGE_KEY_PRODUCTS) self._store_categories = Store(hass, STORAGE_VERSION, STORAGE_KEY_CATEGORIES) self._store_loyalty_cards = Store(hass, STORAGE_VERSION, STORAGE_KEY_LOYALTY_CARDS) + self._store_custom_regions = Store(hass, STORAGE_VERSION, STORAGE_KEY_CUSTOM_REGIONS) self._lists: Dict[str, ShoppingList] = {} self._items: Dict[str, List[Item]] = {} self._products: Dict[str, Product] = {} self._categories: List[Category] = [] self._loyalty_cards: Dict[str, LoyaltyCard] = {} + self._custom_regions: Dict[str, str] = {} # code -> display name self._search_engine: Optional[ProductSearch] = None self._images_dir = Path(hass.config.path(IMAGES_LOCAL_DIR)) self._legacy_images_dir = Path(hass.config.path(LEGACY_IMAGES_LOCAL_DIR)) @@ -155,6 +158,12 @@ class ShoppingListStorage: } _LOGGER.debug("Loaded %d loyalty cards", len(self._loyalty_cards)) + # Load custom regions + custom_regions_data = await self._store_custom_regions.async_load() + if custom_regions_data: + self._custom_regions = custom_regions_data.get("regions", {}) + _LOGGER.debug("Loaded %d custom regions", len(self._custom_regions)) + # Initialize search engine after products are loaded if self._products: products_dict = {pid: p.to_dict() for pid, p in self._products.items()} @@ -824,3 +833,33 @@ class ShoppingListStorage: await self._save_loyalty_cards() _LOGGER.debug("Updated members for loyalty card: %s", card_id) return card + + # ========================================================================== + # Custom Regions + # ========================================================================== + + def get_custom_regions(self) -> Dict[str, str]: + """Return all custom regions as {code: display_name}.""" + return dict(self._custom_regions) + + async def create_custom_region(self, code: str, name: str) -> bool: + """Create a new custom region. Returns False if the code already exists.""" + if code in self._custom_regions: + return False + self._custom_regions[code] = name + await self._save_custom_regions() + _LOGGER.debug("Created custom region: %s (%s)", code, name) + return True + + async def delete_custom_region(self, code: str) -> bool: + """Delete a custom region. Returns False if not found.""" + if code not in self._custom_regions: + return False + del self._custom_regions[code] + await self._save_custom_regions() + _LOGGER.debug("Deleted custom region: %s", code) + return True + + async def _save_custom_regions(self) -> None: + """Persist custom regions to storage.""" + await self._store_custom_regions.async_save({"regions": self._custom_regions}) diff --git a/custom_components/shopping_list_manager/websocket/handlers.py b/custom_components/shopping_list_manager/websocket/handlers.py index 5423a51..fdf6eda 100644 --- a/custom_components/shopping_list_manager/websocket/handlers.py +++ b/custom_components/shopping_list_manager/websocket/handlers.py @@ -1207,29 +1207,33 @@ def websocket_get_integration_settings( """Return current country and available country options.""" country = hass.data[DOMAIN].get("country", "NZ") version = hass.data[DOMAIN].get("version", "unknown") + storage = get_storage(hass) + built_in = { + "NZ": "New Zealand", + "AU": "Australia", + "US": "United States", + "GB": "United Kingdom", + "CA": "Canada", + "BE": "Belgium (Dutch)", + } + custom = storage.get_custom_regions() connection.send_result( msg["id"], { "country": country, "version": version, - "available_countries": { - "NZ": "New Zealand", - "AU": "Australia", - "US": "United States", - "GB": "United Kingdom", - "CA": "Canada", - "BE": "Belgium (Dutch)", - }, + "available_countries": {**built_in, **custom}, + "custom_regions": custom, } ) -_VALID_COUNTRIES = ["NZ", "AU", "US", "GB", "CA", "BE"] +_BUILT_IN_COUNTRIES = ["NZ", "AU", "US", "GB", "CA", "BE"] @websocket_api.websocket_command( { vol.Required("type"): "shopping_list_manager/set_country", - vol.Required("country"): vol.In(_VALID_COUNTRIES), + vol.Required("country"): str, } ) @websocket_api.async_response @@ -1242,6 +1246,11 @@ async def websocket_set_country( country = msg["country"].upper() storage = get_storage(hass) + custom_regions = storage.get_custom_regions() + if country not in _BUILT_IN_COUNTRIES and country not in custom_regions: + connection.send_error(msg["id"], "invalid_country", f"Unknown region: {country}") + return + count = await storage.reload_catalog(country) # Persist to HA config entry so country survives restart @@ -1258,6 +1267,74 @@ async def websocket_set_country( ) +@websocket_api.websocket_command( + { + vol.Required("type"): "shopping_list_manager/regions/create", + vol.Required("code"): vol.All(str, vol.Length(min=2, max=8), vol.Upper), + vol.Required("name"): vol.All(str, vol.Length(min=1, max=64)), + } +) +@websocket_api.async_response +async def websocket_create_custom_region( + hass: HomeAssistant, + connection: websocket_api.ActiveConnection, + msg: Dict[str, Any], +) -> None: + """Create a custom region.""" + code = msg["code"].upper() + name = msg["name"].strip() + storage = get_storage(hass) + + if code in _BUILT_IN_COUNTRIES: + connection.send_error(msg["id"], "conflict", f"{code} is a built-in region") + return + + created = await storage.create_custom_region(code, name) + if not created: + connection.send_error(msg["id"], "conflict", f"Region {code} already exists") + return + + connection.send_result( + msg["id"], + {"success": True, "code": code, "name": name, "custom_regions": storage.get_custom_regions()} + ) + + +@websocket_api.websocket_command( + { + vol.Required("type"): "shopping_list_manager/regions/delete", + vol.Required("code"): str, + } +) +@websocket_api.async_response +async def websocket_delete_custom_region( + hass: HomeAssistant, + connection: websocket_api.ActiveConnection, + msg: Dict[str, Any], +) -> None: + """Delete a custom region.""" + code = msg["code"].upper() + storage = get_storage(hass) + + deleted = await storage.delete_custom_region(code) + if not deleted: + connection.send_error(msg["id"], "not_found", f"Custom region {code} not found") + return + + # If the active country was this region, fall back to NZ + if hass.data[DOMAIN].get("country") == code: + hass.data[DOMAIN]["country"] = "NZ" + entries = hass.config_entries.async_entries(DOMAIN) + if entries: + entry = entries[0] + hass.config_entries.async_update_entry(entry, options={**entry.options, "country": "NZ"}) + + connection.send_result( + msg["id"], + {"success": True, "code": code, "custom_regions": storage.get_custom_regions()} + ) + + # ============================================================================= # BACKUP / RESTORE HANDLERS # ============================================================================= From 5e2a7e8d3579d7a91c87fa2363cef0bcce79e7bd Mon Sep 17 00:00:00 2001 From: thekiwismarthome Date: Sun, 9 Aug 2026 10:29:26 +1200 Subject: [PATCH 2/4] feat: add currency_symbol and language fields to custom regions --- .../shopping_list_manager/storage.py | 24 +++++++++++++------ .../websocket/handlers.py | 11 ++++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/custom_components/shopping_list_manager/storage.py b/custom_components/shopping_list_manager/storage.py index 4b20ca0..d026e1f 100644 --- a/custom_components/shopping_list_manager/storage.py +++ b/custom_components/shopping_list_manager/storage.py @@ -56,7 +56,7 @@ class ShoppingListStorage: self._products: Dict[str, Product] = {} self._categories: List[Category] = [] self._loyalty_cards: Dict[str, LoyaltyCard] = {} - self._custom_regions: Dict[str, str] = {} # code -> display name + self._custom_regions: Dict[str, Any] = {} # code -> {name, currency_symbol, language} self._search_engine: Optional[ProductSearch] = None self._images_dir = Path(hass.config.path(IMAGES_LOCAL_DIR)) self._legacy_images_dir = Path(hass.config.path(LEGACY_IMAGES_LOCAL_DIR)) @@ -158,10 +158,14 @@ class ShoppingListStorage: } _LOGGER.debug("Loaded %d loyalty cards", len(self._loyalty_cards)) - # Load custom regions + # Load custom regions (migrate old string-only format) custom_regions_data = await self._store_custom_regions.async_load() if custom_regions_data: - self._custom_regions = custom_regions_data.get("regions", {}) + raw = custom_regions_data.get("regions", {}) + self._custom_regions = { + k: (v if isinstance(v, dict) else {"name": v, "currency_symbol": None, "language": None}) + for k, v in raw.items() + } _LOGGER.debug("Loaded %d custom regions", len(self._custom_regions)) # Initialize search engine after products are loaded @@ -838,15 +842,21 @@ class ShoppingListStorage: # Custom Regions # ========================================================================== - def get_custom_regions(self) -> Dict[str, str]: - """Return all custom regions as {code: display_name}.""" + def get_custom_regions(self) -> Dict[str, Any]: + """Return all custom regions as {code: {name, currency_symbol, language}}.""" return dict(self._custom_regions) - async def create_custom_region(self, code: str, name: str) -> bool: + async def create_custom_region( + self, code: str, name: str, currency_symbol: Optional[str] = None, language: Optional[str] = None + ) -> bool: """Create a new custom region. Returns False if the code already exists.""" if code in self._custom_regions: return False - self._custom_regions[code] = name + self._custom_regions[code] = { + "name": name, + "currency_symbol": currency_symbol, + "language": language, + } await self._save_custom_regions() _LOGGER.debug("Created custom region: %s (%s)", code, name) return True diff --git a/custom_components/shopping_list_manager/websocket/handlers.py b/custom_components/shopping_list_manager/websocket/handlers.py index fdf6eda..fff5aa6 100644 --- a/custom_components/shopping_list_manager/websocket/handlers.py +++ b/custom_components/shopping_list_manager/websocket/handlers.py @@ -1217,12 +1217,13 @@ def websocket_get_integration_settings( "BE": "Belgium (Dutch)", } custom = storage.get_custom_regions() + custom_names = {code: region["name"] for code, region in custom.items()} connection.send_result( msg["id"], { "country": country, "version": version, - "available_countries": {**built_in, **custom}, + "available_countries": {**built_in, **custom_names}, "custom_regions": custom, } ) @@ -1272,6 +1273,8 @@ async def websocket_set_country( vol.Required("type"): "shopping_list_manager/regions/create", vol.Required("code"): vol.All(str, vol.Length(min=2, max=8), vol.Upper), vol.Required("name"): vol.All(str, vol.Length(min=1, max=64)), + vol.Optional("currency_symbol"): vol.Any(vol.All(str, vol.Length(min=1, max=5)), None), + vol.Optional("language"): vol.Any(vol.All(str, vol.Length(min=1, max=64)), None), } ) @websocket_api.async_response @@ -1283,20 +1286,22 @@ async def websocket_create_custom_region( """Create a custom region.""" code = msg["code"].upper() name = msg["name"].strip() + currency_symbol = msg.get("currency_symbol") + language = msg.get("language") storage = get_storage(hass) if code in _BUILT_IN_COUNTRIES: connection.send_error(msg["id"], "conflict", f"{code} is a built-in region") return - created = await storage.create_custom_region(code, name) + created = await storage.create_custom_region(code, name, currency_symbol, language) if not created: connection.send_error(msg["id"], "conflict", f"Region {code} already exists") return connection.send_result( msg["id"], - {"success": True, "code": code, "name": name, "custom_regions": storage.get_custom_regions()} + {"success": True, "code": code, "custom_regions": storage.get_custom_regions()} ) From 88cadea42f00c7e2817fd179ce318b343ef0a004 Mon Sep 17 00:00:00 2001 From: thekiwismarthome Date: Sun, 9 Aug 2026 14:38:36 +1200 Subject: [PATCH 3/4] fix: persist migrated custom regions format on first load --- custom_components/shopping_list_manager/storage.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/custom_components/shopping_list_manager/storage.py b/custom_components/shopping_list_manager/storage.py index d026e1f..3dd3c04 100644 --- a/custom_components/shopping_list_manager/storage.py +++ b/custom_components/shopping_list_manager/storage.py @@ -162,11 +162,16 @@ class ShoppingListStorage: custom_regions_data = await self._store_custom_regions.async_load() if custom_regions_data: raw = custom_regions_data.get("regions", {}) + needs_migration = any(isinstance(v, str) for v in raw.values()) self._custom_regions = { k: (v if isinstance(v, dict) else {"name": v, "currency_symbol": None, "language": None}) for k, v in raw.items() } - _LOGGER.debug("Loaded %d custom regions", len(self._custom_regions)) + if needs_migration: + await self._save_custom_regions() + _LOGGER.info("Migrated %d custom regions to new dict format", len(self._custom_regions)) + else: + _LOGGER.debug("Loaded %d custom regions", len(self._custom_regions)) # Initialize search engine after products are loaded if self._products: From 3e4f014b11fa368294648b201cb52d1722985fcd Mon Sep 17 00:00:00 2001 From: thekiwismarthome Date: Sun, 9 Aug 2026 21:45:47 +1200 Subject: [PATCH 4/4] feat: add es/fr/de/pt/it config flow translations and expose metric/price settings via WebSocket --- .../shopping_list_manager/strings.json | 33 +++++++++++++++++++ .../translations/de.json | 33 +++++++++++++++++++ .../translations/es.json | 33 +++++++++++++++++++ .../translations/fr.json | 33 +++++++++++++++++++ .../translations/it.json | 33 +++++++++++++++++++ .../translations/pt.json | 33 +++++++++++++++++++ .../websocket/handlers.py | 4 +++ 7 files changed, 202 insertions(+) create mode 100644 custom_components/shopping_list_manager/strings.json create mode 100644 custom_components/shopping_list_manager/translations/de.json create mode 100644 custom_components/shopping_list_manager/translations/es.json create mode 100644 custom_components/shopping_list_manager/translations/fr.json create mode 100644 custom_components/shopping_list_manager/translations/it.json create mode 100644 custom_components/shopping_list_manager/translations/pt.json diff --git a/custom_components/shopping_list_manager/strings.json b/custom_components/shopping_list_manager/strings.json new file mode 100644 index 0000000..62771bc --- /dev/null +++ b/custom_components/shopping_list_manager/strings.json @@ -0,0 +1,33 @@ +{ + "config": { + "step": { + "user": { + "title": "Shopping List Manager", + "description": "Set up the Shopping List Manager integration. Country and other settings can be configured after setup via the Configure button." + } + }, + "abort": { + "single_instance_allowed": "Only a single instance of Shopping List Manager is allowed." + } + }, + "options": { + "step": { + "init": { + "title": "Shopping List Manager Options", + "description": "Changing country will reload the product catalog on next restart.", + "data": { + "country": "Country", + "enable_price_tracking": "Enable price tracking", + "enable_image_search": "Enable image search", + "metric_units_only": "Metric units only" + }, + "data_description": { + "country": "Used to localise product catalog and pricing.", + "enable_price_tracking": "Track and display product prices.", + "enable_image_search": "Search for product images automatically.", + "metric_units_only": "Show only metric units (g, kg, ml, L)." + } + } + } + } +} diff --git a/custom_components/shopping_list_manager/translations/de.json b/custom_components/shopping_list_manager/translations/de.json new file mode 100644 index 0000000..b8487cb --- /dev/null +++ b/custom_components/shopping_list_manager/translations/de.json @@ -0,0 +1,33 @@ +{ + "config": { + "step": { + "user": { + "title": "Shopping List Manager", + "description": "Richte die Shopping List Manager-Integration ein. Land und andere Einstellungen können nach der Einrichtung über die Schaltfläche Konfigurieren angepasst werden." + } + }, + "abort": { + "single_instance_allowed": "Es ist nur eine Instanz von Shopping List Manager erlaubt." + } + }, + "options": { + "step": { + "init": { + "title": "Shopping List Manager Optionen", + "description": "Das Ändern des Landes lädt den Produktkatalog beim nächsten Neustart neu.", + "data": { + "country": "Land", + "enable_price_tracking": "Preisverfolgung aktivieren", + "enable_image_search": "Bildsuche aktivieren", + "metric_units_only": "Nur metrische Einheiten" + }, + "data_description": { + "country": "Wird verwendet, um den Produktkatalog und die Preise zu lokalisieren.", + "enable_price_tracking": "Produktpreise verfolgen und anzeigen.", + "enable_image_search": "Automatisch nach Produktbildern suchen.", + "metric_units_only": "Nur metrische Einheiten anzeigen (g, kg, ml, L)." + } + } + } + } +} diff --git a/custom_components/shopping_list_manager/translations/es.json b/custom_components/shopping_list_manager/translations/es.json new file mode 100644 index 0000000..e5217f3 --- /dev/null +++ b/custom_components/shopping_list_manager/translations/es.json @@ -0,0 +1,33 @@ +{ + "config": { + "step": { + "user": { + "title": "Shopping List Manager", + "description": "Configura la integración de Shopping List Manager. El país y otros ajustes se pueden configurar después de la instalación mediante el botón Configurar." + } + }, + "abort": { + "single_instance_allowed": "Solo se permite una instancia de Shopping List Manager." + } + }, + "options": { + "step": { + "init": { + "title": "Opciones de Shopping List Manager", + "description": "Cambiar el país recargará el catálogo de productos en el próximo reinicio.", + "data": { + "country": "País", + "enable_price_tracking": "Activar seguimiento de precios", + "enable_image_search": "Activar búsqueda de imágenes", + "metric_units_only": "Solo unidades métricas" + }, + "data_description": { + "country": "Se utiliza para localizar el catálogo de productos y los precios.", + "enable_price_tracking": "Realizar un seguimiento y mostrar los precios de los productos.", + "enable_image_search": "Buscar imágenes de productos automáticamente.", + "metric_units_only": "Mostrar solo unidades métricas (g, kg, ml, L)." + } + } + } + } +} diff --git a/custom_components/shopping_list_manager/translations/fr.json b/custom_components/shopping_list_manager/translations/fr.json new file mode 100644 index 0000000..9704619 --- /dev/null +++ b/custom_components/shopping_list_manager/translations/fr.json @@ -0,0 +1,33 @@ +{ + "config": { + "step": { + "user": { + "title": "Shopping List Manager", + "description": "Configurez l'intégration Shopping List Manager. Le pays et les autres paramètres peuvent être configurés après l'installation via le bouton Configurer." + } + }, + "abort": { + "single_instance_allowed": "Une seule instance de Shopping List Manager est autorisée." + } + }, + "options": { + "step": { + "init": { + "title": "Options de Shopping List Manager", + "description": "Modifier le pays rechargera le catalogue de produits au prochain redémarrage.", + "data": { + "country": "Pays", + "enable_price_tracking": "Activer le suivi des prix", + "enable_image_search": "Activer la recherche d'images", + "metric_units_only": "Unités métriques uniquement" + }, + "data_description": { + "country": "Utilisé pour localiser le catalogue de produits et les prix.", + "enable_price_tracking": "Suivre et afficher les prix des produits.", + "enable_image_search": "Rechercher automatiquement des images de produits.", + "metric_units_only": "Afficher uniquement les unités métriques (g, kg, ml, L)." + } + } + } + } +} diff --git a/custom_components/shopping_list_manager/translations/it.json b/custom_components/shopping_list_manager/translations/it.json new file mode 100644 index 0000000..dc13e72 --- /dev/null +++ b/custom_components/shopping_list_manager/translations/it.json @@ -0,0 +1,33 @@ +{ + "config": { + "step": { + "user": { + "title": "Shopping List Manager", + "description": "Configura l'integrazione di Shopping List Manager. Il paese e le altre impostazioni possono essere configurati dopo l'installazione tramite il pulsante Configura." + } + }, + "abort": { + "single_instance_allowed": "È consentita solo un'istanza di Shopping List Manager." + } + }, + "options": { + "step": { + "init": { + "title": "Opzioni di Shopping List Manager", + "description": "La modifica del paese ricaricherà il catalogo dei prodotti al prossimo riavvio.", + "data": { + "country": "Paese", + "enable_price_tracking": "Attiva il monitoraggio dei prezzi", + "enable_image_search": "Attiva la ricerca di immagini", + "metric_units_only": "Solo unità metriche" + }, + "data_description": { + "country": "Utilizzato per localizzare il catalogo dei prodotti e i prezzi.", + "enable_price_tracking": "Tracciare e visualizzare i prezzi dei prodotti.", + "enable_image_search": "Cercare automaticamente le immagini dei prodotti.", + "metric_units_only": "Visualizzare solo unità metriche (g, kg, ml, L)." + } + } + } + } +} diff --git a/custom_components/shopping_list_manager/translations/pt.json b/custom_components/shopping_list_manager/translations/pt.json new file mode 100644 index 0000000..df71016 --- /dev/null +++ b/custom_components/shopping_list_manager/translations/pt.json @@ -0,0 +1,33 @@ +{ + "config": { + "step": { + "user": { + "title": "Shopping List Manager", + "description": "Configure a integração do Shopping List Manager. O país e outras configurações podem ser ajustados após a instalação através do botão Configurar." + } + }, + "abort": { + "single_instance_allowed": "Apenas uma instância do Shopping List Manager é permitida." + } + }, + "options": { + "step": { + "init": { + "title": "Opções do Shopping List Manager", + "description": "Alterar o país recarregará o catálogo de produtos no próximo reinício.", + "data": { + "country": "País", + "enable_price_tracking": "Ativar rastreamento de preços", + "enable_image_search": "Ativar pesquisa de imagens", + "metric_units_only": "Apenas unidades métricas" + }, + "data_description": { + "country": "Usado para localizar o catálogo de produtos e os preços.", + "enable_price_tracking": "Rastrear e exibir os preços dos produtos.", + "enable_image_search": "Pesquisar imagens de produtos automaticamente.", + "metric_units_only": "Exibir apenas unidades métricas (g, kg, ml, L)." + } + } + } + } +} diff --git a/custom_components/shopping_list_manager/websocket/handlers.py b/custom_components/shopping_list_manager/websocket/handlers.py index fff5aa6..f961d11 100644 --- a/custom_components/shopping_list_manager/websocket/handlers.py +++ b/custom_components/shopping_list_manager/websocket/handlers.py @@ -1218,6 +1218,8 @@ def websocket_get_integration_settings( } custom = storage.get_custom_regions() custom_names = {code: region["name"] for code, region in custom.items()} + entries = hass.config_entries.async_entries(DOMAIN) + options = entries[0].options if entries else {} connection.send_result( msg["id"], { @@ -1225,6 +1227,8 @@ def websocket_get_integration_settings( "version": version, "available_countries": {**built_in, **custom_names}, "custom_regions": custom, + "metric_units_only": options.get("metric_units_only", True), + "enable_price_tracking": options.get("enable_price_tracking", True), } )