Update Notion to use a DataUpdateCoordinator (#38978)

* Update Notion to use a DataUpdateCoordinator

* isort

* Bug
This commit is contained in:
Aaron Bach 2020-08-21 08:10:12 -06:00 committed by GitHub
parent 6fd61be276
commit 31e0ddaec5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 191 additions and 199 deletions

View file

@ -1,68 +1,35 @@
"""Support for Notion.""" """Support for Notion."""
import asyncio import asyncio
from datetime import timedelta
import logging import logging
from aionotion import async_get_client from aionotion import async_get_client
from aionotion.errors import InvalidCredentialsError, NotionError from aionotion.errors import InvalidCredentialsError, NotionError
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import ( from homeassistant.const import ATTR_ATTRIBUTION, CONF_PASSWORD, CONF_USERNAME
ATTR_ATTRIBUTION, from homeassistant.core import HomeAssistant, callback
CONF_PASSWORD,
CONF_USERNAME,
TEMP_CELSIUS,
)
from homeassistant.core import callback
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import ( from homeassistant.helpers import (
aiohttp_client, aiohttp_client,
config_validation as cv, config_validation as cv,
device_registry as dr, device_registry as dr,
) )
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DATA_CLIENT, DEFAULT_SCAN_INTERVAL, DOMAIN, TOPIC_DATA_UPDATE from .const import DATA_COORDINATOR, DOMAIN
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
PLATFORMS = ["binary_sensor", "sensor"]
ATTR_SYSTEM_MODE = "system_mode" ATTR_SYSTEM_MODE = "system_mode"
ATTR_SYSTEM_NAME = "system_name" ATTR_SYSTEM_NAME = "system_name"
DATA_LISTENER = "listener"
DEFAULT_ATTRIBUTION = "Data provided by Notion" DEFAULT_ATTRIBUTION = "Data provided by Notion"
DEFAULT_SCAN_INTERVAL = timedelta(minutes=1)
SENSOR_BATTERY = "low_battery"
SENSOR_DOOR = "door"
SENSOR_GARAGE_DOOR = "garage_door"
SENSOR_LEAK = "leak"
SENSOR_MISSING = "missing"
SENSOR_SAFE = "safe"
SENSOR_SLIDING = "sliding"
SENSOR_SMOKE_CO = "alarm"
SENSOR_TEMPERATURE = "temperature"
SENSOR_WINDOW_HINGED_HORIZONTAL = "window_hinged_horizontal"
SENSOR_WINDOW_HINGED_VERTICAL = "window_hinged_vertical"
BINARY_SENSOR_TYPES = {
SENSOR_BATTERY: ("Low Battery", "battery"),
SENSOR_DOOR: ("Door", "door"),
SENSOR_GARAGE_DOOR: ("Garage Door", "garage_door"),
SENSOR_LEAK: ("Leak Detector", "moisture"),
SENSOR_MISSING: ("Missing", "connectivity"),
SENSOR_SAFE: ("Safe", "door"),
SENSOR_SLIDING: ("Sliding Door/Window", "door"),
SENSOR_SMOKE_CO: ("Smoke/Carbon Monoxide Detector", "smoke"),
SENSOR_WINDOW_HINGED_HORIZONTAL: ("Hinged Window", "window"),
SENSOR_WINDOW_HINGED_VERTICAL: ("Hinged Window", "window"),
}
SENSOR_TYPES = {SENSOR_TEMPERATURE: ("Temperature", "temperature", TEMP_CELSIUS)}
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
{ {
@ -77,11 +44,9 @@ CONFIG_SCHEMA = vol.Schema(
) )
async def async_setup(hass, config): async def async_setup(hass: HomeAssistant, config: dict) -> bool:
"""Set up the Notion component.""" """Set up the Notion component."""
hass.data[DOMAIN] = {} hass.data[DOMAIN] = {DATA_COORDINATOR: {}}
hass.data[DOMAIN][DATA_CLIENT] = {}
hass.data[DOMAIN][DATA_LISTENER] = {}
if DOMAIN not in config: if DOMAIN not in config:
return True return True
@ -102,18 +67,18 @@ async def async_setup(hass, config):
return True return True
async def async_setup_entry(hass, config_entry): async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Notion as a config entry.""" """Set up Notion as a config entry."""
if not config_entry.unique_id: if not entry.unique_id:
hass.config_entries.async_update_entry( hass.config_entries.async_update_entry(
config_entry, unique_id=config_entry.data[CONF_USERNAME] entry, unique_id=entry.data[CONF_USERNAME]
) )
session = aiohttp_client.async_get_clientsession(hass) session = aiohttp_client.async_get_clientsession(hass)
try: try:
client = await async_get_client( client = await async_get_client(
config_entry.data[CONF_USERNAME], config_entry.data[CONF_PASSWORD], session entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD], session
) )
except InvalidCredentialsError: except InvalidCredentialsError:
_LOGGER.error("Invalid username and/or password") _LOGGER.error("Invalid username and/or password")
@ -122,49 +87,77 @@ async def async_setup_entry(hass, config_entry):
_LOGGER.error("Config entry failed: %s", err) _LOGGER.error("Config entry failed: %s", err)
raise ConfigEntryNotReady raise ConfigEntryNotReady
notion = Notion(hass, client, config_entry.entry_id) async def async_update():
await notion.async_update() """Get the latest data from the Notion API."""
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = notion data = {"bridges": {}, "sensors": {}, "tasks": {}}
tasks = {
"bridges": client.bridge.async_all(),
"sensors": client.sensor.async_all(),
"tasks": client.task.async_all(),
}
for component in ("binary_sensor", "sensor"): results = await asyncio.gather(*tasks.values(), return_exceptions=True)
for attr, result in zip(tasks, results):
if isinstance(result, NotionError):
raise UpdateFailed(
f"There was a Notion error while updating {attr}: {result}"
)
if isinstance(result, Exception):
raise UpdateFailed(
f"There was an unknown error while updating {attr}: {result}"
)
for item in result:
if attr == "bridges" and item["id"] not in data["bridges"]:
# If a new bridge is discovered, register it:
hass.async_create_task(async_register_new_bridge(hass, item, entry))
data[attr][item["id"]] = item
return data
coordinator = hass.data[DOMAIN][DATA_COORDINATOR][
entry.entry_id
] = DataUpdateCoordinator(
hass,
_LOGGER,
name=entry.data[CONF_USERNAME],
update_interval=DEFAULT_SCAN_INTERVAL,
update_method=async_update,
)
await coordinator.async_refresh()
for platform in PLATFORMS:
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, component) hass.config_entries.async_forward_entry_setup(entry, platform)
)
async def refresh(event_time):
"""Refresh Notion sensor data."""
_LOGGER.debug("Refreshing Notion sensor data")
await notion.async_update()
async_dispatcher_send(hass, TOPIC_DATA_UPDATE)
hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id] = async_track_time_interval(
hass, refresh, DEFAULT_SCAN_INTERVAL
) )
return True return True
async def async_unload_entry(hass, config_entry): async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a Notion config entry.""" """Unload a Notion config entry."""
hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id) unload_ok = all(
cancel = hass.data[DOMAIN][DATA_LISTENER].pop(config_entry.entry_id) await asyncio.gather(
cancel() *[
hass.config_entries.async_forward_entry_unload(entry, platform)
tasks = [ for platform in PLATFORMS
hass.config_entries.async_forward_entry_unload(config_entry, component)
for component in ("binary_sensor", "sensor")
] ]
)
)
if unload_ok:
hass.data[DOMAIN][DATA_COORDINATOR].pop(entry.entry_id)
await asyncio.gather(*tasks) return unload_ok
return True
async def register_new_bridge(hass, bridge, config_entry_id): async def async_register_new_bridge(
hass: HomeAssistant, bridge: dict, entry: ConfigEntry
):
"""Register a new bridge.""" """Register a new bridge."""
device_registry = await dr.async_get_registry(hass) device_registry = await dr.async_get_registry(hass)
device_registry.async_get_or_create( device_registry.async_get_or_create(
config_entry_id=config_entry_id, config_entry_id=entry.entry_id,
identifiers={(DOMAIN, bridge["hardware_id"])}, identifiers={(DOMAIN, bridge["hardware_id"])},
manufacturer="Silicon Labs", manufacturer="Silicon Labs",
model=bridge["hardware_revision"], model=bridge["hardware_revision"],
@ -173,73 +166,40 @@ async def register_new_bridge(hass, bridge, config_entry_id):
) )
class Notion:
"""Define a class to handle the Notion API."""
def __init__(self, hass, client, config_entry_id):
"""Initialize."""
self._client = client
self._config_entry_id = config_entry_id
self._hass = hass
self.bridges = {}
self.sensors = {}
self.tasks = {}
async def async_update(self):
"""Get the latest Notion data."""
tasks = {
"bridges": self._client.bridge.async_all(),
"sensors": self._client.sensor.async_all(),
"tasks": self._client.task.async_all(),
}
results = await asyncio.gather(*tasks.values(), return_exceptions=True)
for attr, result in zip(tasks, results):
if isinstance(result, NotionError):
_LOGGER.error(
"There was a Notion error while updating %s: %s", attr, result
)
continue
if isinstance(result, Exception):
_LOGGER.error(
"There was an unknown error while updating %s: %s", attr, result
)
continue
holding_pen = getattr(self, attr)
for item in result:
if attr == "bridges" and item["id"] not in holding_pen:
# If a new bridge is discovered, register it:
self._hass.async_create_task(
register_new_bridge(self._hass, item, self._config_entry_id)
)
holding_pen[item["id"]] = item
class NotionEntity(Entity): class NotionEntity(Entity):
"""Define a base Notion entity.""" """Define a base Notion entity."""
def __init__( def __init__(
self, notion, task_id, sensor_id, bridge_id, system_id, name, device_class self,
coordinator: DataUpdateCoordinator,
task_id: str,
sensor_id: str,
bridge_id: str,
system_id: str,
name: str,
device_class: str,
): ):
"""Initialize the entity.""" """Initialize the entity."""
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION} self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
self._bridge_id = bridge_id self._bridge_id = bridge_id
self._coordinator = coordinator
self._device_class = device_class self._device_class = device_class
self._name = name self._name = name
self._notion = notion
self._sensor_id = sensor_id self._sensor_id = sensor_id
self._state = None self._state = None
self._system_id = system_id self._system_id = system_id
self._task_id = task_id self._task_id = task_id
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return self._task_id in self._notion.tasks return (
self._coordinator.last_update_success
and self._task_id in self._coordinator.data["tasks"]
)
@property @property
def device_class(self): def device_class(self) -> str:
"""Return the device class.""" """Return the device class."""
return self._device_class return self._device_class
@ -249,10 +209,10 @@ class NotionEntity(Entity):
return self._attrs return self._attrs
@property @property
def device_info(self): def device_info(self) -> dict:
"""Return device registry information for this entity.""" """Return device registry information for this entity."""
bridge = self._notion.bridges.get(self._bridge_id, {}) bridge = self._coordinator.data["bridges"].get(self._bridge_id, {})
sensor = self._notion.sensors[self._sensor_id] sensor = self._coordinator.data["sensors"][self._sensor_id]
return { return {
"identifiers": {(DOMAIN, sensor["hardware_id"])}, "identifiers": {(DOMAIN, sensor["hardware_id"])},
@ -264,41 +224,42 @@ class NotionEntity(Entity):
} }
@property @property
def name(self): def name(self) -> str:
"""Return the name of the sensor.""" """Return the name of the entity."""
return f"{self._notion.sensors[self._sensor_id]['name']}: {self._name}" sensor = self._coordinator.data["sensors"][self._sensor_id]
return f'{sensor["name"]}: {self._name}'
@property @property
def should_poll(self): def should_poll(self) -> bool:
"""Disable entity polling.""" """Disable entity polling."""
return False return False
@property @property
def unique_id(self): def unique_id(self) -> str:
"""Return a unique, unchanging string that represents this sensor.""" """Return a unique, unchanging string that represents this entity."""
task = self._notion.tasks[self._task_id] task = self._coordinator.data["tasks"][self._task_id]
return f"{self._sensor_id}_{task['task_type']}" return f'{self._sensor_id}_{task["task_type"]}'
async def _update_bridge_id(self): async def _async_update_bridge_id(self) -> None:
"""Update the entity's bridge ID if it has changed. """Update the entity's bridge ID if it has changed.
Sensors can move to other bridges based on signal strength, etc. Sensors can move to other bridges based on signal strength, etc.
""" """
sensor = self._notion.sensors[self._sensor_id] sensor = self._coordinator.data["sensors"][self._sensor_id]
# If the sensor's bridge ID is the same as what we had before or if it points # If the sensor's bridge ID is the same as what we had before or if it points
# to a bridge that doesn't exist (which can happen due to a Notion API bug), # to a bridge that doesn't exist (which can happen due to a Notion API bug),
# return immediately: # return immediately:
if ( if (
self._bridge_id == sensor["bridge"]["id"] self._bridge_id == sensor["bridge"]["id"]
or sensor["bridge"]["id"] not in self._notion.bridges or sensor["bridge"]["id"] not in self._coordinator.data["bridges"]
): ):
return return
self._bridge_id = sensor["bridge"]["id"] self._bridge_id = sensor["bridge"]["id"]
device_registry = await dr.async_get_registry(self.hass) device_registry = await dr.async_get_registry(self.hass)
bridge = self._notion.bridges[self._bridge_id] bridge = self._coordinator.data["bridges"][self._bridge_id]
bridge_device = device_registry.async_get_device( bridge_device = device_registry.async_get_device(
{DOMAIN: bridge["hardware_id"]}, set() {DOMAIN: bridge["hardware_id"]}, set()
) )
@ -310,23 +271,20 @@ class NotionEntity(Entity):
this_device.id, via_device_id=bridge_device.id this_device.id, via_device_id=bridge_device.id
) )
async def async_added_to_hass(self): @callback
def _async_update_from_latest_data(self) -> None:
"""Update the entity from the latest data."""
raise NotImplementedError
async def async_added_to_hass(self) -> None:
"""Register callbacks.""" """Register callbacks."""
@callback @callback
def update(): def update():
"""Update the entity.""" """Update the state."""
self.hass.async_create_task(self._update_bridge_id()) self._async_update_from_latest_data()
self.update_from_latest_data()
self.async_write_ha_state() self.async_write_ha_state()
self.async_on_remove( self.async_on_remove(self._coordinator.async_add_listener(update))
async_dispatcher_connect(self.hass, TOPIC_DATA_UPDATE, update)
)
self.update_from_latest_data() self._async_update_from_latest_data()
@callback
def update_from_latest_data(self):
"""Update the entity from the latest data."""
raise NotImplementedError

View file

@ -1,11 +1,15 @@
"""Support for Notion binary sensors.""" """Support for Notion binary sensors."""
import logging import logging
from typing import Callable
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.core import callback from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from . import ( from . import NotionEntity
BINARY_SENSOR_TYPES, from .const import (
DATA_COORDINATOR,
DOMAIN,
SENSOR_BATTERY, SENSOR_BATTERY,
SENSOR_DOOR, SENSOR_DOOR,
SENSOR_GARAGE_DOOR, SENSOR_GARAGE_DOOR,
@ -16,28 +20,41 @@ from . import (
SENSOR_SMOKE_CO, SENSOR_SMOKE_CO,
SENSOR_WINDOW_HINGED_HORIZONTAL, SENSOR_WINDOW_HINGED_HORIZONTAL,
SENSOR_WINDOW_HINGED_VERTICAL, SENSOR_WINDOW_HINGED_VERTICAL,
NotionEntity,
) )
from .const import DATA_CLIENT, DOMAIN
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
BINARY_SENSOR_TYPES = {
SENSOR_BATTERY: ("Low Battery", "battery"),
SENSOR_DOOR: ("Door", "door"),
SENSOR_GARAGE_DOOR: ("Garage Door", "garage_door"),
SENSOR_LEAK: ("Leak Detector", "moisture"),
SENSOR_MISSING: ("Missing", "connectivity"),
SENSOR_SAFE: ("Safe", "door"),
SENSOR_SLIDING: ("Sliding Door/Window", "door"),
SENSOR_SMOKE_CO: ("Smoke/Carbon Monoxide Detector", "smoke"),
SENSOR_WINDOW_HINGED_HORIZONTAL: ("Hinged Window", "window"),
SENSOR_WINDOW_HINGED_VERTICAL: ("Hinged Window", "window"),
}
async def async_setup_entry(hass, entry, async_add_entities):
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: Callable
):
"""Set up Notion sensors based on a config entry.""" """Set up Notion sensors based on a config entry."""
notion = hass.data[DOMAIN][DATA_CLIENT][entry.entry_id] coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id]
sensor_list = [] sensor_list = []
for task_id, task in notion.tasks.items(): for task_id, task in coordinator.data["tasks"].items():
if task["task_type"] not in BINARY_SENSOR_TYPES: if task["task_type"] not in BINARY_SENSOR_TYPES:
continue continue
name, device_class = BINARY_SENSOR_TYPES[task["task_type"]] name, device_class = BINARY_SENSOR_TYPES[task["task_type"]]
sensor = notion.sensors[task["sensor_id"]] sensor = coordinator.data["sensors"][task["sensor_id"]]
sensor_list.append( sensor_list.append(
NotionBinarySensor( NotionBinarySensor(
notion, coordinator,
task_id, task_id,
sensor["id"], sensor["id"],
sensor["bridge"]["id"], sensor["bridge"]["id"],
@ -47,16 +64,21 @@ async def async_setup_entry(hass, entry, async_add_entities):
) )
) )
async_add_entities(sensor_list, True) async_add_entities(sensor_list)
class NotionBinarySensor(NotionEntity, BinarySensorEntity): class NotionBinarySensor(NotionEntity, BinarySensorEntity):
"""Define a Notion sensor.""" """Define a Notion sensor."""
@callback
def _async_update_from_latest_data(self) -> None:
"""Fetch new state data for the sensor."""
self._state = self._coordinator.data["tasks"][self._task_id]["status"]["value"]
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return whether the sensor is on or off.""" """Return whether the sensor is on or off."""
task = self._notion.tasks[self._task_id] task = self._coordinator.data["tasks"][self._task_id]
if task["task_type"] == SENSOR_BATTERY: if task["task_type"] == SENSOR_BATTERY:
return self._state != "battery_good" return self._state != "battery_good"
@ -75,10 +97,3 @@ class NotionBinarySensor(NotionEntity, BinarySensorEntity):
return self._state == "not_missing" return self._state == "not_missing"
if task["task_type"] == SENSOR_SMOKE_CO: if task["task_type"] == SENSOR_SMOKE_CO:
return self._state != "no_alarm" return self._state != "no_alarm"
@callback
def update_from_latest_data(self):
"""Fetch new state data for the sensor."""
task = self._notion.tasks[self._task_id]
self._state = task["status"]["value"]

View file

@ -1,13 +1,16 @@
"""Define constants for the Notion integration.""" """Define constants for the Notion integration."""
from datetime import timedelta
DOMAIN = "notion" DOMAIN = "notion"
DEFAULT_SCAN_INTERVAL = timedelta(minutes=1) DATA_COORDINATOR = "coordinator"
DATA_CLIENT = "client" SENSOR_BATTERY = "low_battery"
SENSOR_DOOR = "door"
TOPIC_DATA_UPDATE = f"{DOMAIN}_data_update" SENSOR_GARAGE_DOOR = "garage_door"
SENSOR_LEAK = "leak"
TYPE_BINARY_SENSOR = "binary_sensor" SENSOR_MISSING = "missing"
TYPE_SENSOR = "sensor" SENSOR_SAFE = "safe"
SENSOR_SLIDING = "sliding"
SENSOR_SMOKE_CO = "alarm"
SENSOR_TEMPERATURE = "temperature"
SENSOR_WINDOW_HINGED_HORIZONTAL = "window_hinged_horizontal"
SENSOR_WINDOW_HINGED_VERTICAL = "window_hinged_vertical"

View file

@ -1,29 +1,37 @@
"""Support for Notion sensors.""" """Support for Notion sensors."""
import logging import logging
from typing import Callable
from homeassistant.core import callback from homeassistant.config_entries import ConfigEntry
from homeassistant.const import TEMP_CELSIUS
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from . import SENSOR_TEMPERATURE, SENSOR_TYPES, NotionEntity from . import NotionEntity
from .const import DATA_CLIENT, DOMAIN from .const import DATA_COORDINATOR, DOMAIN, SENSOR_TEMPERATURE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SENSOR_TYPES = {SENSOR_TEMPERATURE: ("Temperature", "temperature", TEMP_CELSIUS)}
async def async_setup_entry(hass, entry, async_add_entities):
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: Callable
):
"""Set up Notion sensors based on a config entry.""" """Set up Notion sensors based on a config entry."""
notion = hass.data[DOMAIN][DATA_CLIENT][entry.entry_id] coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id]
sensor_list = [] sensor_list = []
for task_id, task in notion.tasks.items(): for task_id, task in coordinator.data["tasks"].items():
if task["task_type"] not in SENSOR_TYPES: if task["task_type"] not in SENSOR_TYPES:
continue continue
name, device_class, unit = SENSOR_TYPES[task["task_type"]] name, device_class, unit = SENSOR_TYPES[task["task_type"]]
sensor = notion.sensors[task["sensor_id"]] sensor = coordinator.data["sensors"][task["sensor_id"]]
sensor_list.append( sensor_list.append(
NotionSensor( NotionSensor(
notion, coordinator,
task_id, task_id,
sensor["id"], sensor["id"],
sensor["bridge"]["id"], sensor["bridge"]["id"],
@ -34,42 +42,50 @@ async def async_setup_entry(hass, entry, async_add_entities):
) )
) )
async_add_entities(sensor_list, True) async_add_entities(sensor_list)
class NotionSensor(NotionEntity): class NotionSensor(NotionEntity):
"""Define a Notion sensor.""" """Define a Notion sensor."""
def __init__( def __init__(
self, notion, task_id, sensor_id, bridge_id, system_id, name, device_class, unit self,
coordinator: DataUpdateCoordinator,
task_id: str,
sensor_id: str,
bridge_id: str,
system_id: str,
name: str,
device_class: str,
unit: str,
): ):
"""Initialize the entity.""" """Initialize the entity."""
super().__init__( super().__init__(
notion, task_id, sensor_id, bridge_id, system_id, name, device_class coordinator, task_id, sensor_id, bridge_id, system_id, name, device_class
) )
self._unit = unit self._unit = unit
@property @property
def state(self): def state(self) -> str:
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self._state
@property @property
def unit_of_measurement(self): def unit_of_measurement(self) -> str:
"""Return the unit of measurement.""" """Return the unit of measurement."""
return self._unit return self._unit
@callback @callback
def update_from_latest_data(self): def _async_update_from_latest_data(self) -> None:
"""Fetch new state data for the sensor.""" """Fetch new state data for the sensor."""
task = self._notion.tasks[self._task_id] task = self._coordinator.data["tasks"][self._task_id]
if task["task_type"] == SENSOR_TEMPERATURE: if task["task_type"] == SENSOR_TEMPERATURE:
self._state = round(float(task["status"]["value"]), 1) self._state = round(float(task["status"]["value"]), 1)
else: else:
_LOGGER.error( _LOGGER.error(
"Unknown task type: %s: %s", "Unknown task type: %s: %s",
self._notion.sensors[self._sensor_id], self._coordinator.data["sensors"][self._sensor_id],
task["task_type"], task["task_type"],
) )