-
-
Notifications
You must be signed in to change notification settings - Fork 33k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure all mqtt messages report state to core #140001
base: dev
Are you sure you want to change the base?
Conversation
Core will filter the state of entities and report state changed events in case of changed data and state reported event if no data was changed. This allow helpers like derivate and integrate to work correctly with constant entities as well as things like last_reported.
Hey there @emontnemery, @jbouwh, @bdraco, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
This was originally introduced in #100438 but has since been reworked a bit. Was any perf measurements done during that pull? |
@elupus Please update the PR title, we do not use conventional commits. Thanks 👍 ../Frenck |
I'd like to have a closer look at this change before it is merged. |
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
When a payload arrives an is processed by the entity platform the attribute filter is used to detect if any attribute was changed. If not, the method returns. Adding a state write would cause additional overhead. To add it back where it was in the past would require a major refactoring. It was never intended to always do a state write an all entities when a message comes in. |
There is an open issue with a test still. Seems the event entity relied on this behaviour in test_handling_retained_event_payloads which i can't fully figure out. Sort of seem it ignored messages that did not change the event data. But sort of did it in the background. I do understand that this is a performance tradeoff. I kinda do like last_reported info and being able to rely on reported events. I suppose it could be opt-in, but those type of config choices are hard for anybody to get right. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While getting last_reported
is nice, there are so many power sensors (mostly from Z2M) on the market that flood the state machine with data we would effectively be forcing those users to buy better hardware or move to a different solution. I think this should be opt-in.
BDraco's concern is a valid one. Maybe wise to rate limit 'last_reported' updates to something like max 1 per second per device |
Not sure that will be enough, as the MQTT protocol has some overhead in continuesly reporting states and we do not want to write states when they are not changes. For sensors that need consequent writing we have |
Basically, I'm fine to use something like From performance perspective I seriously doubt that not updating
|
Another note to make is that a lot of MQTT platforms use value templates. In many cases, there is no active update, when the template returns empty. This PR is not addressing this. E.g.: core/homeassistant/components/mqtt/climate.py Lines 720 to 722 in 2985f08
This pattern is seen at many places. Payloads contain details that are to be ignored as they are not in the context of the entity. |
Openened: home-assistant/home-assistant.io#37856 I think we if we want to enable state writes it should be an opt in instead. |
Think about all the objects, syscalls (time and others), dict merges that need to be created to fire And that's far from everything that has to happen to fire that event. While we have done a great job optimizing all that, very little of it has a native code implementation besides generating the ulid (ulid-transform) and hashing (fnv-hash-fast) in the recorder. The rest is implemented mainly in Python code, which is hard to optimize without rewriting most core objects and event paths into a better-performing language. While that is possible, it would make the core more challenging to maintain. Even if we move all the expensive object creation to something like Cython, the objects still have to be passed back to Python, limiting optimizing for this path. |
@bdraco |
If we want to make it optional it should be opt out of state reported not opt in. If we have a feature that by default large integrations ignore, nothing can rely on it. We could maybe default it to on, but on upgrade default it to off. Ie new users get it on by default. Old users stay on off untill they enable. We could also remember all unchanged entities and trigger write on those with a delay, but that get complicated fast. |
That's already the case, as what constitutes a reported state will vary widely between each integration. A typical pattern for integrations and libs is suppressing duplicate data when nothing changes. Suppose I think about the integrations I use that do this. In that case, it includes: nearly all passive Bluetooth devices, anything that relies on Bluetooth RSSI updates, Bluetooth advertisements that don't change (some of that happens at the BlueZ level), HomeKit accessory protocol updates, and ESPHome does it on device for various sensor reads as well as the integration. That's far from an exhaustive list, and only the most common ones I can think of off the top of my head. |
Im leaning towards abandoning this change. jbouwh might have something better when it comes to opting in in the works. However on a tangent. Should there be a capabilities flag or something to indicate if an entity can report last reported? We could indicate in gui based on that and helpers could take it into account. What do you guys think? |
Not suppressing state changes is today mainly of interest to sensor helpers to ensure correct calculations since we don't show the last_reported timestamp in frontend. We could also make this an entity option, configurable by the user via the more details dialog.
What does flood mean in this case? |
@bdraco You mention this work needs to be done:
I agree with this concern, although we try to do this as lazily as possible, for example only creating some objects if there are subscribers to
We have implemented a lot of restrictions on subscribing to
True, but as you also mention, this is very highly optimized. For starters, core/homeassistant/components/recorder/core.py Lines 1105 to 1107 in 3675322
This means there is at worst a doubling of database accesses (if every state change needs the previous state's last_reported timestamp to be updated), no matter how many redundant state writes an entity causes.
I don't mean the concerns are not valid, I just want to point out that we have spent a lot of effort on minimizing the impact of spammy entities. |
I'm more concerned about this part of the update cycle than the other parts that we spent all the time optimizing. Specifically I don't have a good way to optimize those without invasive changes (ie Cython, Rust or something similar). The database update is still mildly concerning as well because updates are so much more expensive than inserts since they have to lookup old data as well. |
For some perspective I took a non-scientific look at a what would happen if the duplicate state writes suppression was removed from the most common push integrations I use: Passive Bluetooth entities - additional ~700 state writes per minute Additionally I have unifi (network) integration disabled because it generates far too many state writes already and produces a noticeable lag on my Blue when it's turned on with a network size of ~300 devices. |
There is a great discussion in #140318 (comment) that is relevant to this The problem with these types of changes is that we really don’t know what the stability and performance impact on users will be, as we have no telemetry data. As a result, we have to rely on past experiences and data that users have manually provided when they encountered issues which is inherently a small sample size. This makes it difficult to make an informed decision, as there will always be users who end up being pushed over the edge as we try to gather more data. Without telemetry, it’s hard to know how many people will be negatively impacted, making it tough to make a well-informed choice. Ultimately, we have to rely on the assumption that we didn’t overwhelm too many users with each change, and our users find out the hard way when we’re wrong. |
Proposed change
Core will filter the state of entities and report state changed events in case of changed data and state reported event if no data was changed.
This allow helpers like derivate and integrate to work correctly with constant entities as well as things like last_reported.
Type of change
Additional information
Checklist
ruff format homeassistant tests
)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest
.requirements_all.txt
.Updated by running
python3 -m script.gen_requirements_all
.To help with the load of incoming pull requests: