Skip to content

Commit

Permalink
Merge pull request #105 from basbruss/adaptive-cover-state-process-up…
Browse files Browse the repository at this point in the history
…date-branch

adaptive-cover-state-process-update-branch
  • Loading branch information
basbruss authored Apr 15, 2024
2 parents f0e1e02 + 832a52b commit 3be8901
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 18 deletions.
9 changes: 8 additions & 1 deletion custom_components/adaptive_cover/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
for entity in [_temp_entity, _presence_entity, _weather_entity]:
if entity is not None:
_entities.append(entity)
_entities += _cover_entities

entry.async_on_unload(
async_track_state_change(
Expand All @@ -56,6 +55,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
)

entry.async_on_unload(
async_track_state_change(
hass,
_cover_entities,
coordinator.async_check_cover_state_change,
)
)

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

Expand Down
2 changes: 1 addition & 1 deletion custom_components/adaptive_cover/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def async_setup_entry(
BinarySensorDeviceClass.RUNNING,
coordinator,
)
async_add_entities([binary_sensor])
async_add_entities([binary_sensor, manual_override])


class AdaptiveCoverBinarySensor(
Expand Down
6 changes: 5 additions & 1 deletion custom_components/adaptive_cover/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

import asyncio

from homeassistant.components.button import ButtonEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
Expand Down Expand Up @@ -81,10 +83,12 @@ async def async_press(self) -> None:
if self.coordinator.manager.is_cover_manual(entity):
_LOGGER.debug("Resetting manual override for: %s", entity)
await self.coordinator.async_set_position(entity)
while self.coordinator.wait_for_target.get(entity):
await asyncio.sleep(1)
self.coordinator.manager.reset(entity)
else:
_LOGGER.debug(
"Resetting manual override for %s is not needed since it is already auto-cotrolled",
"Resetting manual override for %s is not needed since it is already auto-controlled",
entity,
)
await self.coordinator.async_refresh()
63 changes: 48 additions & 15 deletions custom_components/adaptive_cover/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,11 @@ def __init__(self, hass: HomeAssistant) -> None: # noqa: D107
self.manual_duration = self.config_entry.options.get(
CONF_MANUAL_OVERRIDE_DURATION, {"minutes": 15}
)
self.state_change = False
self.cover_state_change = False
self.state_change_data: StateChangedData | None = None
self.manager = AdaptiveCoverManager(self.manual_duration)
self.send_call = False
self.wait_for_target = {}
self.target_call = {}

async def async_config_entry_first_refresh(self):
"""Call the first update from config_entry."""
Expand All @@ -116,12 +117,36 @@ async def async_config_entry_first_refresh(self):

async def async_check_entity_state_change(
self, entity: str, old_state: State | None, new_state: State | None
) -> None:
"""Fetch and process state change event."""
# self.state_change = True
await self.async_refresh()

async def async_check_cover_state_change(
self, entity: str, old_state: State | None, new_state: State | None
) -> None:
"""Fetch and process state change event."""
self.state_change_data = StateChangedData(entity, old_state, new_state)
self.state_change = True
self.cover_state_change = True
self.process_entity_state_change()
await self.async_refresh()

def process_entity_state_change(self):
"""Process state change event."""
event = self.state_change_data
_LOGGER.debug("Processing state change event: %s", event)
entity_id = event.entity_id
if self.wait_for_target.get(entity_id):
position = event.new_state.attributes.get(
"current_position"
if self._cover_type != "cover_tilt"
else "current_tilt_position"
)
if position == self.target_call.get(entity_id):
self.wait_for_target[entity_id] = False
_LOGGER.debug("Position %s reached for %s", position, entity_id)
_LOGGER.debug("Wait for target: %s", self.wait_for_target)

async def _async_update_data(self) -> AdaptiveCoverData:
self.entities = self.config_entry.options.get(CONF_ENTITIES, [])
self.min_change = self.config_entry.options.get(CONF_DELTA_POSITION, 1)
Expand Down Expand Up @@ -167,15 +192,15 @@ async def _async_update_data(self) -> AdaptiveCoverData:

self.default_state = round(NormalCoverState(cover_data).get_state())

state_range = range(
int(self.state - self.min_change), int(self.state + 1 + self.min_change)
)

if self.state_change:
self.manager.state_change(
self.state_change_data, state_range, self._cover_type, self.manual_reset
if self.cover_state_change:
self.manager.handle_state_change(
self.state_change_data,
self.state,
self._cover_type,
self.manual_reset,
self.wait_for_target,
)
self.state_change = False # reset state change
self.cover_state_change = False # reset state change
await self.manager.reset_if_needed()

if self.control_toggle:
Expand Down Expand Up @@ -203,6 +228,9 @@ async def _async_update_data(self) -> AdaptiveCoverData:
self.config_entry.options.get(CONF_FOV_LEFT),
self.config_entry.options.get(CONF_FOV_RIGHT),
],
"wait_for_target": self.wait_for_target,
"target_call": self.target_call,
"manual_control": self.manager.manual_controlled,
},
)

Expand All @@ -227,6 +255,8 @@ async def async_set_position(self, entity):
else:
service_data[ATTR_POSITION] = self.state

self.wait_for_target[entity] = True
self.target_call[entity] = self.state
await self.hass.services.async_call(COVER_DOMAIN, service, service_data)
_LOGGER.debug("Run %s with data %s", service, service_data)

Expand Down Expand Up @@ -385,14 +415,18 @@ def add_covers(self, entity):
"""Update set with entities."""
self.covers.update(entity)

def state_change(self, states_data, our_state, blind_type, allow_reset):
def handle_state_change(
self, states_data, our_state, blind_type, allow_reset, wait_target_call
):
"""Process state change event."""
event = states_data
if event is None:
return
entity_id = event.entity_id
if entity_id not in self.covers:
return
if wait_target_call[entity_id]:
return

new_state = event.new_state

Expand All @@ -401,7 +435,7 @@ def state_change(self, states_data, our_state, blind_type, allow_reset):
else:
new_position = new_state.attributes.get("current_position")

if new_position not in our_state:
if new_position != our_state:
_LOGGER.debug(
"Set manual control for %s, for at least %s seconds, reset_allowed: %s",
entity_id,
Expand All @@ -410,8 +444,6 @@ def state_change(self, states_data, our_state, blind_type, allow_reset):
)
self.mark_manual_control(entity_id)
self.set_last_updated(entity_id, new_state, allow_reset)
else:
self.reset(entity_id)

def set_last_updated(self, entity_id, new_state, allow_reset):
"""Set last updated time for manual control."""
Expand Down Expand Up @@ -451,6 +483,7 @@ def reset(self, entity_id):
"""Reset manual control for a cover."""
self.manual_control[entity_id] = False
self.manual_control_time.pop(entity_id, None)
_LOGGER.debug("Reset manual override for %s", entity_id)

def is_cover_manual(self, entity_id):
"""Check if a cover is under manual control."""
Expand Down

0 comments on commit 3be8901

Please sign in to comment.