Bug: Scale/Number parameters lose checked state on app restart
Summary
Parameters using ScaleRow (e.g., brightness_step_pct) become unchecked after restarting StreamController, while ComboRow parameters (e.g., color_name) persist correctly. The saved value remains in the settings JSON but the checkbox is not restored.
Steps to Reproduce
- Add a Perform Action button
- Set domain:
light, action: turn_on, entity: any light entity
- Check
brightness_step_pct and set a value (e.g., 11)
- Restart StreamController
- Open the button config --
brightness_step_pct is unchecked
Expected Behavior
All checked parameters should remain checked after restart, regardless of their widget type.
Root Cause
During startup, Page.initialize_actions() calls both load_initial_generative_ui() (deferred via GLib.idle_add) and on_ready(). When the deferred load_initial_generative_ui runs, it calls load_initial_ui() on every GenerativeUI object, including the action combo row.
The action combo's load_initial_ui triggers _handle_value_changed with trigger_callback=True, which invokes _on_change_action. This method unconditionally clears all parameters -- there is no guard checking whether the action actually changed:
|
@requires_initialization |
|
def _on_change_action(self, _, __, ___) -> None: |
|
"""Execute when the action is changed.""" |
|
self.settings.clear_parameters() |
|
parameters_helper.load_parameters(self) |
|
self._reload() |
Both on_change_domain and on_change_entity guard against same-value triggers, but _on_change_action is missing this guard -- so it fires even when the action hasn't changed, wiping saved parameters on every startup.
|
@requires_initialization |
|
def on_change_domain(self, _, domain, old_domain): |
|
"""Execute when the domain is changed.""" |
|
domain = str(domain) if domain is not None else None |
|
old_domain = str(old_domain) if old_domain is not None else None |
|
|
|
if old_domain != domain: |
|
entity = self.settings.get_entity() |
|
if entity and self.track_entity: |
|
self.plugin_base.backend.remove_tracked_entity(entity, self.refresh) |
|
self.settings.reset(domain) |
|
self.entity_combo.remove_all_items() |
|
|
|
if domain: |
|
self._load_entities() |
|
|
|
self.set_enabled_disabled() |
|
@requires_initialization |
|
def on_change_entity(self, _, entity, old_entity): |
|
"""Execute when the entity is changed.""" |
|
entity = str(entity) if entity is not None else None |
|
old_entity = str(old_entity) if old_entity is not None else None |
|
|
|
if old_entity == entity: |
|
return |
|
|
|
super().on_change_entity(_, entity, old_entity) |
|
|
|
if entity: |
|
parameters_helper.load_parameters(self) |
|
|
|
self._reload() |
Why ComboRow parameters survive
After clear_parameters wipes everything, load_initial_ui is called on the newly created parameter rows:
-
ComboRow parameters (e.g., color_name): ComboRow.load_initial_ui() calls widget.set_selected_item() without @signal_manager, so the GTK notify::selected signal fires, triggering ParameterComboRow._value_changed which re-checks the checkbox and re-saves the parameter.
-
ScaleRow parameters (e.g., brightness_step_pct): GenerativeUI.load_initial_ui() calls set_ui_value() with @signal_manager (signals disconnected), so no GTK signal fires. The checkbox stays unchecked and the parameter is not re-saved.
Suggested Fix
Add a same-value guard to _on_change_action, matching the existing pattern in the other on_change_* callbacks:
@requires_initialization
def _on_change_action(self, _, action, old_action) -> None:
"""Execute when the action is changed."""
action = str(action) if action is not None else None
old_action = str(old_action) if old_action is not None else None
if old_action == action:
return
self.settings.clear_parameters()
parameters_helper.load_parameters(self)
self._reload()
Affected Parameter Types
| Widget Type |
Example Param |
Persists? |
Why |
ParameterComboRow |
color_name |
Yes |
Signal leak re-saves it |
ParameterScaleRow |
brightness_step_pct, brightness_pct |
No |
Signal-managed, no re-save |
ParameterEntryRow |
free-text params |
No |
Signal-managed, no re-save |
ParameterSwitchRow |
boolean params |
No |
Signal-managed, no re-save |
Environment
- StreamController installed via AUR (
streamcontroller-git)
- HomeAssistantPlugin from git
- Home Assistant with LIFX light entities
Bug: Scale/Number parameters lose checked state on app restart
Summary
Parameters using
ScaleRow(e.g.,brightness_step_pct) become unchecked after restarting StreamController, whileComboRowparameters (e.g.,color_name) persist correctly. The saved value remains in the settings JSON but the checkbox is not restored.Steps to Reproduce
light, action:turn_on, entity: any light entitybrightness_step_pctand set a value (e.g.,11)brightness_step_pctis uncheckedExpected Behavior
All checked parameters should remain checked after restart, regardless of their widget type.
Root Cause
During startup,
Page.initialize_actions()calls bothload_initial_generative_ui()(deferred viaGLib.idle_add) andon_ready(). When the deferredload_initial_generative_uiruns, it callsload_initial_ui()on everyGenerativeUIobject, including the action combo row.The action combo's
load_initial_uitriggers_handle_value_changedwithtrigger_callback=True, which invokes_on_change_action. This method unconditionally clears all parameters -- there is no guard checking whether the action actually changed:HomeAssistantPlugin/actions/perform_action/perform_action.py
Lines 115 to 120 in 2ffddc9
Both
on_change_domainandon_change_entityguard against same-value triggers, but_on_change_actionis missing this guard -- so it fires even when the action hasn't changed, wiping saved parameters on every startup.HomeAssistantPlugin/actions/cores/base_core/base_core.py
Lines 101 to 117 in 2ffddc9
HomeAssistantPlugin/actions/perform_action/perform_action.py
Lines 99 to 113 in 2ffddc9
Why ComboRow parameters survive
After
clear_parameterswipes everything,load_initial_uiis called on the newly created parameter rows:ComboRow parameters (e.g.,
color_name):ComboRow.load_initial_ui()callswidget.set_selected_item()without@signal_manager, so the GTKnotify::selectedsignal fires, triggeringParameterComboRow._value_changedwhich re-checks the checkbox and re-saves the parameter.ScaleRow parameters (e.g.,
brightness_step_pct):GenerativeUI.load_initial_ui()callsset_ui_value()with@signal_manager(signals disconnected), so no GTK signal fires. The checkbox stays unchecked and the parameter is not re-saved.Suggested Fix
Add a same-value guard to
_on_change_action, matching the existing pattern in the otheron_change_*callbacks:Affected Parameter Types
ParameterComboRowcolor_nameParameterScaleRowbrightness_step_pct,brightness_pctParameterEntryRowParameterSwitchRowEnvironment
streamcontroller-git)