async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Logbook setup.""" hass.data[DOMAIN] = {} @callback def log_message(service: ServiceCall) -> None: """Handle sending notification message service calls.""" message = service.data[ATTR_MESSAGE] name = service.data[ATTR_NAME] domain = service.data.get(ATTR_DOMAIN) entity_id = service.data.get(ATTR_ENTITY_ID) if entity_id is None and domain is None: # If there is no entity_id or # domain, the event will get filtered # away so we use the "logbook" domain domain = DOMAIN message.hass = hass message = message.async_render(parse_result=False) async_log_entry(hass, name, message, domain, entity_id) frontend.async_register_built_in_panel(hass, "logbook", "logbook", "hass:format-list-bulleted-type") if conf := config.get(DOMAIN, {}): filters = sqlalchemy_filter_from_include_exclude_conf(conf) entities_filter = convert_include_exclude_filter(conf)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the config component.""" frontend.async_register_built_in_panel( hass, "config", "config", "hass:cog", require_admin=True ) async def setup_panel(panel_name): """Set up a panel.""" panel = importlib.import_module(f".{panel_name}", __name__) if not panel: return success = await panel.async_setup(hass) if success: key = f"{DOMAIN}.{panel_name}" hass.bus.async_fire(EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: key}) tasks = [asyncio.create_task(setup_panel(panel_name)) for panel_name in SECTIONS] if tasks: await asyncio.wait(tasks) return True
async def async_register_panel( hass: HomeAssistant, # The url to serve the panel frontend_url_path: str, # The webcomponent name that loads your panel webcomponent_name: str, # Title/icon for sidebar sidebar_title: str | None = None, sidebar_icon: str | None = None, # JS source of your panel js_url: str | None = None, # JS module of your panel module_url: str | None = None, # If your panel should be run inside an iframe embed_iframe: bool = DEFAULT_EMBED_IFRAME, # Should user be asked for confirmation when loading external source trust_external: bool = DEFAULT_TRUST_EXTERNAL, # Configuration to be passed to the panel config: ConfigType | None = None, # If your panel should only be shown to admin users require_admin: bool = False, ) -> None: """Register a new custom panel.""" if js_url is None and module_url is None: raise ValueError("Either js_url, module_url or html_url is required.") if config is not None and not isinstance(config, dict): raise ValueError("Config needs to be a dictionary.") custom_panel_config = { "name": webcomponent_name, "embed_iframe": embed_iframe, "trust_external": trust_external, } if js_url is not None: custom_panel_config["js_url"] = js_url if module_url is not None: custom_panel_config["module_url"] = module_url if config is not None: # Make copy because we're mutating it config = dict(config) else: config = {} config["_panel_custom"] = custom_panel_config frontend.async_register_built_in_panel( hass, component_name="custom", sidebar_title=sidebar_title, sidebar_icon=sidebar_icon, frontend_url_path=frontend_url_path, config=config, require_admin=require_admin, )
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Logbook setup.""" hass.data[DOMAIN] = {} @callback def log_message(service: ServiceCall) -> None: """Handle sending notification message service calls.""" message = service.data[ATTR_MESSAGE] name = service.data[ATTR_NAME] domain = service.data.get(ATTR_DOMAIN) entity_id = service.data.get(ATTR_ENTITY_ID) if entity_id is None and domain is None: # If there is no entity_id or # domain, the event will get filtered # away so we use the "logbook" domain domain = DOMAIN message.hass = hass message = message.async_render(parse_result=False) async_log_entry(hass, name, message, domain, entity_id, service.context) frontend.async_register_built_in_panel(hass, "logbook", "logbook", "hass:format-list-bulleted-type") recorder_conf = config.get(RECORDER_DOMAIN, {}) logbook_conf = config.get(DOMAIN, {}) recorder_filter = extract_include_exclude_filter_conf(recorder_conf) logbook_filter = extract_include_exclude_filter_conf(logbook_conf) merged_filter = merge_include_exclude_filters(recorder_filter, logbook_filter) possible_merged_entities_filter = convert_include_exclude_filter( merged_filter) if not possible_merged_entities_filter.empty_filter: filters = sqlalchemy_filter_from_include_exclude_conf(merged_filter) entities_filter = possible_merged_entities_filter else: filters = None entities_filter = None hass.data[LOGBOOK_FILTERS] = filters hass.data[LOGBOOK_ENTITIES_FILTER] = entities_filter websocket_api.async_setup(hass) rest_api.async_setup(hass, config, filters, entities_filter) hass.services.async_register(DOMAIN, "log", log_message, schema=LOG_MESSAGE_SCHEMA) await async_process_integration_platforms(hass, DOMAIN, _process_logbook_platform) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the media_source component.""" hass.data[DOMAIN] = {} websocket_api.async_register_command(hass, websocket_browse_media) websocket_api.async_register_command(hass, websocket_resolve_media) frontend.async_register_built_in_panel(hass, "media-browser", "media_browser", "hass:play-box-multiple") local_source.async_setup(hass) await async_process_integration_platforms(hass, DOMAIN, _process_media_source_platform) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Track states and offer events for calendars.""" component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) hass.http.register_view(CalendarListView(component)) hass.http.register_view(CalendarEventView(component)) frontend.async_register_built_in_panel(hass, "calendar", "calendar", "hass:calendar") await component.async_setup(config) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up Energy.""" websocket_api.async_setup(hass) frontend.async_register_built_in_panel(hass, DOMAIN, DOMAIN, "mdi:lightning-bolt") hass.async_create_task( discovery.async_load_platform(hass, "sensor", DOMAIN, {}, config)) hass.data[DOMAIN] = { "cost_sensors": {}, } return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the iFrame frontend panels.""" for url_path, info in config[DOMAIN].items(): frontend.async_register_built_in_panel( hass, "iframe", info.get(CONF_TITLE), info.get(CONF_ICON), url_path, {"url": info[CONF_URL]}, require_admin=info[CONF_REQUIRE_ADMIN], ) return True
def _register_panel(hass, url_path, mode, config, update): """Register a panel.""" kwargs = { "frontend_url_path": url_path, "require_admin": config[CONF_REQUIRE_ADMIN], "config": {"mode": mode}, "update": update, } if config[CONF_SHOW_IN_SIDEBAR]: kwargs["sidebar_title"] = config[CONF_TITLE] kwargs["sidebar_icon"] = config.get(CONF_ICON, DEFAULT_ICON) frontend.async_register_built_in_panel(hass, DOMAIN, **kwargs)
async def update_dashboards() -> None: """Add this integrations Lovelace dashboard.""" hass = get_base().hass config = { CONF_MODE: MODE_YAML, CONF_TITLE: TITLE, CONF_ICON: LOVELACE_DASHBOARD_ICON, CONF_SHOW_IN_SIDEBAR: True, CONF_REQUIRE_ADMIN: False, CONF_FILENAME: os.path.abspath( os.path.join( os.path.dirname(__file__), os.pardir, LOVELACE_DIR, LOVELACE_FILENAME_SOURCE, )), } yaml_config = LovelaceYAML(hass, LOVELACE_DASHBOARD_URL_PATH, config) hass.data[LOVELACE_DOMAIN][CONF_DASHBOARDS][ LOVELACE_DASHBOARD_URL_PATH] = yaml_config kwargs = { "frontend_url_path": LOVELACE_DASHBOARD_URL_PATH, "require_admin": config[CONF_REQUIRE_ADMIN], "config": { CONF_MODE: config[CONF_MODE] }, "update": False, "sidebar_title": config[CONF_TITLE], "sidebar_icon": config[CONF_ICON], } if LOVELACE_DASHBOARD_URL_PATH in hass.data.get(DATA_PANELS, {}): async_remove_panel(hass, LOVELACE_DASHBOARD_URL_PATH) async_register_built_in_panel(hass, LOVELACE_DOMAIN, **kwargs) # Refresh lovelace using browser_mod hass.async_create_task( hass.services.async_call("browser_mod", "lovelace_reload"))
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the history hooks.""" conf = config.get(DOMAIN, {}) filters = sqlalchemy_filter_from_include_exclude_conf(conf) use_include_order = conf.get(CONF_ORDER) hass.http.register_view(HistoryPeriodView(filters, use_include_order)) frontend.async_register_built_in_panel(hass, "history", "history", "hass:chart-box") websocket_api.async_register_command(hass, ws_get_statistics_during_period) websocket_api.async_register_command(hass, ws_get_list_statistic_ids) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the config component.""" frontend.async_register_built_in_panel( hass, "config", "config", "hass:cog", require_admin=True ) async def setup_panel(panel_name): """Set up a panel.""" panel = importlib.import_module(f".{panel_name}", __name__) if not panel: return success = await panel.async_setup(hass) if success: key = f"{DOMAIN}.{panel_name}" hass.bus.async_fire(EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: key}) @callback def component_loaded(event): """Respond to components being loaded.""" panel_name = event.data.get(ATTR_COMPONENT) if panel_name in ON_DEMAND: hass.async_create_task(setup_panel(panel_name)) hass.bus.async_listen(EVENT_COMPONENT_LOADED, component_loaded) tasks = [asyncio.create_task(setup_panel(panel_name)) for panel_name in SECTIONS] for panel_name in ON_DEMAND: if panel_name in hass.config.components: tasks.append(asyncio.create_task(setup_panel(panel_name))) if tasks: await asyncio.wait(tasks) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the Lovelace commands.""" mode = config[DOMAIN][CONF_MODE] yaml_resources = config[DOMAIN].get(CONF_RESOURCES) frontend.async_register_built_in_panel(hass, DOMAIN, config={"mode": mode}) async def reload_resources_service_handler(service_call: ServiceCall) -> None: """Reload yaml resources.""" try: conf = await async_hass_config_yaml(hass) except HomeAssistantError as err: _LOGGER.error(err) return integration = await async_get_integration(hass, DOMAIN) config = await async_process_component_config(hass, conf, integration) resource_collection = await create_yaml_resource_col( hass, config[DOMAIN].get(CONF_RESOURCES) ) hass.data[DOMAIN]["resources"] = resource_collection if mode == MODE_YAML: default_config = dashboard.LovelaceYAML(hass, None, None) resource_collection = await create_yaml_resource_col(hass, yaml_resources) async_register_admin_service( hass, DOMAIN, SERVICE_RELOAD_RESOURCES, reload_resources_service_handler, schema=RESOURCE_RELOAD_SERVICE_SCHEMA, ) else: default_config = dashboard.LovelaceStorage(hass, None) if yaml_resources is not None: _LOGGER.warning( "Lovelace is running in storage mode. Define resources via user interface" ) resource_collection = resources.ResourceStorageCollection(hass, default_config) collection.StorageCollectionWebsocket( resource_collection, "lovelace/resources", "resource", RESOURCE_CREATE_FIELDS, RESOURCE_UPDATE_FIELDS, ).async_setup(hass, create_list=False) websocket_api.async_register_command(hass, websocket.websocket_lovelace_config) websocket_api.async_register_command(hass, websocket.websocket_lovelace_save_config) websocket_api.async_register_command( hass, websocket.websocket_lovelace_delete_config ) websocket_api.async_register_command(hass, websocket.websocket_lovelace_resources) websocket_api.async_register_command(hass, websocket.websocket_lovelace_dashboards) hass.data[DOMAIN] = { # We store a dictionary mapping url_path: config. None is the default. "mode": mode, "dashboards": {None: default_config}, "resources": resource_collection, "yaml_dashboards": config[DOMAIN].get(CONF_DASHBOARDS, {}), } if hass.config.safe_mode: return True async def storage_dashboard_changed(change_type, item_id, item): """Handle a storage dashboard change.""" url_path = item[CONF_URL_PATH] if change_type == collection.CHANGE_REMOVED: frontend.async_remove_panel(hass, url_path) await hass.data[DOMAIN]["dashboards"].pop(url_path).async_delete() return if change_type == collection.CHANGE_ADDED: existing = hass.data[DOMAIN]["dashboards"].get(url_path) if existing: _LOGGER.warning( "Cannot register panel at %s, it is already defined in %s", url_path, existing, ) return hass.data[DOMAIN]["dashboards"][url_path] = dashboard.LovelaceStorage( hass, item ) update = False else: hass.data[DOMAIN]["dashboards"][url_path].config = item update = True try: _register_panel(hass, url_path, MODE_STORAGE, item, update) except ValueError: _LOGGER.warning("Failed to %s panel %s from storage", change_type, url_path) # Process YAML dashboards for url_path, dashboard_conf in hass.data[DOMAIN]["yaml_dashboards"].items(): # For now always mode=yaml config = dashboard.LovelaceYAML(hass, url_path, dashboard_conf) hass.data[DOMAIN]["dashboards"][url_path] = config try: _register_panel(hass, url_path, MODE_YAML, dashboard_conf, False) except ValueError: _LOGGER.warning("Panel url path %s is not unique", url_path) # Process storage dashboards dashboards_collection = dashboard.DashboardsCollection(hass) dashboards_collection.async_add_listener(storage_dashboard_changed) await dashboards_collection.async_load() collection.StorageCollectionWebsocket( dashboards_collection, "lovelace/dashboards", "dashboard", STORAGE_DASHBOARD_CREATE_FIELDS, STORAGE_DASHBOARD_UPDATE_FIELDS, ).async_setup(hass, create_list=False) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Register hidden _my_redirect panel.""" frontend.async_register_built_in_panel(hass, DOMAIN, frontend_url_path=URL_PATH) return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Register the built-in map panel.""" frontend.async_register_built_in_panel(hass, "map", "map", "hass:tooltip-account") return True
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Track states and offer events for mailboxes.""" mailboxes: list[Mailbox] = [] frontend.async_register_built_in_panel(hass, "mailbox", "mailbox", "mdi:mailbox") hass.http.register_view(MailboxPlatformsView(mailboxes)) hass.http.register_view(MailboxMessageView(mailboxes)) hass.http.register_view(MailboxMediaView(mailboxes)) hass.http.register_view(MailboxDeleteView(mailboxes)) async def async_setup_platform( p_type: str, p_config: ConfigType | None = None, discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up a mailbox platform.""" if p_config is None: p_config = {} if discovery_info is None: discovery_info = {} platform = await async_prepare_setup_platform(hass, config, DOMAIN, p_type) if platform is None: _LOGGER.error("Unknown mailbox platform specified") return _LOGGER.info("Setting up %s.%s", DOMAIN, p_type) mailbox = None try: if hasattr(platform, "async_get_handler"): mailbox = await platform.async_get_handler( hass, p_config, discovery_info) elif hasattr(platform, "get_handler"): mailbox = await hass.async_add_executor_job( platform.get_handler, hass, p_config, discovery_info) else: raise HomeAssistantError("Invalid mailbox platform.") if mailbox is None: _LOGGER.error("Failed to initialize mailbox platform %s", p_type) return except Exception: # pylint: disable=broad-except _LOGGER.exception("Error setting up platform %s", p_type) return mailboxes.append(mailbox) mailbox_entity = MailboxEntity(mailbox) component = EntityComponent(logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) await component.async_add_entities([mailbox_entity]) setup_tasks = [ asyncio.create_task(async_setup_platform(p_type, p_config)) for p_type, p_config in config_per_platform(config, DOMAIN) if p_type is not None ] if setup_tasks: await asyncio.wait(setup_tasks) async def async_platform_discovered(platform, info): """Handle for discovered platform.""" await async_setup_platform(platform, discovery_info=info) discovery.async_listen_platform(hass, DOMAIN, async_platform_discovered) return True
schema=SERVICE_LIST_SCHEMA, ) hass.services.async_register( DOMAIN, SERVICE_CLEAR_COMPLETED_ITEMS, clear_completed_items_service, schema=SERVICE_LIST_SCHEMA, ) hass.http.register_view(ShoppingListView) hass.http.register_view(CreateShoppingListItemView) hass.http.register_view(UpdateShoppingListItemView) hass.http.register_view(ClearCompletedItemsView) frontend.async_register_built_in_panel( hass, "shopping-list", "shopping_list", "mdi:cart" ) websocket_api.async_register_command( hass, WS_TYPE_SHOPPING_LIST_ITEMS, websocket_handle_items, SCHEMA_WEBSOCKET_ITEMS, ) websocket_api.async_register_command( hass, WS_TYPE_SHOPPING_LIST_ADD_ITEM, websocket_handle_add, SCHEMA_WEBSOCKET_ADD_ITEM, ) websocket_api.async_register_command(
async def async_setup(hass: HomeAssistantType, config: ConfigType): """Set up the Lovelace commands.""" mode = config[DOMAIN][CONF_MODE] yaml_resources = config[DOMAIN].get(CONF_RESOURCES) frontend.async_register_built_in_panel(hass, DOMAIN, config={"mode": mode}) # ais fix migration dashboards - remove in version 1.0 # run this only if lovelace_dashboards not exist and lovelace exists storage_path = "/data/data/pl.sviete.dom/files/home/AIS/.storage/" import os import shutil if os.path.exists(storage_path + "lovelace") and not os.path.exists( storage_path + "lovelace_dashboards"): ais_dom_lovelace_path = (str(os.path.dirname(__file__)) + "/ais_dom_lovelace_full") ais_dom_dashboards_path = (str(os.path.dirname(__file__)) + "/lovelace_dashboards") # 1. move current lovelace shutil.move(storage_path + "lovelace", storage_path + "lovelace.lovelace_dom") # 2. copy ais dom lovelace as default lovelace shutil.copy(ais_dom_lovelace_path, storage_path + "lovelace") # 3. copy lovelace_dashboards shutil.copy(ais_dom_dashboards_path, storage_path + "lovelace_dashboards") async def reload_resources_service_handler( service_call: ServiceCallType) -> None: """Reload yaml resources.""" try: conf = await async_hass_config_yaml(hass) except HomeAssistantError as err: _LOGGER.error(err) return integration = await async_get_integration(hass, DOMAIN) config = await async_process_component_config(hass, conf, integration) resource_collection = await create_yaml_resource_col( hass, config[DOMAIN].get(CONF_RESOURCES)) hass.data[DOMAIN]["resources"] = resource_collection if mode == MODE_YAML: default_config = dashboard.LovelaceYAML(hass, None, None) resource_collection = await create_yaml_resource_col( hass, yaml_resources) async_register_admin_service( hass, DOMAIN, SERVICE_RELOAD_RESOURCES, reload_resources_service_handler, schema=RESOURCE_RELOAD_SERVICE_SCHEMA, ) else: default_config = dashboard.LovelaceStorage(hass, None) if yaml_resources is not None: _LOGGER.warning( "Lovelace is running in storage mode. Define resources via user interface" ) resource_collection = resources.ResourceStorageCollection( hass, default_config) collection.StorageCollectionWebsocket( resource_collection, "lovelace/resources", "resource", RESOURCE_CREATE_FIELDS, RESOURCE_UPDATE_FIELDS, ).async_setup(hass, create_list=False) hass.components.websocket_api.async_register_command( websocket.websocket_lovelace_config) hass.components.websocket_api.async_register_command( websocket.websocket_lovelace_save_config) hass.components.websocket_api.async_register_command( websocket.websocket_lovelace_delete_config) hass.components.websocket_api.async_register_command( websocket.websocket_lovelace_resources) hass.components.websocket_api.async_register_command( websocket.websocket_lovelace_dashboards) hass.components.system_health.async_register_info(DOMAIN, system_health_info) hass.data[DOMAIN] = { # We store a dictionary mapping url_path: config. None is the default. "dashboards": { None: default_config }, "resources": resource_collection, "yaml_dashboards": config[DOMAIN].get(CONF_DASHBOARDS, {}), } if hass.config.safe_mode: return True async def storage_dashboard_changed(change_type, item_id, item): """Handle a storage dashboard change.""" url_path = item[CONF_URL_PATH] if change_type == collection.CHANGE_REMOVED: frontend.async_remove_panel(hass, url_path) await hass.data[DOMAIN]["dashboards"].pop(url_path).async_delete() return if change_type == collection.CHANGE_ADDED: existing = hass.data[DOMAIN]["dashboards"].get(url_path) if existing: _LOGGER.warning( "Cannot register panel at %s, it is already defined in %s", url_path, existing, ) return hass.data[DOMAIN]["dashboards"][ url_path] = dashboard.LovelaceStorage(hass, item) update = False else: hass.data[DOMAIN]["dashboards"][url_path].config = item update = True try: _register_panel(hass, url_path, MODE_STORAGE, item, update) except ValueError: _LOGGER.warning("Failed to %s panel %s from storage", change_type, url_path) # Process YAML dashboards for url_path, dashboard_conf in hass.data[DOMAIN]["yaml_dashboards"].items( ): # For now always mode=yaml config = dashboard.LovelaceYAML(hass, url_path, dashboard_conf) hass.data[DOMAIN]["dashboards"][url_path] = config try: _register_panel(hass, url_path, MODE_YAML, dashboard_conf, False) except ValueError: _LOGGER.warning("Panel url path %s is not unique", url_path) # Process storage dashboards dashboards_collection = dashboard.DashboardsCollection(hass) dashboards_collection.async_add_listener(storage_dashboard_changed) await dashboards_collection.async_load() collection.StorageCollectionWebsocket( dashboards_collection, "lovelace/dashboards", "dashboard", STORAGE_DASHBOARD_CREATE_FIELDS, STORAGE_DASHBOARD_UPDATE_FIELDS, ).async_setup(hass, create_list=False) return True