Skip to content

Commit

Permalink
Merge pull request #278 from basbruss/end_time
Browse files Browse the repository at this point in the history
Fix end time listeners
  • Loading branch information
basbruss authored Aug 8, 2024
2 parents 02f4b3e + ed98386 commit 01f7475
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 38 deletions.
20 changes: 2 additions & 18 deletions custom_components/adaptive_cover/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.event import (
async_track_point_in_time,
async_track_state_change_event,
)

from .const import (
CONF_END_ENTITY,
CONF_END_TIME,
CONF_ENTITIES,
CONF_PRESENCE_ENTITY,
CONF_RETURN_SUNSET,
CONF_TEMP_ENTITY,
CONF_WEATHER_ENTITY,
DOMAIN,
)
from .coordinator import AdaptiveDataUpdateCoordinator
from .helpers import get_datetime_from_str, get_safe_state

PLATFORMS = [Platform.SENSOR, Platform.SWITCH, Platform.BINARY_SENSOR, Platform.BUTTON]
CONF_SUN = ["sun.sun"]
Expand All @@ -42,22 +38,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data.setdefault(DOMAIN, {})

coordinator = AdaptiveDataUpdateCoordinator(hass)
end_time = None
_temp_entity = entry.options.get(CONF_TEMP_ENTITY)
_presence_entity = entry.options.get(CONF_PRESENCE_ENTITY)
_weather_entity = entry.options.get(CONF_WEATHER_ENTITY)
_cover_entities = entry.options.get(CONF_ENTITIES, [])
_end_time_entity = entry.options.get(CONF_END_ENTITY)
_entities = ["sun.sun"]
for entity in [_temp_entity, _presence_entity, _weather_entity]:
for entity in [_temp_entity, _presence_entity, _weather_entity, _end_time_entity]:
if entity is not None:
_entities.append(entity)
_track_end_time = entry.options.get(CONF_RETURN_SUNSET)
_end_time = entry.options.get(CONF_END_TIME)
_end_time_entity = entry.options.get(CONF_END_ENTITY)
if _end_time is not None:
end_time = get_datetime_from_str(_end_time)
if _end_time_entity is not None:
end_time = get_datetime_from_str(get_safe_state(hass, _end_time_entity))

entry.async_on_unload(
async_track_state_change_event(
Expand All @@ -75,11 +64,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
)

if _track_end_time and end_time is not None:
entry.async_on_unload(
async_track_point_in_time(hass, coordinator.async_timed_refresh, end_time)
)

await coordinator.async_config_entry_first_refresh()
hass.data[DOMAIN][entry.entry_id] = coordinator

Expand Down
85 changes: 65 additions & 20 deletions custom_components/adaptive_cover/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
SERVICE_SET_COVER_POSITION,
SERVICE_SET_COVER_TILT_POSITION,
)
from homeassistant.core import Event, EventStateChangedData, HomeAssistant, State
from homeassistant.core import (
Event,
EventStateChangedData,
HomeAssistant,
State,
callback,
)
from homeassistant.helpers.event import async_track_point_in_time
from homeassistant.helpers.template import state_attr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

Expand All @@ -41,6 +48,8 @@
CONF_DELTA_TIME,
CONF_DISTANCE,
CONF_ENABLE_BLIND_SPOT,
CONF_ENABLE_MAX_POSITION,
CONF_ENABLE_MIN_POSITION,
CONF_END_ENTITY,
CONF_END_TIME,
CONF_ENTITIES,
Expand All @@ -65,8 +74,11 @@
CONF_MAX_ELEVATION,
CONF_MAX_POSITION,
CONF_MIN_ELEVATION,
CONF_MIN_POSITION,
CONF_OUTSIDE_THRESHOLD,
CONF_OUTSIDETEMP_ENTITY,
CONF_PRESENCE_ENTITY,
CONF_RETURN_SUNSET,
CONF_START_ENTITY,
CONF_START_TIME,
CONF_SUNRISE_OFFSET,
Expand All @@ -81,12 +93,8 @@
CONF_TRANSPARENT_BLIND,
CONF_WEATHER_ENTITY,
CONF_WEATHER_STATE,
CONF_MIN_POSITION,
CONF_OUTSIDE_THRESHOLD,
DOMAIN,
LOGGER,
CONF_ENABLE_MAX_POSITION,
CONF_ENABLE_MIN_POSITION,
)
from .helpers import get_datetime_from_str, get_last_updated, get_safe_state

Expand Down Expand Up @@ -122,13 +130,14 @@ def __init__(self, hass: HomeAssistant) -> None: # noqa: D107
self._switch_mode = True if self._climate_mode else False
self._inverse_state = self.config_entry.options.get(CONF_INVERSE_STATE, False)
self._use_interpolation = self.config_entry.options.get(CONF_INTERP, False)
self._track_end_time = self.config_entry.options.get(CONF_RETURN_SUNSET)
self._temp_toggle = None
self._control_toggle = None
self._manual_toggle = None
self._lux_toggle = None
self._irradiance_toggle = None
self._start_time = None
self._end_time = None
# self._end_time = None
self.manual_reset = self.config_entry.options.get(
CONF_MANUAL_OVERRIDE_RESET, False
)
Expand All @@ -148,6 +157,8 @@ def __init__(self, hass: HomeAssistant) -> None: # noqa: D107
self.ignore_intermediate_states = self.config_entry.options.get(
CONF_MANUAL_IGNORE_INTERMEDIATE, False
)
self._update_listener = None
self._scheduled_time = dt.datetime.now()

async def async_config_entry_first_refresh(self) -> None:
"""Config entry first refresh."""
Expand Down Expand Up @@ -216,7 +227,31 @@ def process_entity_state_change(self):
_LOGGER.debug("Position %s reached for %s", position, entity_id)
_LOGGER.debug("Wait for target: %s", self.wait_for_target)

@callback
def _async_cancel_update_listener(self) -> None:
"""Cancel the scheduled update."""
if self._update_listener:
self._update_listener()
self._update_listener = None

async def async_timed_end_time(self) -> None:
"""Control state at end time."""
_LOGGER.debug("Scheduling end time update at %s", self._end_time)
self._async_cancel_update_listener()
_LOGGER.debug(
"End time: %s, Track end time: %s, Scheduled time: %s, Condition: %s",
self._end_time,
self._track_end_time,
self._scheduled_time,
self._end_time > self._scheduled_time,
)
self._update_listener = async_track_point_in_time(
self.hass, self.async_timed_refresh, self._end_time
)
self._scheduled_time = self._end_time

async def _async_update_data(self) -> AdaptiveCoverData:
_LOGGER.debug("Updating data")
options = self.config_entry.options
self._update_options(options)

Expand All @@ -238,6 +273,13 @@ async def _async_update_data(self) -> AdaptiveCoverData:

await self.manager.reset_if_needed()

if (
self._end_time
and self._track_end_time
and self._end_time > self._scheduled_time
):
await self.async_timed_end_time()

# Handle types of changes
if self.state_change:
await self.async_handle_state_change(state, options)
Expand Down Expand Up @@ -331,9 +373,9 @@ async def async_handle_timed_refresh(self, options):
async def async_handle_call_service(self, entity, state: int, options):
"""Handle call service."""
if (
self.check_position_delta(entity, state, options)
self.check_adaptive_time
and self.check_position_delta(entity, state, options)
and self.check_time_delta(entity)
and self.check_adaptive_time
and not self.manager.is_cover_manual(entity)
):
await self.async_set_position(entity, state)
Expand Down Expand Up @@ -447,28 +489,31 @@ def after_start_time(self):
return True

@property
def before_end_time(self):
"""Check if time is before end time."""
now = dt.datetime.now()
def _end_time(self) -> dt.datetime | None:
"""Get end time."""
time = None
if self.end_time_entity is not None:
time = get_datetime_from_str(
get_safe_state(self.hass, self.end_time_entity)
)
_LOGGER.debug(
"End time: %s, now: %s, now < time: %s", time, now, now < time
)
self._end_time = time
return now < time
if self.end_time is not None:
elif self.end_time is not None:
time = get_datetime_from_str(self.end_time)
if time.time() == dt.time(0, 0):
time = time + dt.timedelta(days=1)
return time

@property
def before_end_time(self):
"""Check if time is before end time."""
if self._end_time is not None:
now = dt.datetime.now()
_LOGGER.debug(
"End time: %s, now: %s, now < time: %s", time, now, now < time
"End time: %s, now: %s, now < time: %s",
self._end_time,
now,
now < self._end_time,
)
self._end_time = time
return now < time
return now < self._end_time
return True

def _get_current_position(self, entity) -> int | None:
Expand Down

0 comments on commit 01f7475

Please sign in to comment.