Skip to content

Commit

Permalink
Updated logic for blind position and added persistance during restarts
Browse files Browse the repository at this point in the history
  • Loading branch information
pink88 committed Nov 26, 2024
1 parent 77c9d2c commit bdde4ed
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 12 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ To get started you need to download and use the Tuiss Smartview app to set the u
- Close
- Stop
- Battery State (through service)
- Blind position (through service)
- Decimal Blind position (through service)

### Battery State ###
An accurate battery percentage is not provided by the blind, but it is possible to return two states:
Expand Down Expand Up @@ -75,7 +75,7 @@ To overwrite home assistants built in integer accuracy, you can use the "Tuiss2h

## Limitations ##
- Setting the top and bottom thresholds of the blind. Currently, you still need to pair with and use the Tuiss app to set these values.
- Realtime blind positioning as moving will work after the first use, as this is required to calibrate the speed of your blind motor.
- Realtime blind positioning will only work after the first use as this initial run is required to calibrate the speed of your blind motor.

## Troubleshooting ##
- I've only tested with HAOS installed on a Raspberry Pi4b and the built in Bluetooth module did not work, so I had to use a couple ESP32 devices with Bluetooth proxy software installed (See [here](https://esphome.io/components/bluetooth_proxy.html))
Expand Down
34 changes: 24 additions & 10 deletions custom_components/tuiss2ha/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@

_LOGGER = logging.getLogger(__name__)


ATTR_TRAVERSAL_TIME = "traversal_time"


SET_BLIND_POSITION_SCHEMA = {
vol.Required("position"): vol.All(
vol.Coerce(float),
Expand Down Expand Up @@ -82,8 +86,9 @@ def __init__(self, blind) -> None:
self._state = None
self._startTime = None
self._endTime = None
self._traversalTime = None
self._attr_traversal_time= None
self._locked = False



@property
Expand Down Expand Up @@ -116,17 +121,18 @@ def available(self) -> bool:
"""Return True if blind and hub is available."""
return True

@property
def extra_state_attributes(self) -> dict[str,Any]:
"""Attributes for the traversal time of the blinds."""
return {ATTR_TRAVERSAL_TIME: self._attr_traversal_time}

@property
def current_cover_position(self):
"""Return the current position of the cover."""
if self._blind._current_cover_position is None:
return None
return self._blind._current_cover_position

@property
def traversal_time(self):
"""The speed of the blind, used to calculate the realtime position."""
return self._traversalTime

@property
def is_closed(self) -> bool | None:
Expand Down Expand Up @@ -163,12 +169,19 @@ async def async_scheduled_update_request(self, *_):
async def async_added_to_hass(self) -> None:
"""Run when this Entity has been added to HA."""
last_state = await self.async_get_last_state()
#get the last known position
if not last_state or ATTR_CURRENT_POSITION not in last_state.attributes:
self._blind._current_cover_position = 0
else:
self._blind._current_cover_position = last_state.attributes.get(
ATTR_CURRENT_POSITION
)
#get the last known traversal time, for calculating realtime position
if last_state and ATTR_TRAVERSAL_TIME in last_state.attributes:
self._attr_traversal_time = last_state.attributes.get(
ATTR_TRAVERSAL_TIME
)

self._blind.register_callback(self.async_write_ha_state)


Expand Down Expand Up @@ -212,9 +225,10 @@ async def async_move_cover(self, movVal, targetPos):

while self._blind._client.is_connected:
#Update the position in realtime based on average traversal time
if self._traversalTime is not None:
if self._attr_traversal_time is not None:
_LOGGER.debug("StartPos: %s. Timedelta: %s",startPos, (datetime.datetime.now() - self._startTime).total_seconds())
self._blind._current_cover_position = startPos + ((datetime.datetime.now() - self._startTime).total_seconds()*self._traversalTime*movVal)
traversalDelta = (datetime.datetime.now() - self._startTime).total_seconds()*self._attr_traversal_time*movVal
self._blind._current_cover_position = sorted([startPos,startPos + traversalDelta,100-targetPos])[1]
await self.async_scheduled_update_request()
await asyncio.sleep(1)

Expand All @@ -234,9 +248,9 @@ async def async_move_cover(self, movVal, targetPos):
async def update_traversal_time(self, targetPos, startPos):
timeTaken = (self._endTime - self._startTime).total_seconds()
traversalDistance = abs(targetPos - startPos)
self._traversalTime = traversalDistance/timeTaken
_LOGGER.debug("%s: Time Taken: %s. Start Pos: %s. End Pos: %s. Distance Travelled: %s. Traversal Time: %s", self._attr_name, timeTaken, startPos, targetPos, traversalDistance, self._traversalTime)

self._attr_traversal_time = traversalDistance/timeTaken
_LOGGER.debug("%s: Time Taken: %s. Start Pos: %s. End Pos: %s. Distance Travelled: %s. Traversal Time: %s", self._attr_name, timeTaken, startPos, targetPos, traversalDistance, self._attr_traversal_time)
await self.async_scheduled_update_request()


async def async_stop_cover(self, **kwargs: Any) -> None:
Expand Down

0 comments on commit bdde4ed

Please sign in to comment.