diff --git a/custom_components/variable/__init__.py b/custom_components/variable/__init__.py index a6ea8b3..322514a 100644 --- a/custom_components/variable/__init__.py +++ b/custom_components/variable/__init__.py @@ -1,4 +1,5 @@ """Variable implementation for Home Assistant.""" +import copy import json import logging @@ -27,6 +28,8 @@ CONF_RESTORE, CONF_VALUE, CONF_VARIABLE_ID, + CONF_YAML_PRESENT, + CONF_YAML_VARIABLE, DEFAULT_REPLACE_ATTRIBUTES, DOMAIN, PLATFORMS, @@ -115,7 +118,6 @@ async def _async_set_legacy_service(call, var_ent): variables = json.loads(json.dumps(config.get(DOMAIN, {}))) for var, var_fields in variables.items(): - if var is not None: _LOGGER.debug(f"[YAML] variable_id: {var}") _LOGGER.debug(f"[YAML] var_fields: {var_fields}") @@ -133,7 +135,7 @@ async def _async_set_legacy_service(call, var_ent): entry.data.get(CONF_VARIABLE_ID) for entry in hass.config_entries.async_entries(DOMAIN) }: - _LOGGER.warning(f"[YAML Import] Creating New Sensor Variable: {var}") + _LOGGER.warning(f"[YAML] Creating New Sensor Variable: {var}") hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, @@ -151,21 +153,22 @@ async def _async_set_legacy_service(call, var_ent): ) ) else: - _LOGGER.info(f"[YAML Update] Updating Existing Sensor Variable: {var}") + _LOGGER.info(f"[YAML] Updating Existing Sensor Variable: {var}") entry_id = None for ent in hass.config_entries.async_entries(DOMAIN): if var == ent.data.get(CONF_VARIABLE_ID): entry_id = ent.entry_id break - _LOGGER.debug(f"[YAML Update] entry_id: {entry_id}") + # _LOGGER.debug(f"[YAML] entry_id: {entry_id}") if entry_id: entry = ent - # _LOGGER.debug(f"[YAML Update] entry before: {entry.as_dict()}") + # _LOGGER.debug(f"[YAML] entry before: {entry.as_dict()}") for m in dict(entry.data).keys(): var_fields.setdefault(m, entry.data[m]) - _LOGGER.debug(f"[YAML Update] updated var_fields: {var_fields}") + var_fields.update({CONF_YAML_PRESENT: True}) + # _LOGGER.debug(f"[YAML] Updated var_fields: {var_fields}") entry.options = {} hass.config_entries.async_update_entry( entry, data=var_fields, options=entry.options @@ -175,7 +178,7 @@ async def _async_set_legacy_service(call, var_ent): else: _LOGGER.error( - f"YAML Update Error. Could not find entry_id for: {var}" + f"[YAML] Update Error. Could not find entry_id for: {var}" ) return True @@ -186,6 +189,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: entry.options = {} # _LOGGER.debug(f"[init async_setup_entry] entry: {entry.data}") + if entry.data.get(CONF_YAML_VARIABLE, False) is True: + if entry.data.get(CONF_YAML_PRESENT, False) is False: + _LOGGER.warning( + f"[YAML] YAML Entry no longer exists, deleting entry in HA: {entry.data.get(CONF_VARIABLE_ID)}" + ) + # _LOGGER.debug(f"[YAML] entry_id: {entry.entry_id}") + hass.async_create_task(hass.config_entries.async_remove(entry.entry_id)) + return False + else: + yaml_data = copy.deepcopy(dict(entry.data)) + yaml_data.pop(CONF_YAML_PRESENT, None) + entry.options = {} + hass.config_entries.async_update_entry( + entry, data=yaml_data, options=entry.options + ) + hass.data.setdefault(DOMAIN, {}) hass_data = dict(entry.data) hass.data[DOMAIN][entry.entry_id] = hass_data diff --git a/custom_components/variable/config_flow.py b/custom_components/variable/config_flow.py index 5c9cdfd..8fb3993 100644 --- a/custom_components/variable/config_flow.py +++ b/custom_components/variable/config_flow.py @@ -35,6 +35,7 @@ CONF_VALUE, CONF_VALUE_TYPE, CONF_VARIABLE_ID, + CONF_YAML_PRESENT, CONF_YAML_VARIABLE, DEFAULT_EXCLUDE_FROM_RECORDER, DEFAULT_FORCE_UPDATE, @@ -208,7 +209,6 @@ async def validate_sensor_input(hass: HomeAssistant, data: dict) -> dict[str, An class VariableConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): - VERSION = 1 # Connection classes in homeassistant/config_entries.py are now deprecated @@ -226,6 +226,8 @@ async def async_step_add_sensor( if user_input is not None: user_input.update({CONF_ENTITY_PLATFORM: Platform.SENSOR}) user_input.update({CONF_YAML_VARIABLE: yaml_variable}) + if yaml_variable: + user_input.update({CONF_YAML_PRESENT: True}) _LOGGER.debug(f"[New Sensor Variable] page_1_input: {user_input}") self.add_sensor_input = user_input return await self.async_step_sensor_page_2() @@ -453,10 +455,11 @@ async def async_step_add_binary_sensor( self, user_input=None, errors=None, yaml_variable=False ): if user_input is not None: - try: user_input.update({CONF_ENTITY_PLATFORM: Platform.BINARY_SENSOR}) user_input.update({CONF_YAML_VARIABLE: yaml_variable}) + if yaml_variable: + user_input.update({CONF_YAML_PRESENT: True}) info = await validate_sensor_input(self.hass, user_input) _LOGGER.debug(f"[New Binary Sensor] updated user_input: {user_input}") return self.async_create_entry( @@ -482,10 +485,11 @@ async def async_step_add_device_tracker( self, user_input=None, errors=None, yaml_variable=False ): if user_input is not None: - try: user_input.update({CONF_ENTITY_PLATFORM: Platform.DEVICE_TRACKER}) user_input.update({CONF_YAML_VARIABLE: yaml_variable}) + if yaml_variable: + user_input.update({CONF_YAML_PRESENT: True}) info = await validate_sensor_input(self.hass, user_input) _LOGGER.debug(f"[New Device Tracker] updated user_input: {user_input}") return self.async_create_entry( @@ -511,6 +515,7 @@ async def async_step_add_device_tracker( async def async_step_import(self, import_config=None) -> FlowResult: """Import a config entry from configuration.yaml.""" + # _LOGGER.debug(f"[async_step_import] import_config: {import_config}") return await self.async_step_add_sensor( user_input=import_config, yaml_variable=True ) @@ -548,13 +553,12 @@ async def async_step_init( ): return await new_func() else: - _LOGGER.debug("No Options for YAML Created Variables") + _LOGGER.debug("[YAML] No Options for YAML Created Variables") return self.async_abort(reason="yaml_variable") async def async_step_sensor_options( self, user_input=None, errors=None ) -> FlowResult: - if user_input is not None: _LOGGER.debug(f"[Sensor Options Page 1] page_1_input: {user_input}") self.sensor_options_page_1 = user_input @@ -772,7 +776,9 @@ def build_sensor_options_page_2(self): else: SENSOR_OPTIONS_PAGE_2_SCHEMA = SENSOR_OPTIONS_PAGE_2_SCHEMA.extend( { - vol.Optional(CONF_VALUE,): selector.DateTimeSelector( + vol.Optional( + CONF_VALUE, + ): selector.DateTimeSelector( selector.DateTimeSelectorConfig() ) } @@ -885,7 +891,6 @@ def build_sensor_options_page_2(self): async def async_step_binary_sensor_options( self, user_input=None, errors=None ) -> FlowResult: - if user_input is not None: _LOGGER.debug(f"[Binary Sensor Options] user_input: {user_input}") for m in dict(self.config_entry.data).keys(): @@ -969,7 +974,6 @@ async def async_step_binary_sensor_options( async def async_step_device_tracker_options( self, user_input=None, errors=None ) -> FlowResult: - if user_input is not None: _LOGGER.debug(f"[Device Tracker Options] user_input: {user_input}") for m in dict(self.config_entry.data).keys(): @@ -1059,7 +1063,9 @@ async def async_step_device_tracker_options( if self.config_entry.data.get(ATTR_BATTERY_LEVEL) is None: DEVICE_TRACKER_OPTIONS_SCHEMA = DEVICE_TRACKER_OPTIONS_SCHEMA.extend( { - vol.Optional(ATTR_BATTERY_LEVEL,): selector.NumberSelector( + vol.Optional( + ATTR_BATTERY_LEVEL, + ): selector.NumberSelector( selector.NumberSelectorConfig( min=0, max=100, diff --git a/custom_components/variable/const.py b/custom_components/variable/const.py index 502f964..e7edce3 100644 --- a/custom_components/variable/const.py +++ b/custom_components/variable/const.py @@ -23,6 +23,7 @@ CONF_VALUE = "value" CONF_VALUE_TYPE = "value_type" CONF_VARIABLE_ID = "variable_id" +CONF_YAML_PRESENT = "yaml_present" CONF_YAML_VARIABLE = "yaml_variable" CONF_EXCLUDE_FROM_RECORDER = "exclude_from_recorder" CONF_UPDATED = "config_updated" diff --git a/custom_components/variable/helpers.py b/custom_components/variable/helpers.py index a1d1a58..e60bb45 100644 --- a/custom_components/variable/helpers.py +++ b/custom_components/variable/helpers.py @@ -17,7 +17,6 @@ def to_num(s): def value_to_type(init_val, dest_type): # noqa: C901 - if init_val is None or ( isinstance(init_val, str) and init_val.lower() in ["", "none", "unknown", "unavailable"] @@ -124,7 +123,7 @@ def value_to_type(init_val, dest_type): # noqa: C901 _LOGGER.debug(f"Invalid dest_type: {dest_type}, returning None") raise ValueError(f"Invalid dest_type: {dest_type}") return None - elif isinstance(init_val, datetime.date) and type(init_val) == datetime.date: + elif isinstance(init_val, datetime.date) and type(init_val) is datetime.date: # _LOGGER.debug("[value_to_type] Processing as date") if dest_type is None or dest_type == "string": _LOGGER.debug( @@ -153,7 +152,7 @@ def value_to_type(init_val, dest_type): # noqa: C901 raise ValueError(f"Invalid dest_type: {dest_type}") return None elif ( - isinstance(init_val, datetime.datetime) and type(init_val) == datetime.datetime + isinstance(init_val, datetime.datetime) and type(init_val) is datetime.datetime ): # _LOGGER.debug("[value_to_type] Processing as datetime") if dest_type is None or dest_type == "string": diff --git a/custom_components/variable/strings.json b/custom_components/variable/strings.json index 57a2cf1..b7a10ab 100644 --- a/custom_components/variable/strings.json +++ b/custom_components/variable/strings.json @@ -112,7 +112,7 @@ "longitude": "Longitude (typically only useful if Restore on Restart is False)", "location_name": "Location Name (typically only useful if Restore on Restart is False)", "gps_accuracy": "GPS Accuracy (typically only useful if Restore on Restart is False)", - "battery_level": "Battery Level (typically only useful if Restore on Restart is False)", + "battery_level": "Battery Level (typically only useful if Restore on Restart is False)", "attributes": "Attributes (typically only useful if Restore on Restart is False)", "restore": "Restore on Restart", "force_update": "Force Update", @@ -122,7 +122,7 @@ } }, "abort": { - "yaml_variable": "Cannot change options here for Variables created by YAML.\n\nTo use the User Interface to manage this Variable, you will need to:\n1. Remove it from YAML\n2. Delete the imported Variable entity from Home Assistant\n3. Restart Home Assistant\n4. Manually recreate it in Home Assistant, Integrations, +Add Integration.", + "yaml_variable": "Cannot change options here for Variables created by YAML.\n\nTo use the User Interface to manage this Variable, you will need to:\n1. Remove it from YAML\n2. Restart Home Assistant\n3. Manually recreate it in Home Assistant, Integrations, +Add Integration.", "yaml_update_error": "Unable to update YAML Sensor Variable" }, "error": { diff --git a/custom_components/variable/translations/en.json b/custom_components/variable/translations/en.json index 2bf3907..ba1855e 100644 --- a/custom_components/variable/translations/en.json +++ b/custom_components/variable/translations/en.json @@ -112,7 +112,7 @@ "longitude": "Longitude (typically only useful if Restore on Restart is False)", "location_name": "Location Name (typically only useful if Restore on Restart is False)", "gps_accuracy": "GPS Accuracy (typically only useful if Restore on Restart is False)", - "battery_level": "Battery Level (typically only useful if Restore on Restart is False)", + "battery_level": "Battery Level (typically only useful if Restore on Restart is False)", "attributes": "Attributes (typically only useful if Restore on Restart is False)", "restore": "Restore on Restart", "force_update": "Force Update", @@ -122,7 +122,7 @@ } }, "abort": { - "yaml_variable": "Cannot change options here for Variables created by YAML.\n\nTo use the User Interface to manage this Variable, you will need to:\n1. Remove it from YAML\n2. Delete the imported Variable entity from Home Assistant\n3. Restart Home Assistant\n4. Manually recreate it in Home Assistant, Integrations, +Add Integration.", + "yaml_variable": "Cannot change options here for Variables created by YAML.\n\nTo use the User Interface to manage this Variable, you will need to:\n1. Remove it from YAML\n2. Restart Home Assistant\n3. Manually recreate it in Home Assistant, Integrations, +Add Integration.", "yaml_update_error": "Unable to update YAML Sensor Variable" }, "error": {