Skip to content

WWST: add Zemismart ZM25Z window treatment support - #3280

Open
zemismart-dev wants to merge 2 commits into
SmartThingsCommunity:mainfrom
zemismart-dev:codex/zm25z-wwst-certification
Open

zemismart-dev wants to merge 2 commits into
SmartThingsCommunity:mainfrom
zemismart-dev:codex/zm25z-wwst-certification

Conversation

@zemismart-dev

@zemismart-dev zemismart-dev commented Oct 16, 2026 •

Copy link
Copy Markdown

Type of Change

  • WWST Certification Request
    • 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

Add support for the externally powered Zemismart ZM25Z roller shade motor in zigbee-window-treatment. Its advertised Power Configuration support otherwise selects a battery profile, despite this tested product having no battery. Map _TZE200_cirjrpxe / TS0301 to the existing window-treatment-profile, retaining window shade control, position, preset, relative step, firmware update, and refresh capabilities.

The new sub-driver applies only to this fingerprint with a profile without battery. It suppresses unsolicited BatteryVoltage/BatteryPercentageRemaining events in that configuration and uses standard Window Covering commands and position reads. It does not rewrite the device's reported power source. The device advertises manufacturer-specific cluster 0xEF00; this implementation does not use it. Please review that distinction against the custom-cluster submission criterion.

The implementation also:

  • Declares refresh in the parent driver's supported capabilities, fixing rejection of the existing profile during driver switching.
  • Clears a relative-step target after an intervening absolute command, preset, open, close, or pause, while preserving rapid consecutive step accumulation.
  • Keeps position trust volatile. Startup, conflicting feedback, invalid position values, and a Stop boundary require static confirmation. Two equal, valid position ReadAttributeResponses from separate read rounds establish a static state; Reports alone cannot restore trust. Reads are separated by at least two seconds, with at most three requests per 30-second confirmation session. These are engineering parameters, not certification or travel-time limits.
  • Retains the last confirmed percentage while the shade state is unknown. An unconfirmed device rejects movement requests and performs reads instead; rejected movement is never queued or replayed. Pause remains available. During an authorized movement, strictly directional progress can renew a 30-second progress-silence budget; repeated commands or duplicate values cannot. Target feedback requires static confirmation before publishing completion.
  • Invalidates cancelled timer callbacks, including after device removal, and revokes trust on local send failures. Shared helper changes concern step-cache/timer cleanup; the new feedback policy is confined to the matching sub-driver.

Fingerprint scope requiring review: a separate historical unit recorded as ZM15B uses the same manufacturer/model and firmware value (00000049). No reliable product-variant discriminator has been established. This exact fingerprint therefore also selects the profile without battery when another matching unit is newly paired. Tests preserving an already assigned battery profile do not protect fresh pairing of such units. This request covers ZM25Z only; the mapping's effect on other matching products needs an agreed resolution before merge/catalog release. We do not claim that the fingerprint uniquely identifies the tested power variant.

Summary of Completed Tests

  • SmartThings Test Suite Full Integration XXEUAAMJBV, 2026-10-16: 23/23 passed; zero failures, skips, user exclusions, or errors. Duration: 00:14:15. Tested production revision: 8d4f448895ab89f53610cf650e0d5da3fe5db2c2; installed package version: 2026-10-16T03:24:03.230350782. Fresh onboarding selected window-treatment-profile without battery. Control, 0/50/100 positions, relative steps, preset, the required refresh-capability presence check, firmware checks, Unknown, and formal offboarding completed. Functional refresh/read behavior was additionally exercised in the separate real protocol and power-cut checks below.
  • Formal Unknown case: one ordinary standard pause caused the production driver's pending static-confirmation state to become unknown; two subsequent position reads of 43 restored partially open. This case did not include a power cut.
  • Separate real power-cut/recovery check, same package and physical sample: three read requests received no position response and produced unknown while retaining 43%. After power was restored, unsolicited 0/43 reports did not produce a false 0%, closed, or moving state. Two successful reads of 43 restored the static state. This recovery check sent no motion commands; sampled camera evidence showed the output remaining stationary.
  • The final-version Full Integration exercised 50 → step +10 = 60 → absolute 50 → step −10 = 40. Camera observations supported visible movement/stop and the manual preset checks; percentages are protocol readbacks, not independent mechanical position measurements.
  • Driver integration tests: API 19: 307/307; API 21: 303/307. The four API 21 failures are the existing VIVIDSTORM upper/lower Setlimit cases (Too many args for Mode.setMode), also reproduced on unmodified upstream. The final 49 feedback tests pass on both SDKs, including the strengthened real removed → SDK deleted callback case. That final test-only strengthening was rerun as the 49-case focused suite; production source was unchanged from the full-suite run. Lua 5.3 syntax, Luacheck, and whitespace checks passed.
  • Final test applicability update (test files only): 70 target tests pass on API 15, 19 and 21. Thirteen cases exercise the stock step helper’s API 15 named-argument command-injection dependency and now declare the same min_api_version = 15 as upstream step tests. The unfiltered API 14 harness reports 57/70 because it ignores this metadata; its 13 failures match those 13 API-15-only cases exactly. All 57 applicable cases pass. Additional independent preset, zero-step and non-step removal cases preserve API 14 coverage. Production driver, configuration, profiles, fingerprints and the installed/tested package are unchanged; only test applicability and coverage changed after the full integration run.

Physical testing used an unloaded sample with temporary travel limits. It does not establish rated-load endurance or full production travel coverage. The two-read policy provides bounded consistency checking, not proof of radio freshness or mechanical truth; repeated identical incorrect responses remain a protocol limitation. Passing these tests is evidence for review, not a claim of completed WWST certification.

Use the standard profile without battery and confirm position feedback before
allowing motion after startup or inconsistent reports. Preserve step targets
and invalidate stale callbacks safely across device removal.
Match the stock step helper minimum API 15 for the thirteen tests that
exercise named-argument command injection. Retain API 14 coverage for
non-step removal callbacks, pure preset and zero-step behavior.

No production driver, profile, fingerprint or installed package changes.
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.

1 participant