Skip to content

[Aqara] Roller Shade T1S - #3292

Open
seojune79 wants to merge 2 commits into
SmartThingsCommunity:mainfrom
seojune79:Aqara-Roller-Shade-T1S
Open

seojune79 wants to merge 2 commits into
SmartThingsCommunity:mainfrom
seojune79:Aqara-Roller-Shade-T1S

Conversation

@seojune79

@seojune79 seojune79 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Check all that apply

Type of Change

  • WWST Certification Request
    • If this is your first time contributing code:
      • I have reviewed the README.md file
      • I have reviewed the CODE_OF_CONDUCT.md file
      • I have signed the CLA
    • I plan on entering a WWST Certification Request or have entered a request through the WWST Certification console at developer.smartthings.com
  • Bug fix
  • New feature
  • Refactor

Checklist

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have verified my changes by testing with a device or have communicated a plan for testing
  • I am adding new behavior, such as adding a sub-driver, and have added and run new unit tests to cover the new behavior

Description of Change

Summary of Completed Tests

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

zigbee-window-treatment_coverage.xml

File Coverage
All files 96% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/window_shade_utils.lua 91% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/lazy_load_subdriver.lua 57% ❌
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/aqara/curtain-driver-e1/init.lua 92% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/aqara/version/can_handle.lua 83% ❌
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/aqara/init.lua 90% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/aqara/aqara_utils.lua 93% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/yoolax/init.lua 97% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/sombra/init.lua 95% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/hanssem/init.lua 91% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/VIVIDSTORM/init.lua 93% ✅
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-window-treatment/src/axis/axis_version/init.lua 97% ✅

Minimum allowed coverage is 90%

Generated by 🐒 cobertura-action against 901759b

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Test Results

   73 files    546 suites   0s ⏱️
3 330 tests 3 330 ✅ 0 💤 0 ❌
5 340 runs  5 340 ✅ 0 💤 0 ❌

Results for commit 901759b.

♻️ This comment has been updated with latest results.

-- The position of this device is reported through the present value of the analog output
-- cluster, where 0 is fully closed and 100 is fully open. The lift percentage of the window
-- covering cluster is reported with the opposite polarity (100% = fully closed), so it is
-- ignored here to keep the parent Aqara handler from emitting an inverted shade level.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

current_position_lift_percentage_handler is never registered in zigbee_handlers. Lift-percentage reports therefore go to the parent aqara sub-driver's shade_level_report_legacy_handler, which emits the inverted level the comment is trying to prevent.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test to validate this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing out the missing part. I have added the handler along with the relevant test cases.


local INIT_STATE_REPORTED = "initStateReported"

local function is_not_init(device)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_not_init returns false (control allowed) until the device has reported INIT_STATE_ATTRIBUTE_ID at least once. Allowing commands before the init state is reported is the opposite of the existing roller shade, which prevents commands until the device reports as initialized. Why is this device different? If they can function the same that would be a better experience for users.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requested changes have been applied.

[capabilities.windowShade.ID] = {
[capabilities.windowShade.commands.open.NAME] = window_shade_open_cmd,
[capabilities.windowShade.commands.close.NAME] = window_shade_close_cmd,
-- [capabilities.windowShade.commands.pause.NAME] = window_shade_pause_cmd,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented out handler

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed it as suggested.

local reverseRollerShadeDirPrefValue = device.preferences[reverseRollerShadeDir.ID]
if reverseRollerShadeDirPrefValue ~= nil and
reverseRollerShadeDirPrefValue ~= args.old_st_store.preferences[reverseRollerShadeDir.ID] then
local raw_value = reverseRollerShadeDirPrefValue and true or false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local raw_value = reverseRollerShadeDirPrefValue and true or false
local raw_value = reverseRollerShadeDirPrefValue

reverseRollerShadeDirPrefValue is already a boolean type

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated as requested.

local function init_state_handler(driver, device, value, zb_rx)
device:set_field(INIT_STATE_REPORTED, true, { persist = true })
local state = value.value == 0x02 and initializedStateWithGuide.initializedStateWithGuide.initialized() or
initializedStateWithGuide.initializedStateWithGuide.notInitialized()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indent to show it is a part of the line above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it.


local lazy_load_if_possible = require "lazy_load_subdriver"
local sub_drivers = {
lazy_load_if_possible("aqara.roller-shade.t1s"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: 2 space indentation is our standard

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it.

Comment on lines +37 to +46
local function is_not_init(device)
if not device:get_field(INIT_STATE_REPORTED) then return false end

-- True if uninitialized; false if already initialized
local initialized = device:get_latest_state("main", initializedStateWithGuide.ID,
initializedStateWithGuide.initializedStateWithGuide.NAME) or 0
local ret = true
if initialized == initializedStateWithGuide.initializedStateWithGuide.initialized.NAME then ret = false end
return ret
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local function is_not_init(device)
if not device:get_field(INIT_STATE_REPORTED) then return false end
-- True if uninitialized; false if already initialized
local initialized = device:get_latest_state("main", initializedStateWithGuide.ID,
initializedStateWithGuide.initializedStateWithGuide.NAME) or 0
local ret = true
if initialized == initializedStateWithGuide.initializedStateWithGuide.initialized.NAME then ret = false end
return ret
end
local function is_not_init(device)
-- Only gate commands once the device has reported its init state at least once
return device:get_field(INIT_STATE_REPORTED) and
device:get_latest_state("main", initializedStateWithGuide.ID,
initializedStateWithGuide.initializedStateWithGuide.NAME) ~=
initializedStateWithGuide.initializedStateWithGuide.initialized.NAME
end

nit: Can be compressed/simplified

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the function based on your feedback.

Comment on lines +112 to +117
-- The position of this device is reported through the present value of the analog output
-- cluster, where 0 is fully closed and 100 is fully open. The lift percentage of the window
-- covering cluster is reported with the opposite polarity (100% = fully closed), so it is
-- ignored here to keep the parent Aqara handler from emitting an inverted shade level.
local function current_position_lift_percentage_handler(driver, device, value, zb_rx)
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function is unused

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it.

local reverseRollerShadeDir = capabilities["stse.reverseRollerShadeDir"]
local shadeRotateState = capabilities["stse.shadeRotateState"]
local setRotateStateCommandName = "setRotateState"
local directionReversal = "directionReversal"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unused

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it.

@github-actions

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants