Merge pull request #29 from devmel/38decibel-invert-option
feat: add invert option for covers with reversed open/close logic
This commit is contained in:
@@ -45,6 +45,7 @@ devices:
|
|||||||
Volet salon:
|
Volet salon:
|
||||||
id: 12345
|
id: 12345
|
||||||
type: 4098
|
type: 4098
|
||||||
|
invert: true # add this option for covers where open/close logic is reversed (e.g. shade sails, projector screens)
|
||||||
apiKey: !secret apiKey
|
apiKey: !secret apiKey
|
||||||
spurl: !secret spurl
|
spurl: !secret spurl
|
||||||
channel:
|
channel:
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ class AirSendCover(RestoreEntity, CoverEntity):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self):
|
def extra_state_attributes(self):
|
||||||
return self._device.extra_state_attributes
|
attrs = self._device.extra_state_attributes or {}
|
||||||
|
if self._device.is_inverted:
|
||||||
|
attrs = {**attrs, "inverted": True}
|
||||||
|
return attrs or None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def assumed_state(self):
|
def assumed_state(self):
|
||||||
@@ -75,7 +78,9 @@ class AirSendCover(RestoreEntity, CoverEntity):
|
|||||||
if self._device.is_async and self._hass:
|
if self._device.is_async and self._hass:
|
||||||
component = self._hass.states.get(self.entity_id)
|
component = self._hass.states.get(self.entity_id)
|
||||||
if component is not None:
|
if component is not None:
|
||||||
self._closed = component.state not in ('open', 'on', 'up')
|
is_open_state = component.state not in ('open', 'on', 'up')
|
||||||
|
# Invert the closed logic if needed
|
||||||
|
self._closed = not is_open_state if self._device.is_inverted else is_open_state
|
||||||
return self._closed
|
return self._closed
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
@@ -105,17 +110,25 @@ class AirSendCover(RestoreEntity, CoverEntity):
|
|||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
return result in (TransferResult.SUCCESS, TransferResult.SENT)
|
return result in (TransferResult.SUCCESS, TransferResult.SENT)
|
||||||
|
|
||||||
|
def _up_note(self) -> dict:
|
||||||
|
"""Return UP note, inverted if needed."""
|
||||||
|
value = "DOWN" if self._device.is_inverted else "UP"
|
||||||
|
return {"method": 1, "type": 0, "value": value}
|
||||||
|
|
||||||
|
def _down_note(self) -> dict:
|
||||||
|
"""Return DOWN note, inverted if needed."""
|
||||||
|
value = "UP" if self._device.is_inverted else "DOWN"
|
||||||
|
return {"method": 1, "type": 0, "value": value}
|
||||||
|
|
||||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||||
note = {"method": 1, "type": 0, "value": "UP"}
|
if await self._send(self._up_note()):
|
||||||
if await self._send(note):
|
|
||||||
self._closed = False
|
self._closed = False
|
||||||
if self._device.is_cover_with_position:
|
if self._device.is_cover_with_position:
|
||||||
self._attr_current_cover_position = 100
|
self._attr_current_cover_position = 100
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||||
note = {"method": 1, "type": 0, "value": "DOWN"}
|
if await self._send(self._down_note()):
|
||||||
if await self._send(note):
|
|
||||||
self._closed = True
|
self._closed = True
|
||||||
if self._device.is_cover_with_position:
|
if self._device.is_cover_with_position:
|
||||||
self._attr_current_cover_position = 0
|
self._attr_current_cover_position = 0
|
||||||
@@ -131,7 +144,9 @@ class AirSendCover(RestoreEntity, CoverEntity):
|
|||||||
|
|
||||||
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
||||||
position = int(kwargs["position"])
|
position = int(kwargs["position"])
|
||||||
note = {"method": 1, "type": 9, "value": position}
|
# Invert position value if needed
|
||||||
|
actual_position = (100 - position) if self._device.is_inverted else position
|
||||||
|
note = {"method": 1, "type": 9, "value": actual_position}
|
||||||
if await self._send(note):
|
if await self._send(note):
|
||||||
self._attr_current_cover_position = position
|
self._attr_current_cover_position = position
|
||||||
self._closed = position == 0
|
self._closed = position == 0
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ class Device:
|
|||||||
self._refresh = int(options["refresh"])
|
self._refresh = int(options["refresh"])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
try:
|
||||||
|
self._invert = bool(options["invert"])
|
||||||
|
except KeyError:
|
||||||
|
self._invert = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
@@ -158,6 +162,11 @@ class Device:
|
|||||||
def is_light(self) -> bool:
|
def is_light(self) -> bool:
|
||||||
return self._rtype == 4100
|
return self._rtype == 4100
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_inverted(self) -> bool:
|
||||||
|
"""Return True if open/close logic is inverted."""
|
||||||
|
return self._invert
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def refresh_value(self) -> int:
|
def refresh_value(self) -> int:
|
||||||
"""Return refresh value in seconds."""
|
"""Return refresh value in seconds."""
|
||||||
|
|||||||
Reference in New Issue
Block a user