Fix a series of bugs due to Notion API changes (#93039)
* Fix a series of bugs due to Notion API changes * Simplify * Reduce blast radius * Reduce blast radius * Fix tests
This commit is contained in:
parent
e593ceaaf2
commit
637941df4d
13 changed files with 283 additions and 221 deletions
|
@ -2,7 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from dataclasses import dataclass, field, fields
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import traceback
|
||||
|
@ -10,9 +10,16 @@ from typing import Any
|
|||
from uuid import UUID
|
||||
|
||||
from aionotion import async_get_client
|
||||
from aionotion.bridge.models import Bridge
|
||||
from aionotion.bridge.models import Bridge, BridgeAllResponse
|
||||
from aionotion.errors import InvalidCredentialsError, NotionError
|
||||
from aionotion.sensor.models import Listener, ListenerKind, Sensor
|
||||
from aionotion.sensor.models import (
|
||||
Listener,
|
||||
ListenerAllResponse,
|
||||
ListenerKind,
|
||||
Sensor,
|
||||
SensorAllResponse,
|
||||
)
|
||||
from aionotion.user.models import UserPreferences, UserPreferencesResponse
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
|
||||
|
@ -51,6 +58,11 @@ PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
|||
ATTR_SYSTEM_MODE = "system_mode"
|
||||
ATTR_SYSTEM_NAME = "system_name"
|
||||
|
||||
DATA_BRIDGES = "bridges"
|
||||
DATA_LISTENERS = "listeners"
|
||||
DATA_SENSORS = "sensors"
|
||||
DATA_USER_PREFERENCES = "user_preferences"
|
||||
|
||||
DEFAULT_SCAN_INTERVAL = timedelta(minutes=1)
|
||||
|
||||
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
|
||||
|
@ -84,6 +96,9 @@ def is_uuid(value: str) -> bool:
|
|||
class NotionData:
|
||||
"""Define a manager class for Notion data."""
|
||||
|
||||
hass: HomeAssistant
|
||||
entry: ConfigEntry
|
||||
|
||||
# Define a dict of bridges, indexed by bridge ID (an integer):
|
||||
bridges: dict[int, Bridge] = field(default_factory=dict)
|
||||
|
||||
|
@ -93,12 +108,40 @@ class NotionData:
|
|||
# Define a dict of sensors, indexed by sensor UUID (a string):
|
||||
sensors: dict[str, Sensor] = field(default_factory=dict)
|
||||
|
||||
# Define a user preferences response object:
|
||||
user_preferences: UserPreferences | None = field(default=None)
|
||||
|
||||
def update_data_from_response(
|
||||
self,
|
||||
response: BridgeAllResponse
|
||||
| ListenerAllResponse
|
||||
| SensorAllResponse
|
||||
| UserPreferencesResponse,
|
||||
) -> None:
|
||||
"""Update data from an aionotion response."""
|
||||
if isinstance(response, BridgeAllResponse):
|
||||
for bridge in response.bridges:
|
||||
# If a new bridge is discovered, register it:
|
||||
if bridge.id not in self.bridges:
|
||||
_async_register_new_bridge(self.hass, self.entry, bridge)
|
||||
self.bridges[bridge.id] = bridge
|
||||
elif isinstance(response, ListenerAllResponse):
|
||||
self.listeners = {listener.id: listener for listener in response.listeners}
|
||||
elif isinstance(response, SensorAllResponse):
|
||||
self.sensors = {sensor.uuid: sensor for sensor in response.sensors}
|
||||
elif isinstance(response, UserPreferencesResponse):
|
||||
self.user_preferences = response.user_preferences
|
||||
|
||||
def asdict(self) -> dict[str, Any]:
|
||||
"""Represent this dataclass (and its Pydantic contents) as a dict."""
|
||||
return {
|
||||
field.name: [obj.dict() for obj in getattr(self, field.name).values()]
|
||||
for field in fields(self)
|
||||
data: dict[str, Any] = {
|
||||
DATA_BRIDGES: [bridge.dict() for bridge in self.bridges.values()],
|
||||
DATA_LISTENERS: [listener.dict() for listener in self.listeners.values()],
|
||||
DATA_SENSORS: [sensor.dict() for sensor in self.sensors.values()],
|
||||
}
|
||||
if self.user_preferences:
|
||||
data[DATA_USER_PREFERENCES] = self.user_preferences.dict()
|
||||
return data
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
@ -121,11 +164,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
async def async_update() -> NotionData:
|
||||
"""Get the latest data from the Notion API."""
|
||||
data = NotionData()
|
||||
data = NotionData(hass=hass, entry=entry)
|
||||
tasks = {
|
||||
"bridges": client.bridge.async_all(),
|
||||
"listeners": client.sensor.async_listeners(),
|
||||
"sensors": client.sensor.async_all(),
|
||||
DATA_BRIDGES: client.bridge.async_all(),
|
||||
DATA_LISTENERS: client.sensor.async_listeners(),
|
||||
DATA_SENSORS: client.sensor.async_all(),
|
||||
DATA_USER_PREFERENCES: client.user.async_preferences(),
|
||||
}
|
||||
|
||||
results = await asyncio.gather(*tasks.values(), return_exceptions=True)
|
||||
|
@ -145,16 +189,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
f"There was an unknown error while updating {attr}: {result}"
|
||||
) from result
|
||||
|
||||
for item in result:
|
||||
if attr == "bridges":
|
||||
# If a new bridge is discovered, register it:
|
||||
if item.id not in data.bridges:
|
||||
_async_register_new_bridge(hass, item, entry)
|
||||
data.bridges[item.id] = item
|
||||
elif attr == "listeners":
|
||||
data.listeners[item.id] = item
|
||||
else:
|
||||
data.sensors[item.uuid] = item
|
||||
data.update_data_from_response(result)
|
||||
|
||||
return data
|
||||
|
||||
|
@ -216,7 +251,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
@callback
|
||||
def _async_register_new_bridge(
|
||||
hass: HomeAssistant, bridge: Bridge, entry: ConfigEntry
|
||||
hass: HomeAssistant, entry: ConfigEntry, bridge: Bridge
|
||||
) -> None:
|
||||
"""Register a new bridge."""
|
||||
if name := bridge.name:
|
||||
|
@ -279,6 +314,11 @@ class NotionEntity(CoordinatorEntity[DataUpdateCoordinator[NotionData]]):
|
|||
and self._listener_id in self.coordinator.data.listeners
|
||||
)
|
||||
|
||||
@property
|
||||
def listener(self) -> Listener:
|
||||
"""Return the listener related to this entity."""
|
||||
return self.coordinator.data.listeners[self._listener_id]
|
||||
|
||||
@callback
|
||||
def _async_update_bridge_id(self) -> None:
|
||||
"""Update the entity's bridge ID if it has changed.
|
||||
|
@ -310,21 +350,9 @@ class NotionEntity(CoordinatorEntity[DataUpdateCoordinator[NotionData]]):
|
|||
this_device.id, via_device_id=bridge_device.id
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_update_from_latest_data(self) -> None:
|
||||
"""Update the entity from the latest data."""
|
||||
raise NotImplementedError
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Respond to a DataUpdateCoordinator update."""
|
||||
if self._listener_id in self.coordinator.data.listeners:
|
||||
self._async_update_bridge_id()
|
||||
self._async_update_from_latest_data()
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Handle entity which will be added."""
|
||||
await super().async_added_to_hass()
|
||||
self._async_update_from_latest_data()
|
||||
super()._handle_coordinator_update()
|
||||
|
|
|
@ -13,7 +13,7 @@ from homeassistant.components.binary_sensor import (
|
|||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import NotionEntity
|
||||
|
@ -37,7 +37,7 @@ from .model import NotionEntityDescriptionMixin
|
|||
class NotionBinarySensorDescriptionMixin:
|
||||
"""Define an entity description mixin for binary and regular sensors."""
|
||||
|
||||
on_state: Literal["alarm", "critical", "leak", "not_missing", "open"]
|
||||
on_state: Literal["alarm", "leak", "low", "not_missing", "open"]
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -56,7 +56,7 @@ BINARY_SENSOR_DESCRIPTIONS = (
|
|||
device_class=BinarySensorDeviceClass.BATTERY,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
listener_kind=ListenerKind.BATTERY,
|
||||
on_state="critical",
|
||||
on_state="low",
|
||||
),
|
||||
NotionBinarySensorDescription(
|
||||
key=SENSOR_DOOR,
|
||||
|
@ -146,17 +146,10 @@ class NotionBinarySensor(NotionEntity, BinarySensorEntity):
|
|||
|
||||
entity_description: NotionBinarySensorDescription
|
||||
|
||||
@callback
|
||||
def _async_update_from_latest_data(self) -> None:
|
||||
"""Fetch new state data for the sensor."""
|
||||
listener = self.coordinator.data.listeners[self._listener_id]
|
||||
|
||||
if listener.status.trigger_value:
|
||||
state = listener.status.trigger_value
|
||||
elif listener.insights.primary.value:
|
||||
state = listener.insights.primary.value
|
||||
else:
|
||||
LOGGER.warning("Unknown listener structure: %s", listener)
|
||||
state = None
|
||||
|
||||
self._attr_is_on = self.entity_description.on_state == state
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if the binary sensor is on."""
|
||||
if not self.listener.insights.primary.value:
|
||||
LOGGER.warning("Unknown listener structure: %s", self.listener.dict())
|
||||
return False
|
||||
return self.listener.insights.primary.value == self.entity_description.on_state
|
||||
|
|
|
@ -16,6 +16,7 @@ CONF_DEVICE_KEY = "device_key"
|
|||
CONF_HARDWARE_ID = "hardware_id"
|
||||
CONF_LAST_BRIDGE_HARDWARE_ID = "last_bridge_hardware_id"
|
||||
CONF_TITLE = "title"
|
||||
CONF_USER_ID = "user_id"
|
||||
|
||||
TO_REDACT = {
|
||||
CONF_DEVICE_KEY,
|
||||
|
@ -27,6 +28,7 @@ TO_REDACT = {
|
|||
CONF_TITLE,
|
||||
CONF_UNIQUE_ID,
|
||||
CONF_USERNAME,
|
||||
CONF_USER_ID,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
"integration_type": "hub",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["aionotion"],
|
||||
"requirements": ["aionotion==2023.05.1"]
|
||||
"requirements": ["aionotion==2023.05.4"]
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ from homeassistant.components.sensor import (
|
|||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import NotionEntity
|
||||
from .const import DOMAIN, LOGGER, SENSOR_TEMPERATURE
|
||||
from .const import DOMAIN, SENSOR_TEMPERATURE
|
||||
from .model import NotionEntityDescriptionMixin
|
||||
|
||||
|
||||
|
@ -63,15 +63,24 @@ async def async_setup_entry(
|
|||
class NotionSensor(NotionEntity, SensorEntity):
|
||||
"""Define a Notion sensor."""
|
||||
|
||||
@callback
|
||||
def _async_update_from_latest_data(self) -> None:
|
||||
"""Fetch new state data for the sensor."""
|
||||
listener = self.coordinator.data.listeners[self._listener_id]
|
||||
@property
|
||||
def native_unit_of_measurement(self) -> str | None:
|
||||
"""Return the unit of measurement of the sensor."""
|
||||
if self.listener.listener_kind == ListenerKind.TEMPERATURE:
|
||||
if not self.coordinator.data.user_preferences:
|
||||
return None
|
||||
if self.coordinator.data.user_preferences.celsius_enabled:
|
||||
return UnitOfTemperature.CELSIUS
|
||||
return UnitOfTemperature.FAHRENHEIT
|
||||
return None
|
||||
|
||||
if listener.listener_kind == ListenerKind.TEMPERATURE:
|
||||
self._attr_native_value = round(listener.status.temperature, 1) # type: ignore[attr-defined]
|
||||
else:
|
||||
LOGGER.error(
|
||||
"Unknown listener type for sensor %s",
|
||||
self.coordinator.data.sensors[self._sensor_id],
|
||||
)
|
||||
@property
|
||||
def native_value(self) -> str | None:
|
||||
"""Return the value reported by the sensor.
|
||||
|
||||
The Notion API only returns a localized string for temperature (e.g. "70°"); we
|
||||
simply remove the degree symbol:
|
||||
"""
|
||||
if not self.listener.status_localized:
|
||||
return None
|
||||
return self.listener.status_localized.state[:-1]
|
||||
|
|
|
@ -223,7 +223,7 @@ aionanoleaf==0.2.1
|
|||
aionotify==0.2.0
|
||||
|
||||
# homeassistant.components.notion
|
||||
aionotion==2023.05.1
|
||||
aionotion==2023.05.4
|
||||
|
||||
# homeassistant.components.oncue
|
||||
aiooncue==0.3.4
|
||||
|
|
|
@ -204,7 +204,7 @@ aiomusiccast==0.14.8
|
|||
aionanoleaf==0.2.1
|
||||
|
||||
# homeassistant.components.notion
|
||||
aionotion==2023.05.1
|
||||
aionotion==2023.05.4
|
||||
|
||||
# homeassistant.components.oncue
|
||||
aiooncue==0.3.4
|
||||
|
|
|
@ -3,8 +3,9 @@ from collections.abc import Generator
|
|||
import json
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
from aionotion.bridge.models import Bridge
|
||||
from aionotion.sensor.models import Listener, Sensor
|
||||
from aionotion.bridge.models import BridgeAllResponse
|
||||
from aionotion.sensor.models import ListenerAllResponse, SensorAllResponse
|
||||
from aionotion.user.models import UserPreferencesResponse
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.notion import DOMAIN
|
||||
|
@ -27,24 +28,23 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]:
|
|||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def client_fixture(data_bridge, data_listener, data_sensor):
|
||||
def client_fixture(data_bridge, data_listener, data_sensor, data_user_preferences):
|
||||
"""Define a fixture for an aionotion client."""
|
||||
return Mock(
|
||||
bridge=Mock(
|
||||
async_all=AsyncMock(
|
||||
return_value=[Bridge.parse_obj(bridge) for bridge in data_bridge]
|
||||
)
|
||||
async_all=AsyncMock(return_value=BridgeAllResponse.parse_obj(data_bridge))
|
||||
),
|
||||
sensor=Mock(
|
||||
async_all=AsyncMock(
|
||||
return_value=[Sensor.parse_obj(sensor) for sensor in data_sensor]
|
||||
),
|
||||
async_all=AsyncMock(return_value=SensorAllResponse.parse_obj(data_sensor)),
|
||||
async_listeners=AsyncMock(
|
||||
return_value=[
|
||||
Listener.parse_obj(listener) for listener in data_listener
|
||||
]
|
||||
return_value=ListenerAllResponse.parse_obj(data_listener)
|
||||
),
|
||||
),
|
||||
user=Mock(
|
||||
async_preferences=AsyncMock(
|
||||
return_value=UserPreferencesResponse.parse_obj(data_user_preferences)
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -83,6 +83,12 @@ def data_sensor_fixture():
|
|||
return json.loads(load_fixture("sensor_data.json", "notion"))
|
||||
|
||||
|
||||
@pytest.fixture(name="data_user_preferences", scope="package")
|
||||
def data_user_preferences_fixture():
|
||||
"""Define user preferences data."""
|
||||
return json.loads(load_fixture("user_preferences_data.json", "notion"))
|
||||
|
||||
|
||||
@pytest.fixture(name="get_client")
|
||||
def get_client_fixture(client):
|
||||
"""Define a fixture to mock the async_get_client method."""
|
||||
|
|
|
@ -1,50 +1,52 @@
|
|||
[
|
||||
{
|
||||
"id": 12345,
|
||||
"name": "Bridge 1",
|
||||
"mode": "home",
|
||||
"hardware_id": "0x0000000000000000",
|
||||
"hardware_revision": 4,
|
||||
"firmware_version": {
|
||||
"silabs": "1.1.2",
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0"
|
||||
{
|
||||
"base_stations": [
|
||||
{
|
||||
"id": 12345,
|
||||
"name": "Bridge 1",
|
||||
"mode": "home",
|
||||
"hardware_id": "0x0000000000000000",
|
||||
"hardware_revision": 4,
|
||||
"firmware_version": {
|
||||
"silabs": "1.1.2",
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0"
|
||||
},
|
||||
"missing_at": null,
|
||||
"created_at": "2019-06-27T00:18:44.337Z",
|
||||
"updated_at": "2023-03-19T03:20:16.061Z",
|
||||
"system_id": 11111,
|
||||
"firmware": {
|
||||
"silabs": "1.1.2",
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0"
|
||||
},
|
||||
"links": {
|
||||
"system": 11111
|
||||
}
|
||||
},
|
||||
"missing_at": null,
|
||||
"created_at": "2019-06-27T00:18:44.337Z",
|
||||
"updated_at": "2023-03-19T03:20:16.061Z",
|
||||
"system_id": 11111,
|
||||
"firmware": {
|
||||
"silabs": "1.1.2",
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0"
|
||||
},
|
||||
"links": {
|
||||
"system": 11111
|
||||
{
|
||||
"id": 67890,
|
||||
"name": "Bridge 2",
|
||||
"mode": "home",
|
||||
"hardware_id": "0x0000000000000000",
|
||||
"hardware_revision": 4,
|
||||
"firmware_version": {
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0",
|
||||
"silabs": "1.1.2"
|
||||
},
|
||||
"missing_at": null,
|
||||
"created_at": "2019-04-30T01:43:50.497Z",
|
||||
"updated_at": "2023-01-02T19:09:58.251Z",
|
||||
"system_id": 11111,
|
||||
"firmware": {
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0",
|
||||
"silabs": "1.1.2"
|
||||
},
|
||||
"links": {
|
||||
"system": 11111
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 67890,
|
||||
"name": "Bridge 2",
|
||||
"mode": "home",
|
||||
"hardware_id": "0x0000000000000000",
|
||||
"hardware_revision": 4,
|
||||
"firmware_version": {
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0",
|
||||
"silabs": "1.1.2"
|
||||
},
|
||||
"missing_at": null,
|
||||
"created_at": "2019-04-30T01:43:50.497Z",
|
||||
"updated_at": "2023-01-02T19:09:58.251Z",
|
||||
"system_id": 11111,
|
||||
"firmware": {
|
||||
"wifi": "0.121.0",
|
||||
"wifi_app": "3.3.0",
|
||||
"silabs": "1.1.2"
|
||||
},
|
||||
"links": {
|
||||
"system": 11111
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,55 +1,57 @@
|
|||
[
|
||||
{
|
||||
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"definition_id": 4,
|
||||
"created_at": "2019-06-28T22:12:49.651Z",
|
||||
"type": "sensor",
|
||||
"model_version": "2.1",
|
||||
"sensor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"status": {
|
||||
"trigger_value": "no_leak",
|
||||
"data_received_at": "2022-03-20T08:00:29.763Z"
|
||||
},
|
||||
"status_localized": {
|
||||
"state": "No Leak",
|
||||
"description": "Mar 20 at 2:00am"
|
||||
},
|
||||
"insights": {
|
||||
"primary": {
|
||||
"origin": {
|
||||
"type": "Sensor",
|
||||
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
},
|
||||
"value": "no_leak",
|
||||
{
|
||||
"listeners": [
|
||||
{
|
||||
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"definition_id": 4,
|
||||
"created_at": "2019-06-28T22:12:49.651Z",
|
||||
"type": "sensor",
|
||||
"model_version": "2.1",
|
||||
"sensor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"status": {
|
||||
"trigger_value": "no_leak",
|
||||
"data_received_at": "2022-03-20T08:00:29.763Z"
|
||||
}
|
||||
},
|
||||
"status_localized": {
|
||||
"state": "No Leak",
|
||||
"description": "Mar 20 at 2:00am"
|
||||
},
|
||||
"insights": {
|
||||
"primary": {
|
||||
"origin": {
|
||||
"type": "Sensor",
|
||||
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
},
|
||||
"value": "no_leak",
|
||||
"data_received_at": "2022-03-20T08:00:29.763Z"
|
||||
}
|
||||
},
|
||||
"configuration": {},
|
||||
"pro_monitoring_status": "eligible"
|
||||
},
|
||||
"configuration": {},
|
||||
"pro_monitoring_status": "eligible"
|
||||
},
|
||||
{
|
||||
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"definition_id": 7,
|
||||
"created_at": "2019-07-10T22:40:48.847Z",
|
||||
"type": "sensor",
|
||||
"model_version": "3.1",
|
||||
"sensor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"status": {
|
||||
"trigger_value": "no_alarm",
|
||||
"data_received_at": "2019-06-28T22:12:49.516Z"
|
||||
},
|
||||
"status_localized": {
|
||||
"state": "No Sound",
|
||||
"description": "Jun 28 at 4:12pm"
|
||||
},
|
||||
"insights": {
|
||||
"primary": {
|
||||
"origin": {},
|
||||
"value": "no_alarm",
|
||||
{
|
||||
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"definition_id": 7,
|
||||
"created_at": "2019-07-10T22:40:48.847Z",
|
||||
"type": "sensor",
|
||||
"model_version": "3.1",
|
||||
"sensor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"status": {
|
||||
"trigger_value": "no_alarm",
|
||||
"data_received_at": "2019-06-28T22:12:49.516Z"
|
||||
}
|
||||
},
|
||||
"configuration": {},
|
||||
"pro_monitoring_status": "eligible"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status_localized": {
|
||||
"state": "No Sound",
|
||||
"description": "Jun 28 at 4:12pm"
|
||||
},
|
||||
"insights": {
|
||||
"primary": {
|
||||
"origin": {},
|
||||
"value": "no_alarm",
|
||||
"data_received_at": "2019-06-28T22:12:49.516Z"
|
||||
}
|
||||
},
|
||||
"configuration": {},
|
||||
"pro_monitoring_status": "eligible"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,34 +1,36 @@
|
|||
[
|
||||
{
|
||||
"id": 123456,
|
||||
"uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"user": {
|
||||
"id": 12345,
|
||||
"email": "user@email.com"
|
||||
},
|
||||
"bridge": {
|
||||
"id": 67890,
|
||||
"hardware_id": "0x0000000000000000"
|
||||
},
|
||||
"last_bridge_hardware_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"name": "Sensor 1",
|
||||
"location_id": 123456,
|
||||
"system_id": 12345,
|
||||
"hardware_id": "0x0000000000000000",
|
||||
"hardware_revision": 5,
|
||||
"firmware_version": "1.1.2",
|
||||
"device_key": "0x0000000000000000",
|
||||
"encryption_key": true,
|
||||
"installed_at": "2019-06-28T22:12:51.209Z",
|
||||
"calibrated_at": "2023-03-07T19:51:56.838Z",
|
||||
"last_reported_at": "2023-04-19T18:09:40.479Z",
|
||||
"missing_at": null,
|
||||
"updated_at": "2023-03-28T13:33:33.801Z",
|
||||
"created_at": "2019-06-28T22:12:20.256Z",
|
||||
"signal_strength": 4,
|
||||
"firmware": {
|
||||
"status": "valid"
|
||||
},
|
||||
"surface_type": null
|
||||
}
|
||||
]
|
||||
{
|
||||
"sensors": [
|
||||
{
|
||||
"id": 123456,
|
||||
"uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"user": {
|
||||
"id": 12345,
|
||||
"email": "user@email.com"
|
||||
},
|
||||
"bridge": {
|
||||
"id": 67890,
|
||||
"hardware_id": "0x0000000000000000"
|
||||
},
|
||||
"last_bridge_hardware_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"name": "Sensor 1",
|
||||
"location_id": 123456,
|
||||
"system_id": 12345,
|
||||
"hardware_id": "0x0000000000000000",
|
||||
"hardware_revision": 5,
|
||||
"firmware_version": "1.1.2",
|
||||
"device_key": "0x0000000000000000",
|
||||
"encryption_key": true,
|
||||
"installed_at": "2019-06-28T22:12:51.209Z",
|
||||
"calibrated_at": "2023-03-07T19:51:56.838Z",
|
||||
"last_reported_at": "2023-04-19T18:09:40.479Z",
|
||||
"missing_at": null,
|
||||
"updated_at": "2023-03-28T13:33:33.801Z",
|
||||
"created_at": "2019-06-28T22:12:20.256Z",
|
||||
"signal_strength": 4,
|
||||
"firmware": {
|
||||
"status": "valid"
|
||||
},
|
||||
"surface_type": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
10
tests/components/notion/fixtures/user_preferences_data.json
Normal file
10
tests/components/notion/fixtures/user_preferences_data.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"user_preferences": {
|
||||
"user_id": 12345,
|
||||
"military_time_enabled": false,
|
||||
"celsius_enabled": false,
|
||||
"disconnect_alerts_enabled": true,
|
||||
"home_away_alerts_enabled": false,
|
||||
"battery_alerts_enabled": true
|
||||
}
|
||||
}
|
|
@ -86,14 +86,6 @@ async def test_entry_diagnostics(
|
|||
"device_type": "sensor",
|
||||
"model_version": "3.1",
|
||||
"sensor_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"status": {
|
||||
"trigger_value": "no_alarm",
|
||||
"data_received_at": "2019-06-28T22:12:49.516000+00:00",
|
||||
},
|
||||
"status_localized": {
|
||||
"state": "No Sound",
|
||||
"description": "Jun 28 at 4:12pm",
|
||||
},
|
||||
"insights": {
|
||||
"primary": {
|
||||
"origin": {"type": None, "id": None},
|
||||
|
@ -103,6 +95,14 @@ async def test_entry_diagnostics(
|
|||
},
|
||||
"configuration": {},
|
||||
"pro_monitoring_status": "eligible",
|
||||
"status": {
|
||||
"trigger_value": "no_alarm",
|
||||
"data_received_at": "2019-06-28T22:12:49.516000+00:00",
|
||||
},
|
||||
"status_localized": {
|
||||
"state": "No Sound",
|
||||
"description": "Jun 28 at 4:12pm",
|
||||
},
|
||||
}
|
||||
],
|
||||
"sensors": [
|
||||
|
@ -131,5 +131,13 @@ async def test_entry_diagnostics(
|
|||
"surface_type": None,
|
||||
}
|
||||
],
|
||||
"user_preferences": {
|
||||
"user_id": REDACTED,
|
||||
"military_time_enabled": False,
|
||||
"celsius_enabled": False,
|
||||
"disconnect_alerts_enabled": True,
|
||||
"home_away_alerts_enabled": False,
|
||||
"battery_alerts_enabled": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue