cover position control#402
Conversation
caa3e83 to
0efd35e
Compare
0efd35e to
154c89c
Compare
|
Whoops, I think @LorandBiro was already working on this: LorandBiro/cover-position Nearly 100 (public) forks to track! 🙂 |
|
Thanks for tagging me! Yeah, there’s a large overlap, but both branches have some extras. I added more features around position control, my branch supports delays at the end positions, which makes the position calculation a bit more complex. You also added bug fixes that look important. I’m going to compare the two solutions in detail tonight. |
I will do also that tomorrow ;-) |
I think yours is more robust that mine ! I think mine can be dropped. I will test your branch on my device. |
LorandBiro
left a comment
There was a problem hiding this comment.
Hey,
I took a look at your PR and left a few questions. I’d really appreciate your thoughts on those when you have a moment, as they could help improve my implementation as well.
Also, I’m sorry we ended up working on the same feature in parallel. I’ve had a branch for this for a while, but I was slow to open a PR. In hindsight, sharing it earlier as a draft might have made the overlap more visible.
| | **`R`** | Relay / Triac | • Output <br> • Non-latching: `RC1` - 1 pin: on when high <br> • Latching: `RC2C3` - 2 pins: pulse on, pulse off <br> • Add `i` to invert (active-low): `RC1i` | | ||
| | **`X`** | Cover Switch | • User input for cover control <br> • Format: `XA2B3u` - 2 pins + pull resistor: open button, close button | | ||
| | **`C`** | Cover | • Motor control for curtains/blinds/shades <br> • Format: `CA2B3` - 2 pins: open relay, close relay | | ||
| | **`C`** | Cover | • Motor control for curtains/blinds/shades <br> • Format: `CA2B3` - 2 pins: open relay, close relay <br> • Add `i` to invert both relays (active-low): `CA2B3i` | |
There was a problem hiding this comment.
Is this feature intended to invert the relay states, or to invert the signal that controls the relay? Interpreting it as inverting the relay states sounds like flipping the open/closed states, which doesn’t really make sense for motors.
Further down, it mentions that it inverts the output. That wording is a bit ambiguous to me, I instinctively think of the physical output of the device, rather than the firmware’s logic. I’m not entirely sure how to phrase this better, but I wanted to share my concern.
| motorReversal: {ID: 0xff01, type: Zcl.DataType.BOOLEAN, write: true}, | ||
| }, | ||
| }), | ||
| {% endif %} |
There was a problem hiding this comment.
I noticed you moved away from this custom cluster definition and unified a few things in the file. Did you run into any issues with it?
I’d need to retest to be certain, but from what I remember, the reporting UI didn’t work perfectly without these custom cluster definitions. Reporting itself was functioning, but the UI wasn’t aware of it and couldn’t display the attributes properly.
| valueMax: 60000, | ||
| unit: "ms", | ||
| entityCategory: "config", | ||
| }), |
There was a problem hiding this comment.
I also considered supporting separate open and close times, but after testing my own shutters, I found the difference to be negligible. Because of that, I decided to simplify the scope of my PR.
Do you personally see a need for this? Do you think it’s something others would find useful? My concern is that it might unnecessarily bloat the UI.
That said, if you and others would like this in the firmware, I’d be happy to add it back to my PR.
There was a problem hiding this comment.
On my roller blinds, the difference between opening and closing is over two seconds depending on the window size. They actually close faster.
There was a problem hiding this comment.
Then I’ll add this back to my version and open a draft PR with details on how to test it.
| uint16_t attribute_id) { | ||
| if (cover_switch_cluster_by_endpoint[endpoint] == NULL) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Could you help me understand the purpose of this guard? In what situations would this actually occur?
I noticed that the switch_cluster_callback_attr_write_trampoline and relay_cluster_callback_attr_write_trampoline functions don’t include this guard, which made me wonder why it’s needed here.
| return HAL_ZIGBEE_CMD_SKIPPED; | ||
| } | ||
| cover_go_to_lift_percentage(cluster, ((uint8_t *)cmd_payload)[0]); | ||
| break; |
There was a problem hiding this comment.
Have you tested this with Zigbee2Mqtt? When I worked on this part, I had to make two changes in zigbee_zcl.c to get the payload through. I just want to make sure I’m not introducing unnecessary complexity if it’s not needed.
Cover position control (GoToLiftPercentage)
Summary
Adds time-based position tracking and
GoToLiftPercentagesupport for cover devices. Once calibrated with travel times, the cover can move to an absolute position (0–100%) and stop automatically.Changes
1. Position tracking (
cover_cluster.c,cover_cluster.h)0xff02, uint16, ms) and CLOSE_TIME (0xff03, uint16, ms). Setting both to a non-zero value enables position tracking.0x05): computes run time from current position and travel time, starts the motor, and schedules a stop task. Usesmax(run_ms, RELAY_MIN_SWITCH_TIME_MS)to guarantee the stop is never deferred by motor protection.2. Config parser bug fixes (
config_parser.c)pressed_when_highwas only set for pull-down buttons in theXhandler (cover switch) and not set at all forB(reset button). Both are now derived consistently from the pull direction: pull-down → pressed when high, pull-up → pressed when low.on_highwas hardcoded to1for bothR(relay) andC(cover relay) handlers. Both now respect anisuffix in the config string to support inverted relay outputs.3. Zigbee2MQTT converter template (
switch_custom.js.jinja)0x30,0x20, etc.) withZcl.DataType.*named constants throughout.deviceAddCustomClusterblock forclosuresWindowCovering— thewindowCoveringmodernExtend already handles cluster setup; custom attributes are now accessed by explicit ID.0x0008) to the configure-reporting block alongside the existingmovingattribute.movingandmotorReversalattribute references from named strings to explicit{ID, type}objects, consistent with the new approach.4. Defensive NULL guards (
switch_cluster.c,cover_switch_cluster.c,cover_cluster.c)Attribute-write trampolines now guard against being called for an endpoint that was never registered, preventing a NULL dereference if the Zigbee stack delivers a write to an unexpected endpoint.
5. New device entry (
device_db.yaml)Added MODULE_LORATAP_TS130F_1GANG (LoraTap SC500ZB-v4, 1-gang curtain module, status: in_progress).
Tests
Verification