Skip to content

Commit

Permalink
Handling expired bookings
Browse files Browse the repository at this point in the history
Removed work around  booking expiration date as a booking becomes unavailable become this time approaches.

Instead the booking will be remove when `success` is returned as false.

Also added in logic to prevent errors from happening if processing an expired booking.
  • Loading branch information
jampez77 committed Oct 3, 2024
1 parent 4a5f004 commit 924bb82
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 96 deletions.
58 changes: 33 additions & 25 deletions custom_components/jet2/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ async def async_setup_entry(
sensors = [
Jet2BinarySensor(coordinator, name, description)
for description in SENSOR_TYPES
if description.key in coordinator.data
]
async_add_entities(sensors, update_before_add=True)

Expand All @@ -73,36 +74,43 @@ def __init__(
) -> None:
"""Initialize."""
super().__init__(coordinator)
self.data = coordinator.data.get("data")
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{name}")},
manufacturer="Jet2",
model=self.data.get("holidayType"),
name=name.upper(),
configuration_url="https://github.com/jampez77/Jet2/",
)
self._attr_unique_id = f"{DOMAIN}-{name}-{description.key}-binary".lower()
self.entity_id = f"binary_sensor.{DOMAIN}_{name}_{description.key}".lower()
self.attrs: dict[str, Any] = {}
self.entity_description = description
self._attr_is_on = None
self.success = bool(coordinator.data.get("success"))

if self.success:
self.data = coordinator.data.get("data")
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{name}")},
manufacturer="Jet2",
model=self.data.get("holidayType"),
name=name.upper(),
configuration_url="https://github.com/jampez77/Jet2/",
)
self._attr_unique_id = f"{DOMAIN}-{name}-{description.key}-binary".lower()
self.entity_id = f"binary_sensor.{DOMAIN}_{name}_{description.key}".lower()
self.attrs: dict[str, Any] = {}
self.entity_description = description
self._attr_is_on = None

def update_from_coordinator(self):
"""Update sensor state and attributes from coordinator data."""
value: dict | str | bool = self.data.get(self.entity_description.key, None)
if self.success:
value: dict | str | bool = self.data.get(self.entity_description.key, None)

if isinstance(value, dict) and self.entity_description.key == "checkInStatus":
value = value["checkInAllowed"]
if (
isinstance(value, dict)
and self.entity_description.key == "checkInStatus"
):
value = value["checkInAllowed"]

self._attr_is_on = bool(value)
self._attr_is_on = bool(value)

if isinstance(value, (dict, list)):
for index, attribute in enumerate(value):
if isinstance(attribute, (dict, list)):
for attr in attribute:
self.attrs[str(attr) + str(index)] = attribute[attr]
else:
self.attrs[attribute] = value[attribute]
if isinstance(value, (dict, list)):
for index, attribute in enumerate(value):
if isinstance(attribute, (dict, list)):
for attr in attribute:
self.attrs[str(attr) + str(index)] = attribute[attr]
else:
self.attrs[attribute] = value[attribute]

@callback
def _handle_coordinator_update(self) -> None:
Expand All @@ -124,7 +132,7 @@ async def async_remove(self) -> None:
@property
def available(self) -> bool:
"""Return True if entity is available."""
return bool(self.coordinator.data.get("success"))
return self.success

@property
def is_on(self) -> bool | None:
Expand Down
61 changes: 33 additions & 28 deletions custom_components/jet2/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@
key="holiday",
name="Holiday",
),
SensorEntityDescription(
key="expiryDate",
name="Booking Expiration",
),
]


Expand All @@ -64,21 +60,24 @@ async def async_setup_entry(

await coordinator.async_refresh()

name = entry.data[CONF_BOOKING_REFERENCE]
success = bool(coordinator.data.get("success"))

calendars = entry.data[CONF_CALENDARS]
if success:
name = entry.data[CONF_BOOKING_REFERENCE]

sensors = [Jet2CalendarSensor(coordinator, name)]
calendars = entry.data[CONF_CALENDARS]

for calendar in calendars:
if calendar != "None":
for sensor in sensors:
events = sensor.get_events(datetime.today(), hass)
for event in events:
await add_to_calendar(hass, calendar, event, entry)
sensors = [Jet2CalendarSensor(coordinator, name)]

if "None" in calendars:
async_add_entities(sensors, update_before_add=True)
for calendar in calendars:
if calendar != "None":
for sensor in sensors:
events = sensor.get_events(datetime.today(), hass)
for event in events:
await add_to_calendar(hass, calendar, event, entry)

if "None" in calendars:
async_add_entities(sensors, update_before_add=True)


async def create_event(hass: HomeAssistant, service_data):
Expand Down Expand Up @@ -195,27 +194,33 @@ def __init__(
) -> None:
"""Initialize."""
super().__init__(coordinator)
self.data = coordinator.data.get("data")
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{name}")},
manufacturer="Jet2",
model=self.data.get("holidayType"),
name=name.upper(),
configuration_url="https://github.com/jampez77/Jet2/",
)
self._attr_unique_id = f"{DOMAIN}-{name}-calendar".lower()
self._attr_name = f"{DOMAIN.title()} - {name.upper()}"

self.success = bool(coordinator.data.get("success"))

if self.success:
self.data = coordinator.data.get("data")
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{name}")},
manufacturer="Jet2",
model=self.data.get("holidayType"),
name=name.upper(),
configuration_url="https://github.com/jampez77/Jet2/",
)
self._attr_unique_id = f"{DOMAIN}-{name}-calendar".lower()
self._attr_name = f"{DOMAIN.title()} - {name.upper()}"

@property
def available(self) -> bool:
"""Return True if entity is available."""
return bool(self.coordinator.data.get("success"))
return self.success

@property
def event(self) -> CalendarEvent | None:
"""Return the next upcoming event."""
events = self.get_events(datetime.today(), self.hass)
return sorted(events, key=lambda c: c.start)[0]
if self.success:
events = self.get_events(datetime.today(), self.hass)
return sorted(events, key=lambda c: c.start)[0]
return None

def get_events(
self, start_date: datetime, hass: HomeAssistant
Expand Down
68 changes: 36 additions & 32 deletions custom_components/jet2/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,40 +52,44 @@ def __init__(
"""Initialize."""
super().__init__(coordinator)
Camera.__init__(self) # Initialize the Camera base class
self.data = coordinator.data.get("data")

if "hotel" in self.data:
self._name = self.data["hotel"]["name"]
elif "resort" in self.data:
self._name = self.data["resort"]
elif "area" in self.data:
self._name = self.data["area"]
elif "region" in self.data:
self._name = self.data["region"]
else:
self._name = "Accommodation Images"

self.entity_description = description
self._current_index = 0
self._image_urls = self.data["accommodationImages"]

# Setup unique ID and entity ID
self._attr_unique_id = f"{DOMAIN}-{name}-{description.key}-camera".lower()
self.entity_id = f"camera.{DOMAIN}_{name}_{description.key}".lower()

# Set up device info
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{name}")},
manufacturer="Jet2",
model=self.data.get("holidayType"),
name=name.upper(),
configuration_url="https://github.com/jampez77/Jet2/",
)

self.success = bool(coordinator.data.get("success"))
self._name = "Accommodation Images"
self._image_urls = None

if self.success:
self.data = coordinator.data.get("data")

if "hotel" in self.data:
self._name = self.data["hotel"]["name"]
elif "resort" in self.data:
self._name = self.data["resort"]
elif "area" in self.data:
self._name = self.data["area"]
elif "region" in self.data:
self._name = self.data["region"]

self.entity_description = description
self._current_index = 0
self._image_urls = self.data["accommodationImages"]

# Setup unique ID and entity ID
self._attr_unique_id = f"{DOMAIN}-{name}-{description.key}-camera".lower()
self.entity_id = f"camera.{DOMAIN}_{name}_{description.key}".lower()

# Set up device info
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{name}")},
manufacturer="Jet2",
model=self.data.get("holidayType"),
name=name.upper(),
configuration_url="https://github.com/jampez77/Jet2/",
)

