Convert sense to use DataUpdateCoordinator for trends data (#34160)

* Convert sense to use DataUpdateCoordinator for trends

* remove unused

* request update right away

* clarify

* call async refresh later

* Update homeassistant/components/sense/__init__.py

Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io>

* Update homeassistant/components/sense/__init__.py

Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io>

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
J. Nick Koston 2020-04-13 19:08:37 -05:00 committed by GitHub
parent e1d66f6fdd
commit 5ddcc22583
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 58 deletions

View file

@ -17,6 +17,7 @@ from homeassistant.exceptions import ConfigEntryNotReady
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
ACTIVE_UPDATE_RATE,
@ -27,6 +28,7 @@ from .const import (
SENSE_DEVICES_DATA,
SENSE_DISCOVERED_DEVICES_DATA,
SENSE_TIMEOUT_EXCEPTIONS,
SENSE_TRENDS_COORDINATOR,
)
_LOGGER = logging.getLogger(__name__)
@ -111,9 +113,23 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
except SENSE_TIMEOUT_EXCEPTIONS:
raise ConfigEntryNotReady
trends_coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
name=f"Sense Trends {email}",
update_method=gateway.update_trend_data,
update_interval=timedelta(seconds=300),
)
# This can take longer than 60s and we already know
# sense is online since get_discovered_device_data was
# successful so we do it later.
hass.loop.create_task(trends_coordinator.async_request_refresh())
hass.data[DOMAIN][entry.entry_id] = {
SENSE_DATA: gateway,
SENSE_DEVICES_DATA: sense_devices_data,
SENSE_TRENDS_COORDINATOR: trends_coordinator,
SENSE_DISCOVERED_DEVICES_DATA: sense_discovered_devices,
}
@ -122,7 +138,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
hass.config_entries.async_forward_entry_setup(entry, component)
)
async def async_sense_update(now):
async def async_sense_update(_):
"""Retrieve latest state."""
try:
await gateway.update_realtime()

View file

@ -72,7 +72,6 @@ class SenseDevice(BinarySensorDevice):
self._unique_id = f"{sense_monitor_id}-{self._id}"
self._icon = sense_to_mdi(device["icon"])
self._sense_devices_data = sense_devices_data
self._undo_dispatch_subscription = None
self._state = None
self._available = False
@ -123,16 +122,13 @@ class SenseDevice(BinarySensorDevice):
async def async_added_to_hass(self):
"""Register callbacks."""
self._undo_dispatch_subscription = async_dispatcher_connect(
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{SENSE_DEVICE_UPDATE}-{self._sense_monitor_id}",
self._async_update_from_data,
)
async def async_will_remove_from_hass(self):
"""Undo subscription."""
if self._undo_dispatch_subscription:
self._undo_dispatch_subscription()
)
@callback
def _async_update_from_data(self):

View file

@ -12,6 +12,7 @@ SENSE_DATA = "sense_data"
SENSE_DEVICE_UPDATE = "sense_devices_update"
SENSE_DEVICES_DATA = "sense_devices_data"
SENSE_DISCOVERED_DEVICES_DATA = "sense_discovered_devices"
SENSE_TRENDS_COORDINATOR = "sense_trends_coorindator"
ACTIVE_NAME = "Energy"
ACTIVE_TYPE = "active"

View file

@ -1,5 +1,4 @@
"""Support for monitoring a Sense energy sensor."""
from datetime import timedelta
import logging
from homeassistant.const import (
@ -11,7 +10,6 @@ from homeassistant.const import (
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
from .const import (
ACTIVE_NAME,
@ -28,12 +26,9 @@ from .const import (
SENSE_DEVICE_UPDATE,
SENSE_DEVICES_DATA,
SENSE_DISCOVERED_DEVICES_DATA,
SENSE_TIMEOUT_EXCEPTIONS,
SENSE_TRENDS_COORDINATOR,
)
MIN_TIME_BETWEEN_DAILY_UPDATES = timedelta(seconds=300)
_LOGGER = logging.getLogger(__name__)
@ -70,17 +65,18 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Sense sensor."""
data = hass.data[DOMAIN][config_entry.entry_id][SENSE_DATA]
sense_devices_data = hass.data[DOMAIN][config_entry.entry_id][SENSE_DEVICES_DATA]
trends_coordinator = hass.data[DOMAIN][config_entry.entry_id][
SENSE_TRENDS_COORDINATOR
]
@Throttle(MIN_TIME_BETWEEN_DAILY_UPDATES)
async def update_trends():
"""Update the daily power usage."""
await data.update_trend_data()
# Request only in case it takes longer
# than 60s
await trends_coordinator.async_request_refresh()
sense_monitor_id = data.sense_monitor_id
sense_devices = hass.data[DOMAIN][config_entry.entry_id][
SENSE_DISCOVERED_DEVICES_DATA
]
await data.update_trend_data()
devices = [
SenseEnergyDevice(sense_devices_data, device, sense_monitor_id)
@ -114,8 +110,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
name,
sensor_type,
is_production,
update_trends,
var,
trends_coordinator,
unique_id,
)
)
@ -146,7 +141,6 @@ class SenseActiveSensor(Entity):
self._sensor_type = sensor_type
self._is_production = is_production
self._state = None
self._undo_dispatch_subscription = None
@property
def name(self):
@ -190,16 +184,13 @@ class SenseActiveSensor(Entity):
async def async_added_to_hass(self):
"""Register callbacks."""
self._undo_dispatch_subscription = async_dispatcher_connect(
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{SENSE_DEVICE_UPDATE}-{self._sense_monitor_id}",
self._async_update_from_data,
)
async def async_will_remove_from_hass(self):
"""Undo subscription."""
if self._undo_dispatch_subscription:
self._undo_dispatch_subscription()
)
@callback
def _async_update_from_data(self):
@ -217,7 +208,7 @@ class SenseTrendsSensor(Entity):
"""Implementation of a Sense energy sensor."""
def __init__(
self, data, name, sensor_type, is_production, update_call, sensor_id, unique_id
self, data, name, sensor_type, is_production, trends_coordinator, unique_id,
):
"""Initialize the Sense sensor."""
name_type = PRODUCTION_NAME if is_production else CONSUMPTION_NAME
@ -226,10 +217,11 @@ class SenseTrendsSensor(Entity):
self._available = False
self._data = data
self._sensor_type = sensor_type
self.update_sensor = update_call
self._coordinator = trends_coordinator
self._is_production = is_production
self._state = None
self._unit_of_measurement = ENERGY_KILO_WATT_HOUR
self._had_any_update = False
@property
def name(self):
@ -239,12 +231,12 @@ class SenseTrendsSensor(Entity):
@property
def state(self):
"""Return the state of the sensor."""
return self._state
return round(self._data.get_trend(self._sensor_type, self._is_production), 1)
@property
def available(self):
"""Return the availability of the sensor."""
return self._available
"""Return if entity is available."""
return self._had_any_update and self._coordinator.last_update_success
@property
def unit_of_measurement(self):
@ -266,18 +258,27 @@ class SenseTrendsSensor(Entity):
"""Return the unique id."""
return self._unique_id
@property
def should_poll(self):
"""No need to poll. Coordinator notifies entity of updates."""
return False
@callback
def _async_update(self):
"""Track if we had an update so we do not report zero data."""
self._had_any_update = True
self.async_write_ha_state()
async def async_update(self):
"""Get the latest data, update state."""
"""Update the entity.
try:
await self.update_sensor()
except SENSE_TIMEOUT_EXCEPTIONS:
_LOGGER.error("Timeout retrieving data")
return
Only used by the generic entity update service.
"""
await self._coordinator.async_request_refresh()
state = self._data.get_trend(self._sensor_type, self._is_production)
self._state = round(state, 1)
self._available = True
async def async_added_to_hass(self):
"""When entity is added to hass."""
self.async_on_remove(self._coordinator.async_add_listener(self._async_update))
class SenseEnergyDevice(Entity):
@ -292,7 +293,6 @@ class SenseEnergyDevice(Entity):
self._unique_id = f"{sense_monitor_id}-{self._id}-{CONSUMPTION_ID}"
self._icon = sense_to_mdi(device["icon"])
self._sense_devices_data = sense_devices_data
self._undo_dispatch_subscription = None
self._state = None
@property
@ -342,16 +342,13 @@ class SenseEnergyDevice(Entity):
async def async_added_to_hass(self):
"""Register callbacks."""
self._undo_dispatch_subscription = async_dispatcher_connect(
self.async_on_remove(
async_dispatcher_connect(
self.hass,
f"{SENSE_DEVICE_UPDATE}-{self._sense_monitor_id}",
self._async_update_from_data,
)
async def async_will_remove_from_hass(self):
"""Undo subscription."""
if self._undo_dispatch_subscription:
self._undo_dispatch_subscription()
)
@callback
def _async_update_from_data(self):