LevoitSwitch: set has_state on publish to match Select/Number behavior#31
Open
TheDave94 wants to merge 1 commit into
Open
LevoitSwitch: set has_state on publish to match Select/Number behavior#31TheDave94 wants to merge 1 commit into
TheDave94 wants to merge 1 commit into
Conversation
Switch::publish_state in core ESPHome sets the public `state` field and fires callbacks but does not flip has_state_ on EntityBase. Select::publish_state and Number::publish_state both call set_has_state(true). The asymmetry breaks any caller that uses `if (entity->has_state())` to decide whether the entity carries a fresh user-supplied value worth preferring over a cached default — the check works for select / number but always returns false for switch, even after the user has just toggled it and even after the decoder published the device's reported value. Two paths fixed: LevoitSwitch::write_state — explicit set_has_state(true) after publish_state(state). Handles the user-toggle path (HA service → Switch::turn_on → LevoitSwitch::write_state → on_switch_command). Levoit::publish_switch — set_has_state(true) hoisted above the dedup early-return `if (sw->state == state)`. A decoder publish whose value matches the entity's default (e.g. first decoded false against default sw->state=false) would otherwise skip publish_state entirely and leave has_state_ at false for the rest of the session. No behavior change for callers that don't use has_state(): the public `state` field, callbacks, and ControllerRegistry notifications work exactly as before.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Switch::publish_statein core ESPHome sets the publicstatefield but does not fliphas_state_onEntityBase, unlikeSelect::publish_stateandNumber::publish_statewhich both callset_has_state(true).For callers that use
if (entity->has_state())as a guard — typically to decide whether an entity holds a fresh published value worth preferring over a cached default — the check works for select and number but always returns false for switch. The bug is silent: the publicstatefield updates correctly, callbacks fire, the device behaves as expected; only code that explicitly checkshas_state()sees stale results.Fix
Two paths get explicit
set_has_state(true)calls:LevoitSwitch::write_state— after the optimisticpublish_state(state). Handles the user-toggle path (HA service →Switch::turn_on→LevoitSwitch::write_state→on_switch_command).Levoit::publish_switch— hoisted above the dedup early-returnif (sw->state == state). Without this, a decoder publish whose value happens to match the entity's default-initialized state would skippublish_stateentirely and leavehas_state_at false forever.Behavior change
None for callers that don't use
has_state(). The publicstatefield, value-change callbacks, andControllerRegistrynotifications work exactly as before.Context
Discovered while developing additional Vital 200S Pro support that uses
has_state()to distinguish "user just toggled this entity" from "never published yet" in a command builder. The asymmetry meant switches always took the "cached default" branch and the user's new value was silently discarded over the wire. The fix is independent of any Vital-specific work and applies to upstream main directly.Verified by building against upstream main and flashing to a Vital 200S Pro running MCU FW 2.0.0; switches now correctly report
has_state()=trueafter both user toggles and decoder publishes.