Switch async_track_state_change to the faster async_track_state_change_event part 3 (#37852)

async_track_state_change_event is faster than async_track_state_change
This commit is contained in:
J. Nick Koston 2020-07-14 09:40:01 -10:00 committed by GitHub
parent ea17d36cbb
commit 5cd6370822
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 58 deletions

View File

@ -18,7 +18,7 @@ from homeassistant.const import (
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers import condition from homeassistant.helpers import condition
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change_event
ATTR_OBSERVATIONS = "observations" ATTR_OBSERVATIONS = "observations"
ATTR_OCCURRED_OBSERVATION_ENTITIES = "occurred_observation_entities" ATTR_OCCURRED_OBSERVATION_ENTITIES = "occurred_observation_entities"
@ -151,16 +151,20 @@ class BayesianBinarySensor(BinarySensorEntity):
""" """
@callback @callback
def async_threshold_sensor_state_listener(entity, _old_state, new_state): def async_threshold_sensor_state_listener(event):
""" """
Handle sensor state changes. Handle sensor state changes.
When a state changes, we must update our list of current observations, When a state changes, we must update our list of current observations,
then calculate the new probability. then calculate the new probability.
""" """
if new_state.state == STATE_UNKNOWN: new_state = event.data.get("new_state")
if new_state is None or new_state.state == STATE_UNKNOWN:
return return
entity = event.data.get("entity_id")
self.current_observations.update(self._record_entity_observations(entity)) self.current_observations.update(self._record_entity_observations(entity))
self.probability = self._calculate_new_probability() self.probability = self._calculate_new_probability()
@ -168,9 +172,9 @@ class BayesianBinarySensor(BinarySensorEntity):
self.current_observations.update(self._initialize_current_observations()) self.current_observations.update(self._initialize_current_observations())
self.probability = self._calculate_new_probability() self.probability = self._calculate_new_probability()
async_track_state_change( async_track_state_change_event(
self.hass, self.hass,
self.observations_by_entity, list(self.observations_by_entity),
async_threshold_sensor_state_listener, async_threshold_sensor_state_listener,
) )

View File

@ -31,7 +31,7 @@ import homeassistant.helpers.config_validation as cv
import homeassistant.helpers.device_registry as dr import homeassistant.helpers.device_registry as dr
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change_event
from homeassistant.helpers.json import JSONEncoder from homeassistant.helpers.json import JSONEncoder
from homeassistant.helpers.storage import Store from homeassistant.helpers.storage import Store
from homeassistant.helpers.template import Template from homeassistant.helpers.template import Template
@ -133,23 +133,32 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
) )
) )
async def send_home_assistant_state( async def send_home_assistant_state_event(event: Event) -> None:
entity_id: str, _, new_state: Optional[State] """Forward Home Assistant states updates to ESPHome."""
) -> None: new_state = event.data.get("new_state")
"""Forward Home Assistant states to ESPHome."""
if new_state is None: if new_state is None:
return return
entity_id = event.data.get("entity_id")
await cli.send_home_assistant_state(entity_id, new_state.state)
async def _send_home_assistant_state(
entity_id: str, new_state: Optional[State]
) -> None:
"""Forward Home Assistant states to ESPHome."""
await cli.send_home_assistant_state(entity_id, new_state.state) await cli.send_home_assistant_state(entity_id, new_state.state)
@callback @callback
def async_on_state_subscription(entity_id: str) -> None: def async_on_state_subscription(entity_id: str) -> None:
"""Subscribe and forward states for requested entities.""" """Subscribe and forward states for requested entities."""
unsub = async_track_state_change(hass, entity_id, send_home_assistant_state) unsub = async_track_state_change_event(
entry_data.disconnect_callbacks.append(unsub) hass, [entity_id], send_home_assistant_state_event
# Send initial state
hass.async_create_task(
send_home_assistant_state(entity_id, None, hass.states.get(entity_id))
) )
entry_data.disconnect_callbacks.append(unsub)
new_state = hass.states.get(entity_id)
if new_state is None:
return
# Send initial state
hass.async_create_task(_send_home_assistant_state(entity_id, new_state))
async def on_login() -> None: async def on_login() -> None:
"""Subscribe to states and list entities on successful API login.""" """Subscribe to states and list entities on successful API login."""

View File

@ -24,7 +24,7 @@ from homeassistant.const import (
from homeassistant.core import callback from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change_event
from homeassistant.util.decorator import Registry from homeassistant.util.decorator import Registry
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -173,47 +173,52 @@ class SensorFilter(Entity):
self._filters = filters self._filters = filters
self._icon = None self._icon = None
@callback
def _update_filter_sensor_state_event(self, event):
"""Handle device state changes."""
self._update_filter_sensor_state(event.data.get("new_state"))
@callback
def _update_filter_sensor_state(self, new_state, update_ha=True):
"""Process device state changes."""
if new_state is None or new_state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
return
temp_state = new_state
try:
for filt in self._filters:
filtered_state = filt.filter_state(copy(temp_state))
_LOGGER.debug(
"%s(%s=%s) -> %s",
filt.name,
self._entity,
temp_state.state,
"skip" if filt.skip_processing else filtered_state.state,
)
if filt.skip_processing:
return
temp_state = filtered_state
except ValueError:
_LOGGER.error("Could not convert state: %s to number", self._state)
return
self._state = temp_state.state
if self._icon is None:
self._icon = new_state.attributes.get(ATTR_ICON, ICON)
if self._unit_of_measurement is None:
self._unit_of_measurement = new_state.attributes.get(
ATTR_UNIT_OF_MEASUREMENT
)
if update_ha:
self.async_write_ha_state()
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register callbacks.""" """Register callbacks."""
@callback
def filter_sensor_state_listener(entity, old_state, new_state, update_ha=True):
"""Handle device state changes."""
if new_state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
return
temp_state = new_state
try:
for filt in self._filters:
filtered_state = filt.filter_state(copy(temp_state))
_LOGGER.debug(
"%s(%s=%s) -> %s",
filt.name,
self._entity,
temp_state.state,
"skip" if filt.skip_processing else filtered_state.state,
)
if filt.skip_processing:
return
temp_state = filtered_state
except ValueError:
_LOGGER.error("Could not convert state: %s to number", self._state)
return
self._state = temp_state.state
if self._icon is None:
self._icon = new_state.attributes.get(ATTR_ICON, ICON)
if self._unit_of_measurement is None:
self._unit_of_measurement = new_state.attributes.get(
ATTR_UNIT_OF_MEASUREMENT
)
if update_ha:
self.async_write_ha_state()
if "recorder" in self.hass.config.components: if "recorder" in self.hass.config.components:
history_list = [] history_list = []
largest_window_items = 0 largest_window_items = 0
@ -271,12 +276,12 @@ class SensorFilter(Entity):
) )
# Replay history through the filter chain # Replay history through the filter chain
prev_state = None
for state in history_list: for state in history_list:
filter_sensor_state_listener(self._entity, prev_state, state, False) self._update_filter_sensor_state(state, False)
prev_state = state
async_track_state_change(self.hass, self._entity, filter_sensor_state_listener) async_track_state_change_event(
self.hass, [self._entity], self._update_filter_sensor_state_event
)
@property @property
def name(self): def name(self):