Skip to content

Initialise filter_sensor with historical values#13075

Merged
balloob merged 29 commits intohome-assistant:devfrom
dgomes:filter_history
Apr 7, 2018
Merged

Initialise filter_sensor with historical values#13075
balloob merged 29 commits intohome-assistant:devfrom
dgomes:filter_history

Conversation

@dgomes
Copy link
Copy Markdown
Contributor

@dgomes dgomes commented Mar 10, 2018

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):

  - platform: filter
    name: "events"
    entity_id: sensor.power_smart_meter
    history_period: 00:15 
    filters:
      - filter: throttle
        window_size: 1
        precision: 2

Checklist:

  • The code change is tested and works locally.
  • Local tests pass with tox. Your PR cannot be merged unless tests pass
  • Documentation added/updated in home-assistant.github.io
  • Tests have been added to verify that the new code works.

Comment thread tests/components/sensor/test_filter.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace after ','

Comment thread tests/components/sensor/test_filter.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuation line over-indented for visual indent

Comment thread tests/components/sensor/test_filter.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace after ','

Comment thread tests/components/sensor/test_filter.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuation line over-indented for visual indent

@B1tMaster

This comment has been minimized.

@dgomes
Copy link
Copy Markdown
Contributor Author

dgomes commented Mar 13, 2018

@B1tMaster your comment is not related to the issue :)

I'm open to discuss further enhancements, lets please move this discussion to the forums ;)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use dt_util.utcnow() - self._history_period instead

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use STATE_UNKNOWN. Use None instead, HA will do the right thing

Comment thread tests/components/sensor/test_filter.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't really testing the history feature 😅 it was just acknowledging the dependency

Will workout a proper test 👍

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trailing whitespace

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuation line under-indented for visual indent

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (101 > 79 characters)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'datetime.datetime' imported but unused

Copy link
Copy Markdown
Member

@balloob balloob Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:
    return

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this should be configurable. We should just fetch based on the maximum window size of the filters.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then should we have at least some sane default ? For example, look for max window size or else set it to 30 minutes?

Copy link
Copy Markdown
Contributor Author

@dgomes dgomes Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But wouldn't you still want to pass a window size when it's available ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Should I open a new PR for the new function or use this PR (since its related) ?
  2. 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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the two PR's started at different times and will now require adequate merging

@dgomes dgomes requested a review from a team as a code owner March 19, 2018 00:09
Comment thread tests/components/test_history.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line contains whitespace

Added get_last_state_changes()
Comment thread tests/components/sensor/test_filter.py Outdated
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redefinition of unused 'dt_util' from line 8

Comment thread tests/components/sensor/test_filter.py Outdated
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redefinition of unused 'dt_util' from line 8

# Conflicts:
#	homeassistant/components/sensor/filter.py
Comment thread tests/components/sensor/test_filter.py Outdated
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (84 > 79 characters)

Comment thread tests/components/sensor/test_filter.py Outdated

ts = dt_util.utcnow()
for val in raw_values:
self.values.append(ha.State('sensor.test_monitored', val, last_updated=ts))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (87 > 79 characters)

@robmarkcole
Copy link
Copy Markdown
Contributor

@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?

@dgomes
Copy link
Copy Markdown
Contributor Author

dgomes commented Mar 23, 2018

@robmarkcole Yes you are correct! New filters can access as much backlog as they require with timestamps.

@balloob
Copy link
Copy Markdown
Member

balloob commented Mar 25, 2018

@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.

@B1tMaster
Copy link
Copy Markdown
Contributor

B1tMaster commented Mar 25, 2018

@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 ?
How about numpy? Would be nice to have a few of the data-science libraries to be available for use inside HA.

@OttoWinter
Copy link
Copy Markdown
Member

OttoWinter commented Mar 25, 2018

@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

@dgomes
Copy link
Copy Markdown
Contributor Author

dgomes commented Mar 30, 2018

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 :) ?

@balloob
Copy link
Copy Markdown
Member

balloob commented Mar 31, 2018

There are a 105 open PRs…

Copy link
Copy Markdown
Member

@balloob balloob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok to merge once the isinstance usage is replaced with a variable to check the type.

@balloob balloob merged commit 286476f into home-assistant:dev Apr 7, 2018
@balloob balloob mentioned this pull request Apr 27, 2018
@dgomes dgomes deleted the filter_history branch May 7, 2018 22:05
@home-assistant home-assistant locked and limited conversation to collaborators Sep 5, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants