Initialise filter_sensor with historical values#13075
Initialise filter_sensor with historical values#13075balloob merged 29 commits intohome-assistant:devfrom
Conversation
There was a problem hiding this comment.
continuation line over-indented for visual indent
There was a problem hiding this comment.
continuation line over-indented for visual indent
This comment has been minimized.
This comment has been minimized.
|
@B1tMaster your comment is not related to the issue :) I'm open to discuss further enhancements, lets please move this discussion to the forums ;) |
There was a problem hiding this comment.
Use dt_util.utcnow() - self._history_period instead
There was a problem hiding this comment.
You're inside an async function and are calling a sync function: move this to the executor:
from functools import partial
history_list = await self.hass.async_add_job(partial(history.state_changes_during_period, self.hass, start, entity_id=self._entity))(you have to use partial because of the keyword parameter)
There was a problem hiding this comment.
Don't use STATE_UNKNOWN. Use None instead, HA will do the right thing
There was a problem hiding this comment.
This doesn't test anything. I would expect a new test that mocks history.state_changes_during_period to return a list of state objects that would then influence the filter data after setup.
There was a problem hiding this comment.
I wasn't really testing the history feature 😅 it was just acknowledging the dependency
Will workout a proper test 👍
There was a problem hiding this comment.
continuation line under-indented for visual indent
There was a problem hiding this comment.
line too long (101 > 79 characters)
There was a problem hiding this comment.
'datetime.datetime' imported but unused
There was a problem hiding this comment.
We should not add this. Instead, check if history component is loaded inside the added_to_hass callback and only execute restore logic if it is. Home Assistant will make sure that if the user wants to enable the history component that it is set up prior to the sensor component.
Check like this:
if 'history' not in self.hass.config.components:
returnThere was a problem hiding this comment.
I don't think that this should be configurable. We should just fetch based on the maximum window size of the filters.
There was a problem hiding this comment.
Issue is: some filters have a time window, others have a states window (number of states in the window).
- I can agree when the filter has a time window
- If there is a states window I don't know the period of the sensor to derive the history_period (some sensors aren't even periodic) so my option was to let the user take control.
There was a problem hiding this comment.
But then should we have at least some sane default ? For example, look for max window size or else set it to 30 minutes?
There was a problem hiding this comment.
Can I work on the history component and add a:
def get_last_state_changes(hass, number_of_states, entity_id=None):
?
This method would basically query all previous states, order them descending, and limit the returned results to number_of_states. The results set would include the datetime of each state.
This method would enable me to solve this issue.
There was a problem hiding this comment.
But wouldn't you still want to pass a window size when it's available ?
There was a problem hiding this comment.
- Should I open a new PR for the new function or use this PR (since its related) ?
- Being able to determine the window size, I can't see any use case in which the user would define it's own window. Either he would define a larger window (wastes states) or a smaller window (would still be useful but would not properly restore the filter states)
There was a problem hiding this comment.
I would not expect users to configure a window directly for this feature, however the user might define a window size for other filters, like time_sma.
This PR is fine.
There was a problem hiding this comment.
Due to chaining there is only 1 window for all filters in the chain.
The code I will provide will query the window (time/number of state) of all used filters in the filter sensor. Merge all the states (probably through a set()) and initialize all the filters in the chain with the same states, thus reproducing the previous state.
There was a problem hiding this comment.
I'm not sure, but this might not work too well with #13104; because in there you're using now = int(dt_util.utcnow().timestamp()) even though the state changes are from the past. I think you could use the existing State#last_updated field.
There was a problem hiding this comment.
Yes, the two PR's started at different times and will now require adequate merging
Added get_last_state_changes()
| from homeassistant.setup import setup_component | ||
| from tests.common import get_test_home_assistant, assert_setup_component | ||
| import homeassistant.core as ha | ||
| import homeassistant.util.dt as dt_util |
There was a problem hiding this comment.
redefinition of unused 'dt_util' from line 8
| from homeassistant.setup import setup_component | ||
| from tests.common import get_test_home_assistant, assert_setup_component | ||
| import homeassistant.core as ha | ||
| import homeassistant.util.dt as dt_util |
There was a problem hiding this comment.
redefinition of unused 'dt_util' from line 8
# Conflicts: # homeassistant/components/sensor/filter.py
| state = self.hass.states.get('sensor.test') | ||
| self.assertEqual('20.25', state.state) | ||
| for value in self.values: | ||
| self.hass.states.set(config['sensor']['entity_id'], value.state) |
There was a problem hiding this comment.
line too long (84 > 79 characters)
|
|
||
| ts = dt_util.utcnow() | ||
| for val in raw_values: | ||
| self.values.append(ha.State('sensor.test_monitored', val, last_updated=ts)) |
There was a problem hiding this comment.
line too long (87 > 79 characters)
|
@dgomes this is a very welcome PR. If I've understood correctly, it will return historical data as an array which is ideal for implementing the various scipy filters. I'm assuming the time stamps are available? |
|
@robmarkcole Yes you are correct! New filters can access as much backlog as they require with timestamps. |
|
@robmarkcole note that we will not accept scipy as a requirement for the filter platform. It works without any requirement now and that's how it should stay. |
|
@balloob With open source scipy, one can develop so many new things related to ML, AI, data analytics. What is the reason of such hard stance against a most popular library for data-science ? |
|
@B1tMaster We already had that discussion here: #12506 (comment). In short, there's a difference between making it a core and a platform dependency + scipy is just to big and difficult to install to put in as a core dependency, because those have to be installed no matter if you use the features or not. Please keep further discussion limited to this PR. + Not as a filter dependency since the filter platform is probably used quite a.bit |
|
People are starting to work new filters, which will be impacted by this PR. It's been 5 days since the last review, can we get some love :) ? |
|
There are a 105 open PRs… |
balloob
left a comment
There was a problem hiding this comment.
ok to merge once the isinstance usage is replaced with a variable to check the type.
Description:
Initialise filter sensor with historical values, therefore limiting the impact of restarts.
When HA is restarted the filter looses its current state (window), requiring a new running period until the filter becomes stable again.
This PR loads historical values that enable the filters to reach previous state upon initiation.
Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.io#4883
Example entry for
configuration.yaml(if applicable):Checklist:
tox. Your PR cannot be merged unless tests pass