Skip to content

Commit

Permalink
feat(cover): add "cover_duration" attribute
Browse files Browse the repository at this point in the history
Duration of the cover to open and/or close in seconds, so `toggle_open` and `toggle_close` can stop the cover if the cover is still moving. This is recommended to be used when the cover does not report `opening` and `closing` states, otherwise it is not necessary.

related to #368
  • Loading branch information
xaviml committed Oct 29, 2021
1 parent f877bc4 commit 7a3aa99
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 15 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ PRERELEASE_NOTE
## :pencil2: Features

- Add `previous_state` attribute to restrict when an action is performed depending on the previous state of the entity. This is just applicable for `state` and `z2m` (with not MQTT) integrations. [#366]
- Add `cover_duration` attribute. Duration of the cover to open and/or close in seconds, so `toggle_open` and `toggle_close` can stop the cover if the cover is still moving. This is recommended to be used when the cover does not report `opening` and `closing` states, otherwise, it is not necessary. [#368]

<!--
## :hammer: Fixes
Expand Down
37 changes: 35 additions & 2 deletions apps/controllerx/cx_core/type/cover_controller.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Callable, Type
from typing import Callable, Optional, Type

from cx_const import Cover, PredefinedActionsMapping
from cx_core.controller import action
Expand All @@ -25,9 +25,15 @@ class CoverController(TypeController[Entity]):
open_position: int
close_position: int

cover_duration: Optional[int]

is_supposedly_moving: bool = False
stop_timer_handle: Optional[str] = None

async def init(self) -> None:
self.open_position = self.args.get("open_position", 100)
self.close_position = self.args.get("close_position", 0)
self.cover_duration = self.args.get("cover_duration")
if self.open_position < self.close_position:
raise ValueError("`open_position` must be higher than `close_position`")
await super().init()
Expand All @@ -44,6 +50,24 @@ def get_predefined_actions_mapping(self) -> PredefinedActionsMapping:
Cover.TOGGLE_CLOSE: (self.toggle, (self.close,)),
}

async def cover_stopped_cb(self, kwargs):
self.is_supposedly_moving = False
self.stop_timer_handle = None

async def start_timer(self):
if self.cover_duration is None:
return
await self.stop_timer()
self.is_supposedly_moving = True
self.stop_timer_handle = await self.run_in(
self.cover_stopped_cb, self.cover_duration
)

async def stop_timer(self):
if self.stop_timer_handle is not None:
self.is_supposedly_moving = False
await self.cancel_timer(self.stop_timer_handle)

@action
async def open(self) -> None:
if await self.feature_support.is_supported(CoverSupport.SET_COVER_POSITION):
Expand All @@ -60,6 +84,8 @@ async def open(self) -> None:
level="WARNING",
ascii_encode=False,
)
return
await self.start_timer()

@action
async def close(self) -> None:
Expand All @@ -77,15 +103,22 @@ async def close(self) -> None:
level="WARNING",
ascii_encode=False,
)
return
await self.start_timer()

@action
async def stop(self) -> None:
await self.stop_timer()
await self.call_service("cover/stop_cover", entity_id=self.entity.name)

@action
async def toggle(self, action: Callable) -> None:
cover_state = await self.get_entity_state()
if cover_state == "opening" or cover_state == "closing":
if (
cover_state == "opening"
or cover_state == "closing"
or self.is_supposedly_moving
):
await self.stop()
else:
await action()
27 changes: 14 additions & 13 deletions docs/start/type-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ This controller allows the devices to control light or group of lights. This all
| `add_transition` | boolean | True | If `true` adds transition if supported, otherwise it does not adds the `transition` attribute. |
| `add_transition_turn_toggle` | boolean | True | If `false` does not add transition when turning on/off or toggling, otherwise it adds the `transition` attribute to the call. See [FAQ #6](/controllerx/faq#6-light-is-not-turning-on-to-the-previous-brightness) for a further explanation on the use of this parameter. |
| `color_wheel` | string \| list | `default_color_wheel` | It defines the color wheel used when changing the xy color either when click or hold actions are used. Check down to know more about the options. |
| `supported_features` | int | `0b101100` or `44` | See [below](#supported_features-field) for the explanation. |
| `supported_features` | int | `0b101100` or `44` | See [below](#supported_features-field) for the explanation. |
| `supported_color_modes` | list | `["xy", "rgb"]` | It overrides the `supported_color_modes` that can be found in light attributes. Values can be `color_temp`, `hs`, `xy`, `rgb`, `rgbw` and `rgbww`. |
| `update_supported_features` | boolean | False | If `true`, it will check the supported features field everytime before calling any call service action. Useful in case the supported features of the device entity changes over the time. |

Expand Down Expand Up @@ -104,13 +104,14 @@ _\* Required fields_

This allows you to control covers. It supports opening/closing and stop covers.

| key | type | value | description |
| --------------------------- | ------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cover`\* | string | `group.all_covers` or `cover.kitchen` | The cover (or group of covers) you want to control |
| `open_position` | number | 100 | The open position (between 0 and 100) |
| `close_position` | number | 0 | The close position (between 0 and 100) |
| `supported_features` | int | `0b10111111` or `191` | See [below](#supported_features-field) for the explanation. |
| `update_supported_features` | boolean | False | If `true`, it will check the supported features field everytime before calling any call service action. Useful in case the supported features of the device entity changes over the time. |
| key | type | value | description |
| --------------------------- | ------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cover`\* | string | `group.all_covers` or `cover.kitchen` | The cover (or group of covers) you want to control |
| `open_position` | number | 100 | The open position (between 0 and 100) |
| `close_position` | number | 0 | The close position (between 0 and 100) |
| `cover_duration` | number | - | Duration of the cover to open and/or close in seconds, so `toggle_open` and `toggle_close` can stop the cover if the cover is still moving. This is recommended to be used when the cover does not report `opening` and `closing` states, otherwise, it is not necessary. |
| `supported_features` | int | `0b10111111` or `191` | See [below](#supported_features-field) for the explanation. |
| `update_supported_features` | boolean | False | If `true`, it will check the supported features field everytime before calling any call service action. Useful in case the supported features of the device entity changes over the time. |

_\* Required fields_

Expand All @@ -120,11 +121,11 @@ This field will override the `supported_features` attribute from the entity (lig

#### Light

| feature | value |
| ----------- | ----- |
| EFFECT | 4 |
| FLASH | 8 |
| TRANSITION | 32 |
| feature | value |
| ---------- | ----- |
| EFFECT | 4 |
| FLASH | 8 |
| TRANSITION | 32 |

If you want to express support for everything, the value is `0b101100` or `44`.

Expand Down
8 changes: 8 additions & 0 deletions tests/integ_tests/cover_duration/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
example_app:
module: controllerx
class: E1743CoverController
controller: 00:11:22:33:44:55:66:77
integration: zha
action_delta: 50
cover_duration: 1
cover: cover.my_cover
17 changes: 17 additions & 0 deletions tests/integ_tests/cover_duration/open_cover_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
fired_actions: ["on", 0.1, "off", 0.1, "off", 1.05, "on"]
expected_calls:
- service: cover/set_cover_position
data:
entity_id: cover.my_cover
position: 100
- service: cover/stop_cover
data:
entity_id: cover.my_cover
- service: cover/set_cover_position
data:
entity_id: cover.my_cover
position: 0
- service: cover/set_cover_position
data:
entity_id: cover.my_cover
position: 100

0 comments on commit 7a3aa99

Please sign in to comment.