diff --git a/custom_components/rental_control/__init__.py b/custom_components/rental_control/__init__.py index 66e637d..3e65434 100644 --- a/custom_components/rental_control/__init__.py +++ b/custom_components/rental_control/__init__.py @@ -50,6 +50,7 @@ from .const import CONF_CHECKIN from .const import CONF_CHECKOUT from .const import CONF_CODE_GENERATION +from .const import CONF_SHOULD_UPDATE_CODE from .const import CONF_CODE_LENGTH from .const import CONF_CREATION_DATETIME from .const import CONF_DAYS @@ -64,6 +65,7 @@ from .const import CONF_TIMEZONE from .const import COORDINATOR from .const import DEFAULT_CODE_GENERATION +from .const import DEFAULT_SHOULD_UPDATE_CODE from .const import DEFAULT_CODE_LENGTH from .const import DEFAULT_GENERATE from .const import DEFAULT_REFRESH_FREQUENCY @@ -402,6 +404,9 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry): self.code_generator: str = config.get( CONF_CODE_GENERATION, DEFAULT_CODE_GENERATION ) + self.should_update_code: bool = config.get( + CONF_SHOULD_UPDATE_CODE, DEFAULT_SHOULD_UPDATE_CODE + ) self.code_length: int = config.get(CONF_CODE_LENGTH, DEFAULT_CODE_LENGTH) self.event: CalendarEvent | None = None self.created: str = config.get(CONF_CREATION_DATETIME, str(dt.now())) @@ -555,6 +560,9 @@ def update_config(self, config) -> None: self.max_events = config.get(CONF_MAX_EVENTS) self.days = config.get(CONF_DAYS) self.code_generator = config.get(CONF_CODE_GENERATION, DEFAULT_CODE_GENERATION) + self.should_update_code = config.get( + CONF_SHOULD_UPDATE_CODE, DEFAULT_SHOULD_UPDATE_CODE + ) self.code_length = config.get(CONF_CODE_LENGTH, DEFAULT_CODE_LENGTH) self.ignore_non_reserved = config.get(CONF_IGNORE_NON_RESERVED) self.verify_ssl = config.get(CONF_VERIFY_SSL) diff --git a/custom_components/rental_control/config_flow.py b/custom_components/rental_control/config_flow.py index c2e3710..bdd3a87 100644 --- a/custom_components/rental_control/config_flow.py +++ b/custom_components/rental_control/config_flow.py @@ -28,6 +28,7 @@ from .const import CONF_CHECKIN from .const import CONF_CHECKOUT from .const import CONF_CODE_GENERATION +from .const import CONF_SHOULD_UPDATE_CODE from .const import CONF_CODE_LENGTH from .const import CONF_CREATION_DATETIME from .const import CONF_DAYS @@ -42,6 +43,7 @@ from .const import DEFAULT_CHECKIN from .const import DEFAULT_CHECKOUT from .const import DEFAULT_CODE_GENERATION +from .const import DEFAULT_SHOULD_UPDATE_CODE from .const import DEFAULT_CODE_LENGTH from .const import DEFAULT_DAYS from .const import DEFAULT_EVENT_PREFIX @@ -281,6 +283,12 @@ def _get_default(key: str, fallback_default: Any = None) -> Any | None: to_type=False, ), ): vol.In(_code_generators()), + vol.Optional( + CONF_SHOULD_UPDATE_CODE, + default=_get_default( + CONF_SHOULD_UPDATE_CODE, DEFAULT_SHOULD_UPDATE_CODE + ), + ): cv.boolean, vol.Optional( CONF_IGNORE_NON_RESERVED, default=_get_default(CONF_IGNORE_NON_RESERVED, True), diff --git a/custom_components/rental_control/const.py b/custom_components/rental_control/const.py index ba94ddb..606e191 100644 --- a/custom_components/rental_control/const.py +++ b/custom_components/rental_control/const.py @@ -45,6 +45,7 @@ CONF_CHECKIN = "checkin" CONF_CHECKOUT = "checkout" CONF_CODE_GENERATION = "code_generation" +CONF_SHOULD_UPDATE_CODE = "should_update_code" CONF_CODE_LENGTH = "code_length" CONF_DAYS = "days" CONF_EVENT_PREFIX = "event_prefix" @@ -62,6 +63,7 @@ DEFAULT_CHECKIN = "16:00" DEFAULT_CHECKOUT = "11:00" DEFAULT_CODE_GENERATION = "date_based" +DEFAULT_SHOULD_UPDATE_CODE = False DEFAULT_CODE_LENGTH = 4 DEFAULT_DAYS = 365 DEFAULT_EVENT_PREFIX = "" diff --git a/custom_components/rental_control/sensors/calsensor.py b/custom_components/rental_control/sensors/calsensor.py index a7f6486..5671969 100644 --- a/custom_components/rental_control/sensors/calsensor.py +++ b/custom_components/rental_control/sensors/calsensor.py @@ -16,6 +16,7 @@ from ..const import ICON from ..util import async_fire_set_code from ..util import async_fire_update_times +from ..util import async_fire_update_slot_code from ..util import gen_uuid from ..util import get_slot_name @@ -277,6 +278,19 @@ async def async_update(self): ) self._event_attributes["summary"] = event.summary + + # Three conditions for update: + # 1. I think we can assume that rental sites will not let a guest change the start date of their reservation if they have checked in already + # therefore, we should check the event.start to make sure it is after now + # 2. Either the start or end time need to have changed + # 3. We need to have toggled this on in the config + should_update_code = ( + event.start > datetime.now() + and self._event_attributes["start"] != event.start + or self._event_attributes["end"] != event.end + and self.coordinator.should_update_code + ) + self._event_attributes["start"] = event.start self._event_attributes["end"] = event.end self._event_attributes["location"] = event.location @@ -319,7 +333,9 @@ async def async_update(self): ): update_times = True - if override and override["slot_code"]: + if should_update_code: # This takes priority + slot_code = self._generate_door_code() + elif override and override["slot_code"]: slot_code = str(override["slot_code"]) else: slot_code = self._generate_door_code() @@ -361,6 +377,9 @@ async def async_update(self): if update_times: await async_fire_update_times(self.coordinator, self) + if should_update_code: + await async_fire_update_slot_code(self.coordinator, self) + else: # No reservations _LOGGER.debug( diff --git a/custom_components/rental_control/strings.json b/custom_components/rental_control/strings.json index 57534a1..7b0f080 100644 --- a/custom_components/rental_control/strings.json +++ b/custom_components/rental_control/strings.json @@ -17,6 +17,7 @@ "checkin": "Default Check-in time", "checkout": "Default Check-out time", "code_generation": "Door code generator", + "should_update_code": "Update code when start or end date change.", "code_length": "Door code length (>= 4 and an even number)", "days": "Maximum number of days into the future to fetch", "event_prefix": "Prefix for all events (useful if linking more than one rental)", @@ -51,6 +52,7 @@ "checkin": "Default Check-in time", "checkout": "Default Check-out time", "code_generation": "Door code generator", + "should_update_code": "Update code when start or end date change.", "code_length": "Door code length (>= 4 and an even number)", "days": "Maximum number of days into the future to fetch", "event_prefix": "Prefix for all events (useful if linking more than one rental)", diff --git a/custom_components/rental_control/translations/en.json b/custom_components/rental_control/translations/en.json index 57534a1..7b0f080 100644 --- a/custom_components/rental_control/translations/en.json +++ b/custom_components/rental_control/translations/en.json @@ -17,6 +17,7 @@ "checkin": "Default Check-in time", "checkout": "Default Check-out time", "code_generation": "Door code generator", + "should_update_code": "Update code when start or end date change.", "code_length": "Door code length (>= 4 and an even number)", "days": "Maximum number of days into the future to fetch", "event_prefix": "Prefix for all events (useful if linking more than one rental)", @@ -51,6 +52,7 @@ "checkin": "Default Check-in time", "checkout": "Default Check-out time", "code_generation": "Door code generator", + "should_update_code": "Update code when start or end date change.", "code_length": "Door code length (>= 4 and an even number)", "days": "Maximum number of days into the future to fetch", "event_prefix": "Prefix for all events (useful if linking more than one rental)", diff --git a/custom_components/rental_control/util.py b/custom_components/rental_control/util.py index 4d2a08d..9f7ae4b 100644 --- a/custom_components/rental_control/util.py +++ b/custom_components/rental_control/util.py @@ -228,6 +228,28 @@ async def async_fire_set_code(coordinator, event, slot: int) -> None: await asyncio.gather(*coro) +async def async_fire_update_slot_code(coordinator, event) -> None: + """Update the code for the slot""" + + lockname: str = coordinator.lockname + coro: List[Coroutine] = [] + slot_name: str = event.extra_state_attributes["slot_name"] + slot = coordinator.event_overrides.get_slot_key_by_name(slot_name) + + if not slot or not lockname: + return + + coro = add_call( + coordinator.hass, + coro, + INPUT_TEXT, + "set_value", + f"input_text.{lockname}_pin_{slot}", + {"value": event.extra_state_attributes["slot_code"]}, + ) + + # Update the slot details + await asyncio.gather(*coro) async def async_fire_update_times(coordinator, event) -> None: """Update times on slot."""