From e5a5d27afc7bc6176935e6201e9ce6e74541d0d7 Mon Sep 17 00:00:00 2001 From: andrea Date: Sat, 27 Apr 2024 11:59:42 +0200 Subject: [PATCH 1/2] Added openenig and closing time attributes --- custom_components/myhome/const.py | 2 ++ custom_components/myhome/cover.py | 40 ++++++++++++++++++++++++++-- custom_components/myhome/validate.py | 4 +++ 3 files changed, 44 insertions(+), 2 deletions(-) mode change 100644 => 100755 custom_components/myhome/const.py mode change 100644 => 100755 custom_components/myhome/cover.py mode change 100644 => 100755 custom_components/myhome/validate.py diff --git a/custom_components/myhome/const.py b/custom_components/myhome/const.py old mode 100644 new mode 100755 index 9c560b6..358dc6d --- a/custom_components/myhome/const.py +++ b/custom_components/myhome/const.py @@ -46,3 +46,5 @@ CONF_SHORT_RELEASE = "pushbutton_short_release" CONF_LONG_PRESS = "pushbutton_long_press" CONF_LONG_RELEASE = "pushbutton_long_release" +CONF_SHUTTER_OPENING_TIME = "opening_time" +CONF_SHUTTER_CLOSING_TIME = "closing_time" \ No newline at end of file diff --git a/custom_components/myhome/cover.py b/custom_components/myhome/cover.py old mode 100644 new mode 100755 index 13c42e0..773b9a7 --- a/custom_components/myhome/cover.py +++ b/custom_components/myhome/cover.py @@ -29,9 +29,12 @@ CONF_ADVANCED_SHUTTER, DOMAIN, LOGGER, + CONF_SHUTTER_OPENING_TIME, + CONF_SHUTTER_CLOSING_TIME, ) from .myhome_device import MyHOMEEntity from .gateway import MyHOMEGatewayHandler +from datetime import datetime async def async_setup_entry(hass, config_entry, async_add_entities): @@ -54,6 +57,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): manufacturer=_configured_covers[_cover][CONF_MANUFACTURER], model=_configured_covers[_cover][CONF_DEVICE_MODEL], gateway=hass.data[DOMAIN][config_entry.data[CONF_MAC]][CONF_ENTITY], + opening_time=_configured_covers[_cover][CONF_SHUTTER_OPENING_TIME], + closing_time=_configured_covers[_cover][CONF_SHUTTER_CLOSING_TIME], ) _covers.append(_cover) @@ -86,6 +91,8 @@ def __init__( manufacturer: str, model: str, gateway: MyHOMEGatewayHandler, + opening_time: int, + closing_time: int ): super().__init__( hass=hass, @@ -107,6 +114,8 @@ def __init__( self._attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE | CoverEntityFeature.STOP if advanced: self._attr_supported_features |= CoverEntityFeature.SET_POSITION + elif opening_time > 0 and closing_time > 0: + self._attr_supported_features |= CoverEntityFeature.SET_POSITION self._gateway_handler = gateway self._attr_extra_state_attributes = { @@ -120,6 +129,9 @@ def __init__( self._attr_is_opening = None self._attr_is_closing = None self._attr_is_closed = None + self._attr_last_event = datetime.now() + self._attr_opening_time = opening_time + self._attr_closing_time = closing_time async def async_update(self): """Update the entity. @@ -153,11 +165,35 @@ def handle_event(self, message: OWNAutomationEvent): self._gateway_handler.log_id, message.human_readable_log, ) + + if message.current_position is not None: + self._attr_current_cover_position = message.current_position + elif self._attr_last_event is not None and self._attr_opening_time > 0 and self._attr_closing_time > 0: + elapsed_seconds = (datetime.now() - self._attr_last_event).total_seconds() + if elapsed_seconds > 0: + if self._attr_is_opening: + if self._attr_opening_time < elapsed_seconds: + self._attr_current_cover_position = 100 + elif (self._attr_current_cover_position is not None): + self._attr_current_cover_position = round(min(100, self._attr_current_cover_position + (100 * elapsed_seconds / self._attr_opening_time)), 0) + elif self._attr_is_closing: + if self._attr_closing_time < elapsed_seconds: + self._attr_current_cover_position = 0 + elif self._attr_current_cover_position is not None: + self._attr_current_cover_position = round(max(0, self._attr_current_cover_position - (100 * elapsed_seconds / self._attr_closing_time)), 0) + + LOGGER.info( + "%s %s", + self._gateway_handler.log_id, + self._attr_current_cover_position, + ) + + self._attr_last_event = datetime.now() self._attr_is_opening = message.is_opening self._attr_is_closing = message.is_closing if message.is_closed is not None: self._attr_is_closed = message.is_closed - if message.current_position is not None: - self._attr_current_cover_position = message.current_position + elif self._attr_current_cover_position is not None: + self._attr_is_closed = self._attr_current_cover_position == 0 self.async_schedule_update_ha_state() diff --git a/custom_components/myhome/validate.py b/custom_components/myhome/validate.py old mode 100644 new mode 100755 index a27b09c..dcef874 --- a/custom_components/myhome/validate.py +++ b/custom_components/myhome/validate.py @@ -52,6 +52,8 @@ CONF_COOLING_SUPPORT, CONF_STANDALONE, CONF_CENTRAL, + CONF_SHUTTER_OPENING_TIME, + CONF_SHUTTER_CLOSING_TIME, ) @@ -336,6 +338,8 @@ def __call__(self, data): Required(CONF_NAME): str, Optional(CONF_ENTITY_NAME): str, Optional(CONF_ADVANCED_SHUTTER, default=False): Boolean(), + Optional(CONF_SHUTTER_OPENING_TIME, default=0): int, + Optional(CONF_SHUTTER_CLOSING_TIME, default=0): int, Optional(CONF_MANUFACTURER, default="BTicino S.p.A."): str, Optional(CONF_DEVICE_MODEL): Coerce(str), } From bba3c6420351c52d3139b1606f3a7157183d407e Mon Sep 17 00:00:00 2001 From: andrea Date: Sat, 4 May 2024 10:42:47 +0200 Subject: [PATCH 2/2] Add the support to move a cover to a position without advanced device --- custom_components/myhome/cover.py | 44 ++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/custom_components/myhome/cover.py b/custom_components/myhome/cover.py index 773b9a7..7253241 100755 --- a/custom_components/myhome/cover.py +++ b/custom_components/myhome/cover.py @@ -35,7 +35,7 @@ from .myhome_device import MyHOMEEntity from .gateway import MyHOMEGatewayHandler from datetime import datetime - +import asyncio async def async_setup_entry(hass, config_entry, async_add_entities): if PLATFORM not in hass.data[DOMAIN][config_entry.data[CONF_MAC]][CONF_PLATFORMS]: @@ -110,6 +110,9 @@ def __init__( self._interface = interface self._full_where = f"{self._where}#4#{self._interface}" if self._interface is not None else self._where + self._attr_opening_time = opening_time + self._attr_closing_time = closing_time + self._attr_advanced = advanced self._attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE | CoverEntityFeature.STOP if advanced: @@ -130,8 +133,6 @@ def __init__( self._attr_is_closing = None self._attr_is_closed = None self._attr_last_event = datetime.now() - self._attr_opening_time = opening_time - self._attr_closing_time = closing_time async def async_update(self): """Update the entity. @@ -152,7 +153,38 @@ async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" if ATTR_POSITION in kwargs: position = kwargs[ATTR_POSITION] - await self._gateway_handler.send(OWNAutomationCommand.set_shutter_level(self._full_where, position)) + if self._attr_advanced: + await self._gateway_handler.send(OWNAutomationCommand.set_shutter_level(self._full_where, position)) + elif self._attr_opening_time > 0 or self._attr_closing_time > 0: + + if self._attr_is_closing or self._attr_is_closing: + await self._gateway_handler.send(OWNAutomationCommand.stop_shutter(self._full_where)) + + if self._attr_current_cover_position is None: + return + + required_move = int(position - self._attr_current_cover_position) + if required_move > 0: + """ open """ + required_time = abs(self._attr_opening_time * required_move / 100) + LOGGER.debug( + "Open -> Required time %s", + required_time, + ) + await self._gateway_handler.send(OWNAutomationCommand.raise_shutter(self._full_where)) + await asyncio.sleep(required_time) + await self._gateway_handler.send(OWNAutomationCommand.stop_shutter(self._full_where)) + elif required_move < 0: + """ close """ + required_time = abs(self._attr_closing_time * required_move / 100) + LOGGER.debug( + "Close -> Required time %s", + required_time, + ) + await self._gateway_handler.send(OWNAutomationCommand.lower_shutter(self._full_where)) + await asyncio.sleep(required_time) + await self._gateway_handler.send(OWNAutomationCommand.stop_shutter(self._full_where)) + async def async_stop_cover(self, **kwargs): # pylint: disable=unused-argument """Stop the cover.""" @@ -182,7 +214,7 @@ def handle_event(self, message: OWNAutomationEvent): elif self._attr_current_cover_position is not None: self._attr_current_cover_position = round(max(0, self._attr_current_cover_position - (100 * elapsed_seconds / self._attr_closing_time)), 0) - LOGGER.info( + LOGGER.debug( "%s %s", self._gateway_handler.log_id, self._attr_current_cover_position, @@ -196,4 +228,4 @@ def handle_event(self, message: OWNAutomationEvent): elif self._attr_current_cover_position is not None: self._attr_is_closed = self._attr_current_cover_position == 0 - self.async_schedule_update_ha_state() + self.async_schedule_update_ha_state() \ No newline at end of file