Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,14 @@ BulbDevice Additional Functions
result = state():

CoverDevice Additional Functions
open_cover(switch=1):
close_cover(switch=1):
stop_cover(switch=1):
open_cover(switch=1, nowait=False):
close_cover(switch=1, nowait=False):
stop_cover(switch=1, nowait=False):
set_cover_command_type(use_open_close=True): # Manually set command type ("open"/"close" vs "on"/"off")

Note: CoverDevice automatically detects whether the device uses "open"/"close" or
"on"/"off" commands by checking the device status on first use. You can manually
override this detection using set_cover_command_type() if needed.

Cloud Functions
setregion(apiRegion)
Expand Down Expand Up @@ -349,6 +354,30 @@ d.set_mode('scene')
# Scene Example: Set Color Rotation Scene
d.set_value(25, '07464602000003e803e800000000464602007803e803e80000000046460200f003e803e800000000464602003d03e803e80000000046460200ae03e803e800000000464602011303e803e800000000')

"""
Cover Device (Window Shade)
"""
c = tinytuya.CoverDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE')
c.set_version(3.3)
data = c.status()

# Show status
print('Dictionary %r' % data)

# Open the cover
c.open_cover()

# Close the cover
c.close_cover()

# Stop the cover
c.stop_cover()

# Manually set command type if auto-detection doesn't work
# Some devices use "open"/"close", others use "on"/"off"
c.set_cover_command_type(True) # Use "open"/"close" commands
c.set_cover_command_type(False) # Use "on"/"off" commands

```
### Example Device Monitor

Expand Down
4 changes: 4 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# RELEASE NOTES

## v1.17.5 - CoverDevice Command Detection

* CoverDevice: Add automatic detection of device command type ("open"/"close" vs "on"/"off") by lazy polling device status on first use. This allows CoverDevice to work with both device types without manual configuration. Defaults to "on"/"off" for backward compatibility.

## 1.17.4 - Cloud Config

- Cloud: Add `configFile` option to the Cloud constructor, allowing users to specify the config file location (default remains 'tinytuya.json') by @blackw1ng in https://github.com/jasonacox/tinytuya/pull/640
Expand Down
84 changes: 76 additions & 8 deletions tinytuya/CoverDevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@

Functions
CoverDevice:
open_cover(switch=1):
close_cover(switch=1):
stop_cover(switch=1):
open_cover(switch=None, nowait=False) # Open the cover (switch defaults to DPS_INDEX_MOVE)
close_cover(switch=None, nowait=False) # Close the cover (switch defaults to DPS_INDEX_MOVE)
stop_cover(switch=None, nowait=False) # Stop the cover motion (switch defaults to DPS_INDEX_MOVE)
set_cover_command_type(use_open_close=True) # Manually set command type

Notes
CoverDevice will automatically detect the command type used by the device:
- Some devices use "open"/"close" commands
- Other devices use "on"/"off" commands
Detection occurs on first open_cover() or close_cover() call by checking
the device status. Defaults to "on"/"off" for backward compatibility.

Inherited
json = status() # returns json payload
Expand Down Expand Up @@ -56,14 +64,74 @@ class CoverDevice(Device):
"101": "backlight",
}

def open_cover(self, switch=1, nowait=False):
def __init__(self, *args, **kwargs):
super(CoverDevice, self).__init__(*args, **kwargs)
self._cover_commands_detected = False
self._use_open_close = False # Default to "on"/"off"

def _detect_cover_commands(self, switch=None):
"""
Lazy detection of cover command type by checking device status.
Some devices use "open"/"close", others use "on"/"off".
This method is called automatically on first open/close command.

Args:
switch (str/int): The DPS index to check for command type detection.
Defaults to DPS_INDEX_MOVE if not specified.
"""
if self._cover_commands_detected:
return

if switch is None:
switch = self.DPS_INDEX_MOVE

try:
result = self.status()
if result and 'dps' in result:
dps_key = str(switch)
dps_value = result['dps'].get(dps_key)
if dps_value in ['open', 'close']:
self._use_open_close = True
# else: keep default False (use "on"/"off")
except Exception:
# If status check fails, stick with default "on"/"off"
pass

self._cover_commands_detected = True

def set_cover_command_type(self, use_open_close=True):
"""
Manually set the cover command type.

Args:
use_open_close (bool): If True, uses "open"/"close" commands.
If False, uses "on"/"off" commands.

Example:
cover.set_cover_command_type(True) # Use "open"/"close"
cover.set_cover_command_type(False) # Use "on"/"off"
"""
self._use_open_close = use_open_close
self._cover_commands_detected = True # Prevent auto-detection

def open_cover(self, switch=None, nowait=False):
"""Open the cover"""
self.set_status("on", switch, nowait=nowait)
if switch is None:
switch = self.DPS_INDEX_MOVE
self._detect_cover_commands(switch)
command = "open" if self._use_open_close else "on"
self.set_status(command, switch, nowait=nowait)

def close_cover(self, switch=1, nowait=False):
def close_cover(self, switch=None, nowait=False):
"""Close the cover"""
self.set_status("off", switch, nowait=nowait)
if switch is None:
switch = self.DPS_INDEX_MOVE
self._detect_cover_commands(switch)
command = "close" if self._use_open_close else "off"
self.set_status(command, switch, nowait=nowait)

def stop_cover(self, switch=1, nowait=False):
def stop_cover(self, switch=None, nowait=False):
"""Stop the motion of the cover"""
if switch is None:
switch = self.DPS_INDEX_MOVE
self.set_status("stop", switch, nowait=nowait)
2 changes: 1 addition & 1 deletion tinytuya/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
if HAVE_COLORAMA:
init()

version_tuple = (1, 17, 4) # Major, Minor, Patch
version_tuple = (1, 17, 5) # Major, Minor, Patch
version = __version__ = "%d.%d.%d" % version_tuple
__author__ = "jasonacox"

Expand Down
Loading