From b6bfa78eb51dd9ae86b2978fa08edc9f728fcc86 Mon Sep 17 00:00:00 2001 From: thekiwismarthome <134335563+thekiwismarthome@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:31:02 +1300 Subject: [PATCH] Add files via upload --- .../shopping_list_manager/__init__.py | 187 ++++++++++++++---- 1 file changed, 152 insertions(+), 35 deletions(-) diff --git a/custom_components/shopping_list_manager/__init__.py b/custom_components/shopping_list_manager/__init__.py index 56cbb4d..fcd152a 100644 --- a/custom_components/shopping_list_manager/__init__.py +++ b/custom_components/shopping_list_manager/__init__.py @@ -1,56 +1,173 @@ -""" -Shopping List Manager - Home Assistant Custom Integration -Clean-slate architecture with enforced invariants -""" +"""Shopping List Manager integration for Home Assistant.""" import logging +import os + from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.components import websocket_api as ha_websocket -from .websocket_api import websocket_create_list - +from homeassistant.helpers.typing import ConfigType from .const import DOMAIN -from .manager import ShoppingListManager -# Import websocket handler functions directly -from .websocket_api import ( - websocket_add_product, - websocket_set_qty, - websocket_get_products, - websocket_get_active, - websocket_delete_product, - ws_get_catalogues, - ws_get_lists, -) +from .storage import ShoppingListStorage _LOGGER = logging.getLogger(__name__) +# Track storage instance globally +DATA_STORAGE = f"{DOMAIN}_storage" + + +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: + """Set up the Shopping List Manager component from yaml (not used).""" + # This integration doesn't support YAML configuration + # All setup is done via config entries (UI configuration) + return True + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Shopping List Manager from a config entry.""" - # Initialize the manager - manager = ShoppingListManager(hass) - await manager.async_load() + _LOGGER.info("Setting up Shopping List Manager") - # Store manager in hass.data + # Get component path for loading data files + component_path = os.path.dirname(__file__) + + # Initialize storage + storage = ShoppingListStorage(hass, component_path) + await storage.async_load() + + # Store storage instance in hass.data hass.data.setdefault(DOMAIN, {}) - hass.data[DOMAIN]["manager"] = manager + hass.data[DOMAIN][DATA_STORAGE] = storage - # Register WebSocket commands using Home Assistant's websocket_api - ha_websocket.async_register_command(hass, websocket_create_list) - ha_websocket.async_register_command(hass, websocket_add_product) - ha_websocket.async_register_command(hass, websocket_set_qty) - ha_websocket.async_register_command(hass, websocket_get_products) - ha_websocket.async_register_command(hass, websocket_get_active) - ha_websocket.async_register_command(hass, websocket_delete_product) - ha_websocket.async_register_command(hass, ws_get_catalogues) - ha_websocket.async_register_command(hass, ws_get_lists) + # Register WebSocket commands + await _async_register_websocket_handlers(hass, storage) - _LOGGER.info("Shopping List Manager setup complete - registered 7 WebSocket commands") + # Register frontend resources + await _async_register_frontend(hass) + _LOGGER.info("Shopping List Manager setup complete") return True async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: - """Unload Shopping List Manager.""" - hass.data[DOMAIN].pop("manager", None) + """Unload a config entry.""" + _LOGGER.info("Unloading Shopping List Manager") + + # Clean up hass.data + if DOMAIN in hass.data: + hass.data[DOMAIN].pop(DATA_STORAGE, None) + return True + + +async def _async_register_websocket_handlers( + hass: HomeAssistant, + storage: ShoppingListStorage +) -> None: + """Register WebSocket API handlers.""" + from homeassistant.components import websocket_api + from .websocket import handlers + + # Lists handlers + websocket_api.async_register_command( + hass, + handlers.websocket_get_lists, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_create_list, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_update_list, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_delete_list, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_set_active_list, + ) + + # Items handlers + websocket_api.async_register_command( + hass, + handlers.websocket_get_items, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_add_item, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_update_item, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_check_item, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_delete_item, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_reorder_items, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_bulk_check_items, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_clear_checked_items, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_get_list_total, + ) + + # Products handlers + websocket_api.async_register_command( + hass, + handlers.websocket_search_products, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_get_product_suggestions, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_add_product, + ) + websocket_api.async_register_command( + hass, + handlers.websocket_update_product, + ) + + # Categories handlers + websocket_api.async_register_command( + hass, + handlers.websocket_get_categories, + ) + + _LOGGER.debug("WebSocket handlers registered") + + +async def _async_register_frontend(hass: HomeAssistant) -> None: + """Register frontend resources.""" + # Register the custom card + hass.http.register_static_path( + f"/hacsfiles/{DOMAIN}", + hass.config.path(f"custom_components/{DOMAIN}/www"), + True, + ) + + _LOGGER.debug("Frontend resources registered") + + +def get_storage(hass: HomeAssistant) -> ShoppingListStorage: + """Get the storage instance from hass.data. + + Helper function for WebSocket handlers to access storage. + """ + return hass.data[DOMAIN][DATA_STORAGE] \ No newline at end of file