Skip to content

Commit

Permalink
Merge pull request #84 from tykeal/unique_id
Browse files Browse the repository at this point in the history
unique id
  • Loading branch information
tykeal authored Mar 23, 2022
2 parents d11baf7 + 44079b8 commit 464b370
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 28 deletions.
39 changes: 35 additions & 4 deletions custom_components/rental_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from .const import CONF_CHECKIN
from .const import CONF_CHECKOUT
from .const import CONF_CODE_GENERATION
from .const import CONF_CREATION_DATETIME
from .const import CONF_DAYS
from .const import CONF_EVENT_PREFIX
from .const import CONF_IGNORE_NON_RESERVED
Expand All @@ -43,6 +44,7 @@
from .const import DOMAIN
from .const import PLATFORMS
from .const import REQUEST_TIMEOUT
from .util import gen_uuid

_LOGGER = logging.getLogger(__name__)

Expand All @@ -67,7 +69,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# hass.data[DOMAIN][entry.entry_id] = MyApi(...)
if DOMAIN not in hass.data:
hass.data[DOMAIN] = {}
hass.data[DOMAIN][config.get(CONF_NAME)] = ICalEvents(hass=hass, config=config)
hass.data[DOMAIN][entry.unique_id] = ICalEvents(hass=hass, config=config)

for component in PLATFORMS:
hass.async_create_task(
Expand All @@ -92,11 +94,33 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
)
)
if unload_ok:
hass.data[DOMAIN].pop(config.get(CONF_NAME))
hass.data[DOMAIN].pop(entry.unique_id)

return unload_ok


async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Migrate configuration."""

version = config_entry.version

# 1 -> 2: Migrate keys
if version == 1:
_LOGGER.debug("Migrating from version %s", version)
data = config_entry.data.copy()

data[CONF_CREATION_DATETIME] = str(dt.now())
hass.config_entries.async_update_entry(
entry=config_entry,
unique_id=gen_uuid(data[CONF_CREATION_DATETIME]),
data=data,
)
config_entry.version = 2
_LOGGER.debug("Migration of to version %s complete", config_entry.version)

return True


async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Update listener."""
# No need to update if the options match the data
Expand All @@ -105,15 +129,21 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:

new_data = entry.options.copy()

old_data = hass.data[DOMAIN][entry.unique_id]

# do not update the creation datetime if it already exists (which it should)
new_data[CONF_CREATION_DATETIME] = old_data.created

hass.config_entries.async_update_entry(
entry=entry,
unique_id=entry.options[CONF_NAME],
unique_id=entry.unique_id,
data=new_data,
title=new_data[CONF_NAME],
options={},
)

# Update the calendar config
hass.data[DOMAIN][entry.data.get(CONF_NAME)].update_config(new_data)
hass.data[DOMAIN][entry.unique_id].update_config(new_data)


class ICalEvents:
Expand Down Expand Up @@ -151,6 +181,7 @@ def __init__(self, hass, config):
self.code_generator = config.get(CONF_CODE_GENERATION, DEFAULT_CODE_GENERATION)
self.event = None
self.all_day = False
self.created = config.get(CONF_CREATION_DATETIME, str(dt.now()))

async def async_get_events(
self, hass, start_date, end_date
Expand Down
2 changes: 1 addition & 1 deletion custom_components/rental_control/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):

entity_id = generate_entity_id(ENTITY_ID_FORMAT, DOMAIN + " " + name, hass=hass)

rental_control_events = hass.data[DOMAIN][name]
rental_control_events = hass.data[DOMAIN][config_entry.unique_id]

calendar = ICalCalendarEventDevice(hass, name, entity_id, rental_control_events)

Expand Down
38 changes: 16 additions & 22 deletions custom_components/rental_control/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Config flow for Rental Control integration."""
import asyncio
import logging
import re
from typing import Any
Expand All @@ -25,6 +24,7 @@
from .const import CONF_CHECKIN
from .const import CONF_CHECKOUT
from .const import CONF_CODE_GENERATION
from .const import CONF_CREATION_DATETIME
from .const import CONF_DAYS
from .const import CONF_EVENT_PREFIX
from .const import CONF_IGNORE_NON_RESERVED
Expand All @@ -44,6 +44,7 @@
from .const import DOMAIN
from .const import LOCK_MANAGER
from .const import REQUEST_TIMEOUT
from .util import gen_uuid

_LOGGER = logging.getLogger(__name__)

Expand All @@ -55,7 +56,7 @@
class RentalControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle the config flow for Rental Control."""

