Repository navigation
Conversation
The XML database already describes what every keypad button does: its Press action carries presets whose assignments either set an output level directly (GOTO_LEVEL) or recall a scene in some area (GOTO_SCENE), which in turn holds level assignments. The parser skipped all of it, so a consumer holding a Button had no way to know which loads it drives. Parse it and expose it as `Button.affected_outputs`, a mapping of output integration id to the level the programming assigns. Scene references are resolved through a table built up front, because the area owning a scene is usually not the area owning the button that recalls it -- wall keypads tend to live in their own area. The keys are dependable: pressing the button can change exactly those outputs. That is enough to refresh the right subset after a press instead of querying every output in the system. The values are what the programming assigns, which is not always where the outputs land -- a toggle depends on current state, a raise/lower on how long it is held -- so they are documented as a prediction to confirm rather than as fact. No behaviour changes for existing consumers: the new constructor argument defaults to empty and nothing else reads it. Validated against a real HomeWorks QS project: 153 buttons, 112 outputs, 75 buttons with programming, the largest recalling a scene that touches 106 outputs across several areas. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The red checks are the same repository CI issue described in #133, not anything from this change: all seven jobs fail at Locally on this branch: full suite passes and |
|
Updated this branch to current master (including the CI trigger fix from #137). Local verification on the merged result passes: 74 unit tests and mypy. GitHub created fresh pull_request workflow runs, but they are waiting for repository-admin approval: Python application and Type Checking. Once approved, these will test head 8bd3f37 normally. |
|
Nice parsing work, but I want to understand the motivation before reviewing it. Zone monitoring is already on — So the "112 queries vs a median of 8" comparison is against a refresh that shouldn't need to happen at all. What are you seeing that makes it necessary? If you're subscribed and One bug regardless: the docstring says this reads the button's Press action, but |
A button is programmed per action: Press, Release, Hold and MultiTap can each drive a different set of outputs to different levels. The previous revision folded every action into one mapping, so a conflicting output took whichever level the XML happened to list last -- a value with no meaning. affected_outputs is now the union of output ids across actions, which is what a consumer needs to refresh the right subset after a button event. The level assignments move to affected_outputs_by_action, keyed by the action name, so a caller that knows which action fired can use the levels that belong to it. The fixture gains a button whose Press and Release drive the same output to conflicting levels; the old code could not have passed it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The behavior of my HomeWorks QS processor running OS 15.13.2 (June 2, 2023) motivates this PR. With #MONITORING,5,1 enabled, keypad ~DEVICE events were received normally. I then pressed a Palladiom keypad scene which changed DALI outputs. However, the session received no ~OUTPUT messages for those level changes. Keypad, LED, and occupancy notifications were present. Only the zone-level notifications were absent. Everything the session received across the whole capture: Outputs 57-60 read 0.00 before the press and 50.00 after it. Sixteen outputs changed. ?OUTPUT on the same session returns the correct levels, so the session is not being starved. As a result, Home Assistant's push-only lutron entities remained at their startup values. affected_outputs allows a caller to identify the outputs that may be changed by the button and query only those outputs. It is a fallback for this observed QS behavior, not a replacement for ~OUTPUT notifications on controllers where they work. I have not yet tested a direct GOTO_LEVEL/manual dimmer change because my contractor did not configure these functionalities for any button. I cannot test the behavior on these scenarios. You are right about the action merge, and I have fixed it. Press, Release, Hold and MultiTap are no longer folded together: affected_outputs is now the union of output ids, and the level assignments moved to affected_outputs_by_action, keyed by action name. The fixture now covers a button whose Press and Release drive the same output to conflicting levels. |
|
You should try #130
I've been looking for someone to test this change. It should fix the
status sync challenges with Homeworks but I don't have a system to test it
on.
…On Mon, Sep 14, 2026, 1:22 AM rqi14 ***@***.***> wrote:
*rqi14* left a comment (thecynic/pylutron#135)
<#135 (comment)>
The behavior of my HomeWorks QS processor running OS 15.13.2 (June 2,
2023) motivates this PR. With #MONITORING,5,1 enabled, keypad ~DEVICE
events were received normally. I then pressed a Palladiom keypad scene
which changed DALI outputs. However, the session received no ~OUTPUT
messages for those level changes. Keypad, LED, and occupancy notifications
were present. Only the zone-level notifications were absent.
Everything the session received across the whole capture:
8.6 TX ?MONITORING,5
8.6 ~MONITORING,5,1
136.5 ~DEVICE,138,1,3 <- keypad 138, component 1, press
136.9 ~DEVICE,146,81,9,1 <- LED on
Outputs 57-60 read 0.00 before the press and 50.00 after it. Sixteen
outputs changed. ?OUTPUT on the same session returns the correct levels, so
the session is not being starved.
As a result, Home Assistant's push-only lutron entities remained at their
startup values. affected_outputs allows a caller to identify the outputs
that may be changed by the button and query only those outputs. It is a
fallback for this observed QS behavior, not a replacement for ~OUTPUT
notifications on controllers where they work.
I have not yet tested a direct GOTO_LEVEL/manual dimmer change because my
contractor did not configure these functionalities for any button. I cannot
test the behavior on these scenarios.
You are right about the action merge, and I have fixed it. Press, Release,
Hold and MultiTap are no longer folded together: affected_outputs is now
the union of output ids, and the level assignments moved to
affected_outputs_by_action, keyed by action name. The fixture now covers a
button whose Press and Release drive the same output to conflicting levels.
—
Reply to this email directly, view it on GitHub
<#135?email_source=notifications&email_token=ACQARWTGU7QHOABUNTAUZ335O6TDVA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKNRWGEYTAMZQGQ22M4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-5661103045>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACQARWXF6IC47TBDIADTEPD5O6TDVAVCNFSNUABEKJSXA33TNF2G64TZHM3DENBTHEYDGMR3JFZXG5LFHM2TGMRTHA4TMNBXG6QXMAQ>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/ACQARWVPDYVL7ZMGPUIZT335O6TDVA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKNRWGEYTAMZQGQ22M4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJKTGN5XXIZLSL5UW64Y>
and Android
<https://github.com/notifications/mobile/android/ACQARWQEBXNDZQDWSOEYJZL5O6TDVA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKNRWGEYTAMZQGQ22M4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJLTGN5XXIZLSL5QW4ZDSN5UWI>.
Download it today!
You are receiving this because you commented.Message ID:
***@***.***>
|
|
Tried #130. It doesn't fix this, and testing it answered the question you raised above. I reproduced its architecture with raw telnet rather than the patched library: session A with the full Output 57 really did go 50 → 80 → 50, as the two queries confirm. Across the whole capture, 26 seconds, neither A nor B received an unsolicited That was a direct #130 also couldn't have applied here even if its premise held. The capture in my last comment was a physical keypad press against a passive session, so nothing originated from telnet and there was no originating session to exclude. One processor on one firmware, so I can't say whether this holds for QS in general. But on this one, a caller that wants current levels has to ask for them, which is what |
What this adds
Button.affected_outputs— a mapping of output integration id to the level thebutton's programming assigns.
The XML database already describes what every keypad button does. Its
Pressaction carries presets whose
PresetAssignments either set an output leveldirectly (
GOTO_LEVEL) or recall a scene in some area (GOTO_SCENE), which inturn holds level assignments. The parser skipped all of it, so a consumer
holding a
Buttonhad no way to know which loads it drives.Scene references are resolved through a table built up front, because the area
that owns a scene is usually not the area that owns the button recalling it —
wall keypads tend to live in their own area.
Why it is useful
A consumer that learns a button was pressed currently has two options: refresh
every output in the system, or refresh nothing. With this it can refresh
exactly the outputs that button can change.
On the project I tested against that is the difference between 112 queries and
a median of 8.
It also opens the door to updating state optimistically on a press and
confirming afterwards, though that is the caller's choice — see the caveat
below.
What the values do and don't mean
The keys are dependable: pressing the button can change exactly those
outputs and no others.
The values are what the programming assigns, which is not always where the
outputs land. A toggle button's result depends on the current state, and a
raise/lower button's depends on how long it is held. The docstring says so, and
callers that need certainty should use the keys and query.
Compatibility
No behaviour change for existing consumers. The new constructor argument
defaults to empty, and nothing in the library reads it.
Testing
Four tests in
tests/test_parser.pyagainst a new fixture covering a directGOTO_LEVELassignment, aGOTO_SCENEresolved across areas, a button with noprogramming, and that the returned mapping is a copy.
Full suite: 73 tests pass,
mypyclean.Also validated against a real HomeWorks QS project — 153 buttons, 112 outputs,
75 buttons with programming, the largest recalling a scene touching 106 outputs
across several areas. Results matched an independently written parser on all 75.
🤖 Generated with Claude Code