@property
def available(self) -> bool:
"""Return True if entity is available."""
return bool(self.coordinator.data.get("success") and len(self._image_urls) > 0)
return bool(self.success and len(self._image_urls) > 0)

@property
def name(self) -> str:
Expand All @@ -95,11 +99,11 @@ def name(self) -> str:
@property
def is_streaming(self) -> bool:
"""Return True if the camera is streaming."""
return bool(len(self._image_urls) > 0)
return bool(self.success and len(self._image_urls) > 0)

def camera_image(self, width: int = 0, height: int = 0) -> bytes:
"""Return the image to serve for the camera entity."""
if not self._image_urls:
if not self.success or self._image_urls is None:
return None

# Get the current image URL
Expand Down
2 changes: 1 addition & 1 deletion custom_components/jet2/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self, hass: HomeAssistant, session, data: dict) -> None:
# Name of the data. For logging purposes.
name="Jet2",
# Polling interval. Will only be polled if there are subscribers.
update_interval=timedelta(seconds=300),
update_interval=timedelta(minutes=5),
)
self.session = session
self.booking_reference = data[CONF_BOOKING_REFERENCE]
Expand Down
2 changes: 1 addition & 1 deletion custom_components/jet2/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"issue_tracker": "https://github.com/jampez77/Jet2/issues",
"requirements": [],
"ssdp": [],
"version": "2024.9.10",
"version": "2024.9.11",
"zeroconf": []
}
25 changes: 16 additions & 9 deletions custom_components/jet2/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def hasBookingExpired(hass: HomeAssistant, expiry_date_raw: str) -> bool:

async def removeBooking(hass: HomeAssistant, booking_reference: str):
"""Remove expired booking."""

entry = next(
(
entry
Expand Down Expand Up @@ -156,16 +157,21 @@ async def async_setup_entry(

await coordinator.async_refresh()

success = bool(coordinator.data.get("success"))
name = entry.data[CONF_BOOKING_REFERENCE]

if hasBookingExpired(hass, coordinator.data.get("data")["expiryDate"]):
await removeBooking(hass, name)
if success:
if hasBookingExpired(hass, coordinator.data.get("data")["expiryDate"]):
await removeBooking(hass, name)
else:
sensors = [
Jet2Sensor(coordinator, name, description)
for description in SENSOR_TYPES
if description.key in coordinator.data
]
async_add_entities(sensors, update_before_add=True)
else:
sensors = [
Jet2Sensor(coordinator, name, description)
for description in SENSOR_TYPES
]
async_add_entities(sensors, update_before_add=True)
await removeBooking(hass, name)


class Jet2Sensor(CoordinatorEntity[Jet2Coordinator], SensorEntity):
Expand All @@ -179,6 +185,7 @@ def __init__(
) -> None:
"""Initialize."""
super().__init__(coordinator)
self.success = bool(coordinator.data.get("success"))
self.data = coordinator.data.get("data")
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{name}")},
Expand All @@ -197,7 +204,7 @@ def __init__(
def update_from_coordinator(self):
"""Update sensor state and attributes from coordinator data."""

if hasBookingExpired(self.hass, self.data.get("expiryDate")):
if not self.success:
self.hass.async_add_job(removeBooking(self.hass, self.name))
else:
value = self.data.get(self.entity_description.key)
Expand Down Expand Up @@ -282,7 +289,7 @@ async def async_remove(self) -> None:
@property
def available(self) -> bool:
"""Return True if entity is available."""
return bool(self.coordinator.data.get("success"))
return self.success

@property
def native_value(self) -> str | date | None:
Expand Down

0 comments on commit 924bb82

Please sign in to comment.