diff --git a/custom_components/room_occupancy/.gitignore b/custom_components/room_occupancy/.gitignore new file mode 100644 index 0000000..ed8ebf5 --- /dev/null +++ b/custom_components/room_occupancy/.gitignore @@ -0,0 +1 @@ +__pycache__ \ No newline at end of file diff --git a/custom_components/room_occupancy/__init__.py b/custom_components/room_occupancy/__init__.py index 87493b3..84df5bf 100644 --- a/custom_components/room_occupancy/__init__.py +++ b/custom_components/room_occupancy/__init__.py @@ -15,10 +15,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Room Occupancy from a config entry.""" hass.data.setdefault(DOMAIN, {}) + entry.async_on_unload(entry.add_update_listener(update_listener)) + # entry.async_on_unload(entry.add_update_listener(update_listener)) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True +async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Update listener.""" + await hass.config_entries.async_reload(entry.entry_id) + + async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/custom_components/room_occupancy/binary_sensor.py b/custom_components/room_occupancy/binary_sensor.py index 73af4d6..2ec3bff 100644 --- a/custom_components/room_occupancy/binary_sensor.py +++ b/custom_components/room_occupancy/binary_sensor.py @@ -131,6 +131,11 @@ def check_states(self) -> bool: found = True return found + async def update_listener(self, entry): + """Handle options update.""" + _LOGGER.debug("update_listener triggered!") + _LOGGER.debug("entry: %s", entry.as_dict()) + @property def name(self) -> str: """Return the name of the sensor.""" diff --git a/custom_components/room_occupancy/config_flow.py b/custom_components/room_occupancy/config_flow.py index 0acedb8..3bd2657 100644 --- a/custom_components/room_occupancy/config_flow.py +++ b/custom_components/room_occupancy/config_flow.py @@ -7,10 +7,17 @@ import voluptuous as vol -from homeassistant.config_entries import ConfigFlow, ConfigFlowResult +from homeassistant.config_entries import ( + ConfigFlow, + ConfigFlowResult, + ConfigEntry, + OptionsFlow, +) from homeassistant.const import CONF_NAME +from homeassistant.data_entry_flow import FlowResult import homeassistant.helpers.config_validation as cv + from .const import ( CONF_ACTIVE_STATES, CONF_ENTITIES_KEEP, @@ -25,11 +32,104 @@ _LOGGER = logging.getLogger(__name__) +class OptionsFlowHandler(OptionsFlow): + """Options flow for room occupancy.""" + + def __init__(self, config_entry: ConfigEntry) -> None: + """Initialize options flow.""" + self.config_entry = config_entry + # self.options = dict(config_entry.options) + # _LOGGER.debug("OptionsFlow:Init: got triggered for: %s", config_entry) + # _LOGGER.debug("Options:") + # _LOGGER.debug(self.options) + + # async def async_end(self): + # """Finalize the ConfigEntry creation.""" + # _LOGGER.debug( + # "Recreating entry %s due to configuration change", + # self.config_entry.entry_id, + # ) + # self.hass.config_entries.async_update_entry( + # self.config_entry, data=self.options + # ) + # return self.async_create_entry(title=None, data=None) + + async def async_step_init( + self, user_input: dict[str, Any] | None = None + ) -> FlowResult: + """Manage the options.""" + _LOGGER.debug("OptionsFlow:AsyncStepInit: got triggered") + _LOGGER.debug(self.config_entry) + _LOGGER.debug("entry_id: %s", self.config_entry.entry_id) + + if user_input is not None: + _LOGGER.debug("Userinput found:") + _LOGGER.debug(user_input) + if "timeout" in self.config_entry.data: + _LOGGER.debug( + "timeout found, adding %s", self.config_entry.data["timeout"] + ) + # user_input["timeout"] = self.config_entry.data["timeout"] + # user_input.name = self.config_entry.data["name"] + _LOGGER.debug("config entry data:") + _LOGGER.debug(self.config_entry.data) # this is the old config + user_input["name"] = self.config_entry.data["name"] + _LOGGER.debug("modified Userinput:") + _LOGGER.debug(user_input) # this is the new config + self.hass.config_entries.async_update_entry( + self.config_entry, data=user_input, options=self.config_entry.options + ) + return self.async_create_entry(title="", data=user_input) + + all_entities = [] + for domain in ( + "sensor", + "binary_sensor", + "timer", + "input_boolean", + "media_player", + ): + all_entities += self.hass.states.async_entity_ids(domain) + _LOGGER.debug("all entities: %s", all_entities) + + return self.async_show_form( + step_id="init", + data_schema=vol.Schema( + { + vol.Required( + CONF_TIMEOUT, + default=self.config_entry.data["timeout"], + ): cv.positive_int, + vol.Required( + CONF_ENTITIES_TOGGLE, + default=self.config_entry.data["entities_toggle"], + ): cv.multi_select(sorted(all_entities)), + vol.Optional( + CONF_ENTITIES_KEEP, + default=self.config_entry.data["entities_keep"], + ): cv.multi_select(sorted(all_entities)), + vol.Optional( + CONF_ACTIVE_STATES, + default=self.config_entry.data["active_states"], + ): cv.string, + } + ), + ) + + class RoomOccupancyConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a config flow for Room Occupancy.""" VERSION = 1 + @staticmethod + # @callback + def async_get_options_flow( + config_entry: ConfigEntry, + ) -> OptionsFlow: + """Create the options flow.""" + return OptionsFlowHandler(config_entry) + async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: diff --git a/custom_components/room_occupancy/manifest.json b/custom_components/room_occupancy/manifest.json index 0bc8f3c..9fda5e1 100644 --- a/custom_components/room_occupancy/manifest.json +++ b/custom_components/room_occupancy/manifest.json @@ -7,7 +7,7 @@ "documentation": "https://www.home-assistant.io/integrations/room_occupancy", "homekit": {}, "iot_class": "calculated", - "version": "1.0.0", + "version": "2.0.0", "requirements": [], "ssdp": [], "zeroconf": [] diff --git a/custom_components/room_occupancy/options_flow.py b/custom_components/room_occupancy/options_flow.py new file mode 100644 index 0000000..81b8e9a --- /dev/null +++ b/custom_components/room_occupancy/options_flow.py @@ -0,0 +1,38 @@ +from homeassistant import config_entries +from .const import ( + CONF_ACTIVE_STATES, + CONF_ENTITIES_KEEP, + CONF_ENTITIES_TOGGLE, + CONF_TIMEOUT, + DOMAIN, +) +import voluptuous as vol + + +class RoomOccupancyBinarySensorOptionsFlow(config_entries.OptionsFlow): + """Options flow for RoomOccupancyBinarySensor.""" + + def __init__(self, config_entry): + """Initialize options flow.""" + self.config_entry = config_entry + + async def async_step_init(self, user_input=None): + """Manage the options.""" + if user_input is not None: + return self.async_create_entry(title="", data=user_input) + + options = { + vol.Optional( + CONF_TIMEOUT, + default=self.config_entry.options.get(CONF_TIMEOUT), + ): vol.All(vol.Coerce(int), vol.Range(min=1)) + } + + return self.async_show_form(step_id="init", data_schema=vol.Schema(options)) + + async def async_step_user(self, user_input=None): + """Handle a flow initialized by the user.""" + if user_input is not None: + return self.async_create_entry(title="", data=user_input) + + return await self.async_step_init() diff --git a/custom_components/room_occupancy/strings.json b/custom_components/room_occupancy/strings.json index c48871f..7a012b0 100644 --- a/custom_components/room_occupancy/strings.json +++ b/custom_components/room_occupancy/strings.json @@ -17,5 +17,24 @@ "abort": { "already_configured": "This sensor already exists!" } + }, + "options": { + "step": { + "init": { + "data": { + "name": "Name of the sensor", + "timeout": "Timeout in seconds", + "entities_toggle": "these entities can toggle the sensor to on", + "entities_keep": "these entitites can keep the sensor on", + "active_states": "states that are considered as true" + } + } + }, + "error": { + "already_configured": "This sensor already exists!" + }, + "abort": { + "already_configured": "This sensor already exists!" + } } } diff --git a/custom_components/room_occupancy/translations/en.json b/custom_components/room_occupancy/translations/en.json index c1504b7..cca6494 100644 --- a/custom_components/room_occupancy/translations/en.json +++ b/custom_components/room_occupancy/translations/en.json @@ -1,21 +1,40 @@ { "config": { - "abort": { - "already_configured": "This sensor already exists!" - }, - "error": { - "already_configured": "This sensor already exists!" - }, - "step": { - "user": { - "data": { - "active_states": "states that are considered as true", - "entities_keep": "these entitites can keep the sensor on", - "entities_toggle": "these entities can toggle the sensor to on", - "name": "Name of the sensor", - "timeout": "Timeout in seconds" - } - } + "step": { + "user": { + "data": { + "name": "Name of the sensor", + "timeout": "Timeout in seconds", + "entities_toggle": "these entities can toggle the sensor to on", + "entities_keep": "these entitites can keep the sensor on", + "active_states": "states that are considered as true" + } } + }, + "error": { + "already_configured": "This sensor already exists!" + }, + "abort": { + "already_configured": "This sensor already exists!" + } + }, + "options": { + "step": { + "init": { + "data": { + "name": "Name of the sensor", + "timeout": "Timeout in seconds", + "entities_toggle": "these entities can toggle the sensor to on", + "entities_keep": "these entitites can keep the sensor on", + "active_states": "states that are considered as true" + } + } + }, + "error": { + "already_configured": "This sensor already exists!" + }, + "abort": { + "already_configured": "This sensor already exists!" + } } -} \ No newline at end of file + }