VERSION = 1
VERSION = 2

DEFAULTS = {
CONF_CHECKIN: DEFAULT_CHECKIN,
Expand All @@ -69,11 +70,14 @@ class RentalControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
CONF_VERIFY_SSL: True,
}

async def _get_unique_name_error(self, user_input) -> Dict[str, str]:
"""Check if name is unique, returning dictionary if so."""
# Validate that Rental control is unique
def __init__(self):
"""Setup the RentalControlFlowHandler."""
self.created = str(dt.now())

async def _get_unique_id(self, user_input) -> Dict[str, str]:
"""Generate the unique_id."""
existing_entry = await self.async_set_unique_id(
user_input[CONF_NAME], raise_on_progress=True
gen_uuid(self.created), raise_on_progress=True
)
if existing_entry:
return {CONF_NAME: "same_name"}
Expand Down Expand Up @@ -103,16 +107,6 @@ def __init__(self, config_entry: config_entries.ConfigEntry):
"""Initialize Options Flow."""
self.config_entry = config_entry

def _get_unique_name_error(self, user_input) -> Dict[str, str]:
"""Check if name is unique, returning dictionary if so."""
# If name has changed, make sure new name isn't already being used
# otherwise show an error
if self.config_entry.unique_id != user_input[CONF_NAME]:
for entry in self.hass.config_entries.async_entries(DOMAIN):
if entry.unique_id == user_input[CONF_NAME]:
return {CONF_NAME: "same_name"}
return {}

async def async_step_init(
self,
user_input: Dict[str, Any] = None,
Expand Down Expand Up @@ -273,12 +267,9 @@ async def _start_config_flow(
description_placeholders = {}

if user_input is not None:
# Regular flow has an async function, options flow has a sync function
# so we need to handle them conditionally
if asyncio.iscoroutinefunction(cls._get_unique_name_error):
errors.update(await cls._get_unique_name_error(user_input))
else:
errors.update(cls._get_unique_name_error(user_input))
# Regular flow has an async function
if hasattr(cls, "_get_unique_id"):
errors.update(await cls._get_unique_id(user_input))

# Validate user input
try:
Expand Down Expand Up @@ -331,6 +322,9 @@ async def _start_config_flow(
ident=user_input[CONF_CODE_GENERATION], to_type=True
)

if hasattr(cls, "created"):
user_input[CONF_CREATION_DATETIME] = cls.created

return cls.async_create_entry(title=title, data=user_input)

return _show_config_form(
Expand Down
1 change: 1 addition & 0 deletions custom_components/rental_control/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
CONF_REFRESH_FREQUENCY = "refresh_frequency"
CONF_START_SLOT = "start_slot"
CONF_TIMEZONE = "timezone"
CONF_CREATION_DATETIME = "creation_datetime"

# Defaults
DEFAULT_CHECKIN = "16:00"
Expand Down
2 changes: 1 addition & 1 deletion custom_components/rental_control/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
name = config.get(CONF_NAME)
max_events = config.get(CONF_MAX_EVENTS)

rental_control_events = hass.data[DOMAIN][name]
rental_control_events = hass.data[DOMAIN][config_entry.unique_id]
await rental_control_events.update()
if rental_control_events.calendar is None:
_LOGGER.error("Unable to fetch iCal")
Expand Down
26 changes: 26 additions & 0 deletions custom_components/rental_control/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-License-Identifier: Apache-2.0
##############################################################################
# COPYRIGHT 2022 Andrew Grimberg
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache 2.0 License
# which accompanies this distribution, and is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# Contributors:
# Andrew Grimberg - Initial implementation
##############################################################################
"""Rental Control utils."""
import hashlib
import logging
import uuid

from .const import NAME

_LOGGER = logging.getLogger(__name__)


def gen_uuid(created: str) -> str:
"""Generation a UUID from the NAME and creation time."""
m = hashlib.md5(f"{NAME} {created}".encode("utf-8"))
return str(uuid.UUID(m.hexdigest()))

0 comments on commit 464b370

Please sign in to comment.