diff --git a/custom_components/watchman/__init__.py b/custom_components/watchman/__init__.py index 29842fa..c953d82 100644 --- a/custom_components/watchman/__init__.py +++ b/custom_components/watchman/__init__.py @@ -59,6 +59,13 @@ CONF_TEST_MODE, EVENT_AUTOMATION_RELOADED, EVENT_SCENE_RELOADED, + HASS_DATA_CANCEL_HANDLERS, + HASS_DATA_COORDINATOR, + HASS_DATA_FILES_IGNORED, + HASS_DATA_FILES_PARSED, + HASS_DATA_PARSE_DURATION, + HASS_DATA_PARSED_ENTITY_LIST, + HASS_DATA_PARSED_SERVICE_LIST, TRACKED_EVENT_DOMAINS, MONITORED_STATES, PLATFORMS, @@ -122,7 +129,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): raise ConfigEntryNotReady hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator - hass.data[DOMAIN]["coordinator"] = coordinator + hass.data[DOMAIN][HASS_DATA_COORDINATOR] = coordinator hass.data[DOMAIN_DATA] = entry.options # TODO: refactor await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) @@ -148,7 +155,7 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistant, config_entry): # pylint: disable=unused-argument """Handle integration unload""" - for cancel_handle in hass.data[DOMAIN].get("cancel_handlers", []): + for cancel_handle in hass.data[DOMAIN].get(HASS_DATA_CANCEL_HANDLERS, []): if cancel_handle: cancel_handle() @@ -256,7 +263,7 @@ async def async_schedule_refresh_states(hass, delay): async def async_delayed_refresh_states(timedate): # pylint: disable=unused-argument """refresh sensors state""" # parse_config should be invoked beforehand - coordinator = hass.data[DOMAIN]["coordinator"] + coordinator = hass.data[DOMAIN][HASS_DATA_COORDINATOR] await coordinator.async_refresh() async def async_on_home_assistant_started(event): # pylint: disable=unused-argument @@ -274,19 +281,19 @@ async def async_on_configuration_changed(event): "reload", ]: await parse_config(hass, reason="configuration changes") - coordinator = hass.data[DOMAIN]["coordinator"] + coordinator = hass.data[DOMAIN][HASS_DATA_COORDINATOR] await coordinator.async_refresh() elif typ in [EVENT_AUTOMATION_RELOADED, EVENT_SCENE_RELOADED]: await parse_config(hass, reason="configuration changes") - coordinator = hass.data[DOMAIN]["coordinator"] + coordinator = hass.data[DOMAIN][HASS_DATA_COORDINATOR] await coordinator.async_refresh() async def async_on_service_changed(event): service = f"{event.data['domain']}.{event.data['service']}" - if service in hass.data[DOMAIN].get("service_list", []): + if service in hass.data[DOMAIN].get(HASS_DATA_PARSED_SERVICE_LIST, []): _LOGGER.debug("Monitored service changed: %s", service) - coordinator = hass.data[DOMAIN]["coordinator"] + coordinator = hass.data[DOMAIN][HASS_DATA_COORDINATOR] await coordinator.async_refresh() async def async_on_state_changed(event): @@ -296,14 +303,16 @@ def state_or_missing(state_id): """return missing state if entity not found""" return "missing" if not event.data[state_id] else event.data[state_id].state - if event.data["entity_id"] in hass.data[DOMAIN].get("entity_list", []): + if event.data["entity_id"] in hass.data[DOMAIN].get( + HASS_DATA_PARSED_ENTITY_LIST, [] + ): ignored_states = get_config(hass, CONF_IGNORED_STATES, []) old_state = state_or_missing("old_state") new_state = state_or_missing("new_state") checked_states = set(MONITORED_STATES) - set(ignored_states) if new_state in checked_states or old_state in checked_states: _LOGGER.debug("Monitored entity changed: %s", event.data["entity_id"]) - coordinator = hass.data[DOMAIN]["coordinator"] + coordinator = hass.data[DOMAIN][HASS_DATA_COORDINATOR] await coordinator.async_refresh() # hass is not started yet, schedule config parsing once it loaded @@ -327,7 +336,7 @@ def state_or_missing(state_id): ) hdlr.append(hass.bus.async_listen(EVENT_SERVICE_REMOVED, async_on_service_changed)) hdlr.append(hass.bus.async_listen(EVENT_STATE_CHANGED, async_on_state_changed)) - hass.data[DOMAIN]["cancel_handlers"] = hdlr + hass.data[DOMAIN][HASS_DATA_CANCEL_HANDLERS] = hdlr async def parse_config(hass: HomeAssistant, reason=None): @@ -337,19 +346,19 @@ async def parse_config(hass: HomeAssistant, reason=None): included_folders = get_included_folders(hass) ignored_files = hass.data[DOMAIN_DATA].get(CONF_IGNORED_FILES, None) - entity_list, service_list, files_parsed, files_ignored = await parse( + parsed_entity_list, parsed_service_list, files_parsed, files_ignored = await parse( hass, included_folders, ignored_files, hass.config.config_dir ) - hass.data[DOMAIN]["entity_list"] = entity_list - hass.data[DOMAIN]["service_list"] = service_list - hass.data[DOMAIN]["files_parsed"] = files_parsed - hass.data[DOMAIN]["files_ignored"] = files_ignored - hass.data[DOMAIN]["parse_duration"] = time.time() - start_time + hass.data[DOMAIN][HASS_DATA_PARSED_ENTITY_LIST] = parsed_entity_list + hass.data[DOMAIN][HASS_DATA_PARSED_SERVICE_LIST] = parsed_service_list + hass.data[DOMAIN][HASS_DATA_FILES_PARSED] = files_parsed + hass.data[DOMAIN][HASS_DATA_FILES_IGNORED] = files_ignored + hass.data[DOMAIN][HASS_DATA_PARSE_DURATION] = time.time() - start_time _LOGGER.info( "%s files parsed and %s files ignored in %.2fs. due to %s", files_parsed, files_ignored, - hass.data[DOMAIN]["parse_duration"], + hass.data[DOMAIN][HASS_DATA_PARSE_DURATION], reason, ) @@ -375,7 +384,7 @@ def get_included_folders(hass): async def async_report_to_file(hass, path, test_mode): """save report to a file""" - coordinator = hass.data[DOMAIN]["coordinator"] + coordinator = hass.data[DOMAIN][HASS_DATA_COORDINATOR] await coordinator.async_refresh() report_chunks = await report( hass, table_renderer, chunk_size=0, test_mode=test_mode @@ -415,7 +424,7 @@ async def async_report_to_notification(hass, service_str, service_data, chunk_si data = {} if service_data is None else json.loads(service_data) - coordinator = hass.data[DOMAIN]["coordinator"] + coordinator = hass.data[DOMAIN][HASS_DATA_COORDINATOR] await coordinator.async_refresh() report_chunks = await report(hass, text_renderer, chunk_size) for chunk in report_chunks: diff --git a/custom_components/watchman/const.py b/custom_components/watchman/const.py index 3af06bb..a90b009 100644 --- a/custom_components/watchman/const.py +++ b/custom_components/watchman/const.py @@ -10,6 +10,26 @@ DEFAULT_HEADER = "-== WATCHMAN REPORT ==- " DEFAULT_CHUNK_SIZE = 3500 +HASS_DATA_PARSED_ENTITY_LIST = "entity_list" +HASS_DATA_PARSED_SERVICE_LIST = "service_list" +HASS_DATA_FILES_PARSED = "files_parsed" +HASS_DATA_FILES_IGNORED = "files_ignored" +HASS_DATA_PARSE_DURATION = "parse_duration" +HASS_DATA_CANCEL_HANDLERS = "cancel_handlers" +HASS_DATA_COORDINATOR = "coordinator" +HASS_DATA_MISSING_ENTITIES = "entities_missing" +HASS_DATA_MISSING_SERVICES = "services_missing" +HASS_DATA_CHECK_DURATION = "check_duration" + +COORD_DATA_MISSING_ENTITIES = "entities_missing" +COORD_DATA_MISSING_SERVICES = "services_missing" +COORD_DATA_LAST_UPDATE = "last_update" +COORD_DATA_SERVICE_ATTRS = "service_attrs" +COORD_DATA_ENTITY_ATTRS = "entity_attrs" + +REPORT_ENTRY_TYPE_SERVICE = "service_list" +REPORT_ENTRY_TYPE_ENTITY = "entity_list" + CONF_IGNORED_FILES = "ignored_files" CONF_HEADER = "report_header" CONF_REPORT_PATH = "report_path" diff --git a/custom_components/watchman/coordinator.py b/custom_components/watchman/coordinator.py index 6f0f74f..d8a06cc 100644 --- a/custom_components/watchman/coordinator.py +++ b/custom_components/watchman/coordinator.py @@ -4,7 +4,19 @@ import time from homeassistant.util import dt as dt_util from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from .const import DOMAIN +from .const import ( + COORD_DATA_ENTITY_ATTRS, + COORD_DATA_LAST_UPDATE, + COORD_DATA_MISSING_ENTITIES, + COORD_DATA_MISSING_SERVICES, + COORD_DATA_SERVICE_ATTRS, + DOMAIN, + HASS_DATA_CHECK_DURATION, + HASS_DATA_MISSING_ENTITIES, + HASS_DATA_MISSING_SERVICES, + HASS_DATA_PARSED_ENTITY_LIST, + HASS_DATA_PARSED_SERVICE_LIST, +) from .utils import check_entitites, check_services, get_entity_state, fill @@ -29,13 +41,13 @@ async def _async_update_data(self) -> None: start_time = time.time() services_missing = check_services(self.hass) entities_missing = check_entitites(self.hass) - self.hass.data[DOMAIN]["check_duration"] = time.time() - start_time - self.hass.data[DOMAIN]["entities_missing"] = entities_missing - self.hass.data[DOMAIN]["services_missing"] = services_missing + self.hass.data[DOMAIN][HASS_DATA_CHECK_DURATION] = time.time() - start_time + self.hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES] = entities_missing + self.hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES] = services_missing # build entity attributes map for missing_entities sensor entity_attrs = [] - entity_list = self.hass.data[DOMAIN]["entity_list"] + parsed_entity_list = self.hass.data[DOMAIN][HASS_DATA_PARSED_ENTITY_LIST] for entity in entities_missing: state, name = get_entity_state(self.hass, entity, friendly_names=True) entity_attrs.append( @@ -43,24 +55,24 @@ async def _async_update_data(self) -> None: "id": entity, "state": state, "friendly_name": name or "", - "occurrences": fill(entity_list[entity], 0), + "occurrences": fill(parsed_entity_list[entity], 0), } ) # build service attributes map for missing_services sensor service_attrs = [] - service_list = self.hass.data[DOMAIN]["service_list"] + parsed_service_list = self.hass.data[DOMAIN][HASS_DATA_PARSED_SERVICE_LIST] for service in services_missing: service_attrs.append( - {"id": service, "occurrences": fill(service_list[service], 0)} + {"id": service, "occurrences": fill(parsed_service_list[service], 0)} ) self.data = { - "entities_missing": len(entities_missing), - "services_missing": len(services_missing), - "last_update": dt_util.now(), - "service_attrs": service_attrs, - "entity_attrs": entity_attrs, + COORD_DATA_MISSING_ENTITIES: len(entities_missing), + COORD_DATA_MISSING_SERVICES: len(services_missing), + COORD_DATA_LAST_UPDATE: dt_util.now(), + COORD_DATA_SERVICE_ATTRS: service_attrs, + COORD_DATA_ENTITY_ATTRS: entity_attrs, } _LOGGER.debug("Watchman sensors updated") diff --git a/custom_components/watchman/sensor.py b/custom_components/watchman/sensor.py index ddb2bac..9178c5d 100644 --- a/custom_components/watchman/sensor.py +++ b/custom_components/watchman/sensor.py @@ -13,6 +13,11 @@ from .entity import WatchmanEntity from .const import ( + COORD_DATA_ENTITY_ATTRS, + COORD_DATA_LAST_UPDATE, + COORD_DATA_MISSING_ENTITIES, + COORD_DATA_MISSING_SERVICES, + COORD_DATA_SERVICE_ATTRS, DOMAIN, SENSOR_LAST_UPDATE, SENSOR_MISSING_ENTITIES, @@ -71,7 +76,7 @@ def should_poll(self) -> bool: def native_value(self): """Return the native value of the sensor.""" if self.coordinator.data: - return self.coordinator.data["last_update"] + return self.coordinator.data[COORD_DATA_LAST_UPDATE] else: return self._attr_native_value @@ -79,7 +84,7 @@ def native_value(self): def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" if self.coordinator.data: - self._attr_native_value = self.coordinator.data["last_update"] + self._attr_native_value = self.coordinator.data[COORD_DATA_LAST_UPDATE] self.async_write_ha_state() super()._handle_coordinator_update() @@ -100,7 +105,7 @@ def should_poll(self) -> bool: def native_value(self): """Return the native value of the sensor.""" if self.coordinator.data: - return self.coordinator.data["entities_missing"] + return self.coordinator.data[COORD_DATA_MISSING_ENTITIES] else: return self._attr_native_value @@ -108,7 +113,7 @@ def native_value(self): def extra_state_attributes(self): """Return the state attributes.""" if self.coordinator.data: - return {"entities": self.coordinator.data["entity_attrs"]} + return {"entities": self.coordinator.data[COORD_DATA_ENTITY_ATTRS]} else: return {} @@ -116,9 +121,9 @@ def extra_state_attributes(self): def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" if self.coordinator.data: - self._attr_native_value = self.coordinator.data["entities_missing"] + self._attr_native_value = self.coordinator.data[COORD_DATA_MISSING_ENTITIES] self._attr_extra_state_attributes = { - "entities": self.coordinator.data["entity_attrs"] + "entities": self.coordinator.data[COORD_DATA_ENTITY_ATTRS] } self.async_write_ha_state() super()._handle_coordinator_update() @@ -140,7 +145,7 @@ def should_poll(self) -> bool: def native_value(self): """Return the native value of the sensor.""" if self.coordinator.data: - return self.coordinator.data["services_missing"] + return self.coordinator.data[COORD_DATA_MISSING_SERVICES] else: return self._attr_native_value @@ -148,7 +153,7 @@ def native_value(self): def extra_state_attributes(self): """Return the state attributes.""" if self.coordinator.data: - return {"entities": self.coordinator.data["service_attrs"]} + return {"entities": self.coordinator.data[COORD_DATA_SERVICE_ATTRS]} else: return {} @@ -156,9 +161,9 @@ def extra_state_attributes(self): def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" if self.coordinator.data: - self._attr_native_value = self.coordinator.data["services_missing"] + self._attr_native_value = self.coordinator.data[COORD_DATA_MISSING_SERVICES] self._attr_extra_state_attributes = { - "services": self.coordinator.data["service_attrs"] + "services": self.coordinator.data[COORD_DATA_SERVICE_ATTRS] } self.async_write_ha_state() super()._handle_coordinator_update() diff --git a/custom_components/watchman/utils.py b/custom_components/watchman/utils.py index d66721c..6e84f0e 100644 --- a/custom_components/watchman/utils.py +++ b/custom_components/watchman/utils.py @@ -27,6 +27,16 @@ CONF_FRIENDLY_NAMES, BUNDLED_IGNORED_ITEMS, DEFAULT_REPORT_FILENAME, + HASS_DATA_CHECK_DURATION, + HASS_DATA_FILES_IGNORED, + HASS_DATA_FILES_PARSED, + HASS_DATA_MISSING_ENTITIES, + HASS_DATA_MISSING_SERVICES, + HASS_DATA_PARSE_DURATION, + HASS_DATA_PARSED_ENTITY_LIST, + HASS_DATA_PARSED_SERVICE_LIST, + REPORT_ENTRY_TYPE_ENTITY, + REPORT_ENTRY_TYPE_SERVICE, ) _LOGGER = logging.getLogger(__name__) @@ -69,9 +79,9 @@ def table_renderer(hass, entry_type): table = PrettyTable() columns_width = get_config(hass, CONF_COLUMNS_WIDTH, None) columns_width = get_columns_width(columns_width) - if entry_type == "service_list": - services_missing = hass.data[DOMAIN]["services_missing"] - service_list = hass.data[DOMAIN]["service_list"] + if entry_type == REPORT_ENTRY_TYPE_SERVICE: + services_missing = hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES] + service_list = hass.data[DOMAIN][HASS_DATA_PARSED_SERVICE_LIST] table.field_names = ["Service ID", "State", "Location"] for service in services_missing: row = [ @@ -82,9 +92,9 @@ def table_renderer(hass, entry_type): table.add_row(row) table.align = "l" return table.get_string() - elif entry_type == "entity_list": - entities_missing = hass.data[DOMAIN]["entities_missing"] - entity_list = hass.data[DOMAIN]["entity_list"] + elif entry_type == REPORT_ENTRY_TYPE_ENTITY: + entities_missing = hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES] + parsed_entity_list = hass.data[DOMAIN][HASS_DATA_PARSED_ENTITY_LIST] friendly_names = get_config(hass, CONF_FRIENDLY_NAMES, False) header = ["Entity ID", "State", "Location"] table.field_names = header @@ -94,7 +104,7 @@ def table_renderer(hass, entry_type): [ fill(entity, columns_width[0], name), fill(state, columns_width[1]), - fill(entity_list[entity], columns_width[2]), + fill(parsed_entity_list[entity], columns_width[2]), ] ) @@ -108,15 +118,15 @@ def table_renderer(hass, entry_type): def text_renderer(hass, entry_type): """Render plain lists in the report""" result = "" - if entry_type == "service_list": - services_missing = hass.data[DOMAIN]["services_missing"] - service_list = hass.data[DOMAIN]["service_list"] + if entry_type == REPORT_ENTRY_TYPE_SERVICE: + services_missing = hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES] + service_list = hass.data[DOMAIN][HASS_DATA_PARSED_SERVICE_LIST] for service in services_missing: result += f"{service} in {fill(service_list[service], 0)}\n" return result - elif entry_type == "entity_list": - entities_missing = hass.data[DOMAIN]["entities_missing"] - entity_list = hass.data[DOMAIN]["entity_list"] + elif entry_type == REPORT_ENTRY_TYPE_ENTITY: + entities_missing = hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES] + entity_list = hass.data[DOMAIN][HASS_DATA_PARSED_ENTITY_LIST] friendly_names = get_config(hass, CONF_FRIENDLY_NAMES, False) for entity in entities_missing: state, name = get_entity_state(hass, entity, friendly_names) @@ -184,11 +194,14 @@ def check_services(hass): services_missing = {} if "missing" in get_config(hass, CONF_IGNORED_STATES, []): return services_missing - if DOMAIN not in hass.data or "service_list" not in hass.data[DOMAIN]: + if ( + DOMAIN not in hass.data + or HASS_DATA_PARSED_SERVICE_LIST not in hass.data[DOMAIN] + ): raise HomeAssistantError("Service list not found") - service_list = hass.data[DOMAIN]["service_list"] + parsed_service_list = hass.data[DOMAIN][HASS_DATA_PARSED_SERVICE_LIST] _LOGGER.debug("::check_services") - for entry, occurences in service_list.items(): + for entry, occurences in parsed_service_list.items(): if not is_service(hass, entry): services_missing[entry] = occurences _LOGGER.debug("service %s added to missing list", entry) @@ -201,13 +214,13 @@ def check_entitites(hass): "unavail" if s == "unavailable" else s for s in get_config(hass, CONF_IGNORED_STATES, []) ] - if DOMAIN not in hass.data or "entity_list" not in hass.data[DOMAIN]: + if DOMAIN not in hass.data or HASS_DATA_PARSED_ENTITY_LIST not in hass.data[DOMAIN]: _LOGGER.error("Entity list not found") raise Exception("Entity list not found") - entity_list = hass.data[DOMAIN]["entity_list"] + parsed_entity_list = hass.data[DOMAIN][HASS_DATA_PARSED_ENTITY_LIST] entities_missing = {} _LOGGER.debug("::check_entities") - for entry, occurences in entity_list.items(): + for entry, occurences in parsed_entity_list.items(): if is_service(hass, entry): # this is a service, not entity _LOGGER.debug("entry %s is service, skipping", entry) continue @@ -233,8 +246,8 @@ async def parse(hass, folders, ignored_files, root=None): ) service_pattern = re.compile(r"service:\s*([A-Za-z_0-9]*\.[A-Za-z_0-9]+)") comment_pattern = re.compile(r"#.*") - entity_list = {} - service_list = {} + parsed_entity_list = {} + parsed_service_list = {} effectively_ignored = [] _LOGGER.debug("::parse started") async for yaml_file, ignored in async_get_next_file(folders, ignored_files): @@ -258,10 +271,10 @@ async def parse(hass, folders, ignored_files, root=None): and "*" not in val and not val.endswith(".yaml") ): - add_entry(entity_list, val, short_path, lineno) + add_entry(parsed_entity_list, val, short_path, lineno) for match in re.finditer(service_pattern, line): val = match.group(1) - add_entry(service_list, val, short_path, lineno) + add_entry(parsed_service_list, val, short_path, lineno) lineno += 1 files_parsed += 1 _LOGGER.debug("%s parsed", yaml_file) @@ -281,17 +294,26 @@ async def parse(hass, folders, ignored_files, root=None): excluded_services = [] for itm in ignored_items: if itm: - excluded_entities.extend(fnmatch.filter(entity_list, itm)) - excluded_services.extend(fnmatch.filter(service_list, itm)) + excluded_entities.extend(fnmatch.filter(parsed_entity_list, itm)) + excluded_services.extend(fnmatch.filter(parsed_service_list, itm)) - entity_list = {k: v for k, v in entity_list.items() if k not in excluded_entities} - service_list = {k: v for k, v in service_list.items() if k not in excluded_services} + parsed_entity_list = { + k: v for k, v in parsed_entity_list.items() if k not in excluded_entities + } + parsed_service_list = { + k: v for k, v in parsed_service_list.items() if k not in excluded_services + } _LOGGER.debug("Parsed files: %s", files_parsed) _LOGGER.debug("Ignored files: %s", effectively_ignored) - _LOGGER.debug("Found entities: %s", len(entity_list)) - _LOGGER.debug("Found services: %s", len(service_list)) - return (entity_list, service_list, files_parsed, len(effectively_ignored)) + _LOGGER.debug("Found entities: %s", len(parsed_entity_list)) + _LOGGER.debug("Found services: %s", len(parsed_service_list)) + return ( + parsed_entity_list, + parsed_service_list, + files_parsed, + len(effectively_ignored), + ) def fill(data, width, extra=None): @@ -314,12 +336,12 @@ async def report(hass, render, chunk_size, test_mode=False): start_time = time.time() header = get_config(hass, CONF_HEADER, DEFAULT_HEADER) - services_missing = hass.data[DOMAIN]["services_missing"] - service_list = hass.data[DOMAIN]["service_list"] - entities_missing = hass.data[DOMAIN]["entities_missing"] - entity_list = hass.data[DOMAIN]["entity_list"] - files_parsed = hass.data[DOMAIN]["files_parsed"] - files_ignored = hass.data[DOMAIN]["files_ignored"] + services_missing = hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES] + service_list = hass.data[DOMAIN][HASS_DATA_PARSED_SERVICE_LIST] + entities_missing = hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES] + entity_list = hass.data[DOMAIN][HASS_DATA_PARSED_ENTITY_LIST] + files_parsed = hass.data[DOMAIN][HASS_DATA_FILES_PARSED] + files_ignored = hass.data[DOMAIN][HASS_DATA_FILES_IGNORED] chunk_size = ( get_config(hass, CONF_CHUNK_SIZE, DEFAULT_CHUNK_SIZE) if chunk_size is None @@ -330,7 +352,7 @@ async def report(hass, render, chunk_size, test_mode=False): if services_missing: rep += f"\n-== Missing {len(services_missing)} service(s) from " rep += f"{len(service_list)} found in your config:\n" - rep += render(hass, "service_list") + rep += render(hass, REPORT_ENTRY_TYPE_SERVICE) rep += "\n" elif len(service_list) > 0: rep += f"\n-== Congratulations, all {len(service_list)} services from " @@ -341,7 +363,7 @@ async def report(hass, render, chunk_size, test_mode=False): if entities_missing: rep += f"\n-== Missing {len(entities_missing)} entity(ies) from " rep += f"{len(entity_list)} found in your config:\n" - rep += render(hass, "entity_list") + rep += render(hass, REPORT_ENTRY_TYPE_ENTITY) rep += "\n" elif len(entity_list) > 0: @@ -357,8 +379,8 @@ def get_timezone(hass): if not test_mode: report_datetime = datetime.now(timezone).strftime("%d %b %Y %H:%M:%S") - parse_duration = hass.data[DOMAIN]["parse_duration"] - check_duration = hass.data[DOMAIN]["check_duration"] + parse_duration = hass.data[DOMAIN][HASS_DATA_PARSE_DURATION] + check_duration = hass.data[DOMAIN][HASS_DATA_CHECK_DURATION] render_duration = time.time() - start_time else: report_datetime = "01 Jan 1970 00:00:00" diff --git a/tests/test_events.py b/tests/test_events.py index f52ec9c..90f424c 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -1,11 +1,17 @@ """Test table reports""" + from copy import deepcopy from pytest_homeassistant_custom_component.common import MockConfigEntry from homeassistant.core import callback from custom_components.watchman import ( async_setup_entry, ) -from custom_components.watchman.const import DOMAIN, CONF_INCLUDED_FOLDERS +from custom_components.watchman.const import ( + DOMAIN, + CONF_INCLUDED_FOLDERS, + HASS_DATA_MISSING_ENTITIES, + HASS_DATA_MISSING_SERVICES, +) from custom_components.watchman.config_flow import DEFAULT_DATA TEST_INCLUDED_FOLDERS = ["/workspaces/thewatchman/tests/input"] @@ -28,14 +34,14 @@ def dummy_service_handler(event): # pylint: disable=unused-argument domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 3 - assert len(hass.data[DOMAIN]["services_missing"]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 3 hass.services.async_register("fake", "service1", dummy_service_handler) await hass.async_block_till_done() - assert len(hass.data[DOMAIN]["services_missing"]) == 2 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 2 hass.services.async_remove("fake", "service1") await hass.async_block_till_done() - assert len(hass.data[DOMAIN]["services_missing"]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 3 async def test_change_state(hass): @@ -50,11 +56,11 @@ async def test_change_state(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 3 - assert len(hass.data[DOMAIN]["services_missing"]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 3 hass.states.async_set("sensor.test1_unknown", "available") await hass.async_block_till_done() - assert len(hass.data[DOMAIN]["entities_missing"]) == 2 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 2 async def test_remove_entity(hass): @@ -69,10 +75,10 @@ async def test_remove_entity(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 3 hass.states.async_remove("sensor.test4_avail") await hass.async_block_till_done() - assert len(hass.data[DOMAIN]["entities_missing"]) == 4 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 4 async def test_add_entity(hass): @@ -86,8 +92,8 @@ async def test_add_entity(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 4 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 4 # missing -> 42 hass.states.async_set("sensor.test4_avail", "42") await hass.async_block_till_done() - assert len(hass.data[DOMAIN]["entities_missing"]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 3 diff --git a/tests/test_init.py b/tests/test_init.py index 0413422..68f8d6f 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -1,4 +1,5 @@ """Test setup process.""" + from copy import deepcopy from pytest_homeassistant_custom_component.common import MockConfigEntry from custom_components.watchman import ( @@ -10,6 +11,10 @@ DOMAIN, CONF_INCLUDED_FOLDERS, CONF_IGNORED_FILES, + HASS_DATA_MISSING_ENTITIES, + HASS_DATA_MISSING_SERVICES, + HASS_DATA_PARSED_ENTITY_LIST, + HASS_DATA_PARSED_SERVICE_LIST, ) from custom_components.watchman.config_flow import DEFAULT_DATA @@ -40,8 +45,8 @@ async def test_missing(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 3 - assert len(hass.data[DOMAIN]["services_missing"]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 3 async def test_ignored_state(hass): @@ -57,8 +62,8 @@ async def test_ignored_state(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 2 - assert len(hass.data[DOMAIN]["services_missing"]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 2 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 3 async def test_multiple_ignored_states(hass): @@ -74,8 +79,8 @@ async def test_multiple_ignored_states(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 0 - assert len(hass.data[DOMAIN]["services_missing"]) == 0 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 0 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 0 async def test_ignored_files(hass): @@ -92,8 +97,8 @@ async def test_ignored_files(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 3 - assert len(hass.data[DOMAIN]["services_missing"]) == 0 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 0 async def test_ignored_items(hass): @@ -110,7 +115,7 @@ async def test_ignored_items(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entity_list"]) == 3 - assert len(hass.data[DOMAIN]["service_list"]) == 2 - assert len(hass.data[DOMAIN]["entities_missing"]) == 2 - assert len(hass.data[DOMAIN]["services_missing"]) == 2 + assert len(hass.data[DOMAIN][HASS_DATA_PARSED_ENTITY_LIST]) == 3 + assert len(hass.data[DOMAIN][HASS_DATA_PARSED_SERVICE_LIST]) == 2 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 2 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_SERVICES]) == 2 diff --git a/tests/test_regex.py b/tests/test_regex.py index 9b3bc47..bb1b4d4 100644 --- a/tests/test_regex.py +++ b/tests/test_regex.py @@ -1,10 +1,15 @@ """Test setup process.""" + from copy import deepcopy from pytest_homeassistant_custom_component.common import MockConfigEntry from custom_components.watchman import ( async_setup_entry, ) -from custom_components.watchman.const import DOMAIN, CONF_INCLUDED_FOLDERS +from custom_components.watchman.const import ( + DOMAIN, + CONF_INCLUDED_FOLDERS, + HASS_DATA_MISSING_ENTITIES, +) from custom_components.watchman.config_flow import DEFAULT_DATA TEST_INCLUDED_FOLDERS = ["/workspaces/thewatchman/tests/input_regex"] @@ -18,4 +23,4 @@ async def test_regex(hass): domain="watchman", data={}, options=options, entry_id="test" ) assert await async_setup_entry(hass, config_entry) - assert len(hass.data[DOMAIN]["entities_missing"]) == 10 + assert len(hass.data[DOMAIN][HASS_DATA_MISSING_ENTITIES]) == 10