Add sensor platform to Bring integration (#126642)
* Add sensor platform to Bring integration * Add more tests * unignore typedef check * Update language sensor * update snapshot * changes * add entities Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * add units * lowercase * snapshot --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>pull/126699/head
parent
c66e2dc076
commit
20030ab604
|
@ -20,7 +20,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|||
from .const import DOMAIN
|
||||
from .coordinator import BringDataUpdateCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.TODO]
|
||||
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.TODO]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -9,3 +9,4 @@ ATTR_ITEM_NAME: Final = "item"
|
|||
ATTR_NOTIFICATION_TYPE: Final = "message"
|
||||
|
||||
SERVICE_PUSH_NOTIFICATION = "send_message"
|
||||
UNIT_ITEMS = "items"
|
||||
|
|
|
@ -11,7 +11,7 @@ from bring_api import (
|
|||
BringParseException,
|
||||
BringRequestException,
|
||||
)
|
||||
from bring_api.types import BringItemsResponse, BringList
|
||||
from bring_api.types import BringItemsResponse, BringList, BringUserSettingsResponse
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_EMAIL
|
||||
|
@ -32,6 +32,7 @@ class BringDataUpdateCoordinator(DataUpdateCoordinator[dict[str, BringData]]):
|
|||
"""A Bring Data Update Coordinator."""
|
||||
|
||||
config_entry: ConfigEntry
|
||||
user_settings: BringUserSettingsResponse
|
||||
|
||||
def __init__(self, hass: HomeAssistant, bring: Bring) -> None:
|
||||
"""Initialize the Bring data coordinator."""
|
||||
|
@ -81,3 +82,17 @@ class BringDataUpdateCoordinator(DataUpdateCoordinator[dict[str, BringData]]):
|
|||
list_dict[lst["listUuid"]] = BringData(**lst, **items)
|
||||
|
||||
return list_dict
|
||||
|
||||
async def _async_setup(self) -> None:
|
||||
"""Set up coordinator."""
|
||||
|
||||
await self.async_refresh_user_settings()
|
||||
|
||||
async def async_refresh_user_settings(self) -> None:
|
||||
"""Refresh user settings."""
|
||||
try:
|
||||
self.user_settings = await self.bring.get_all_user_settings()
|
||||
except (BringAuthException, BringRequestException, BringParseException) as e:
|
||||
raise UpdateFailed(
|
||||
"Unable to connect and retrieve user settings from bring"
|
||||
) from e
|
||||
|
|
|
@ -23,7 +23,6 @@ class BringBaseEntity(CoordinatorEntity[BringDataUpdateCoordinator]):
|
|||
super().__init__(coordinator)
|
||||
|
||||
self._list_uuid = bring_list["listUuid"]
|
||||
self._attr_unique_id = f"{coordinator.config_entry.unique_id}_{self._list_uuid}"
|
||||
|
||||
self.device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
{
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"urgent": {
|
||||
"default": "mdi:run-fast"
|
||||
},
|
||||
"discounted": {
|
||||
"default": "mdi:brightness-percent"
|
||||
},
|
||||
"convenient": {
|
||||
"default": "mdi:fridge-outline"
|
||||
},
|
||||
"list_language": {
|
||||
"default": "mdi:earth"
|
||||
}
|
||||
},
|
||||
"todo": {
|
||||
"shopping_list": {
|
||||
"default": "mdi:cart"
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
"""Sensor platform for the Bring! integration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
|
||||
from bring_api import BringUserSettingsResponse
|
||||
from bring_api.const import BRING_SUPPORTED_LOCALES
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import BringConfigEntry
|
||||
from .const import UNIT_ITEMS
|
||||
from .coordinator import BringData, BringDataUpdateCoordinator
|
||||
from .entity import BringBaseEntity
|
||||
from .util import list_language, sum_attributes
|
||||
|
||||
|
||||
@dataclass(kw_only=True, frozen=True)
|
||||
class BringSensorEntityDescription(SensorEntityDescription):
|
||||
"""Bring Sensor Description."""
|
||||
|
||||
value_fn: Callable[[BringData, BringUserSettingsResponse], StateType]
|
||||
|
||||
|
||||
class BringSensor(StrEnum):
|
||||
"""Bring sensors."""
|
||||
|
||||
URGENT = "urgent"
|
||||
CONVENIENT = "convenient"
|
||||
DISCOUNTED = "discounted"
|
||||
LIST_LANGUAGE = "list_language"
|
||||
|
||||
|
||||
SENSOR_DESCRIPTIONS: tuple[BringSensorEntityDescription, ...] = (
|
||||
BringSensorEntityDescription(
|
||||
key=BringSensor.URGENT,
|
||||
translation_key=BringSensor.URGENT,
|
||||
value_fn=lambda lst, _: sum_attributes(lst, "urgent"),
|
||||
native_unit_of_measurement=UNIT_ITEMS,
|
||||
),
|
||||
BringSensorEntityDescription(
|
||||
key=BringSensor.CONVENIENT,
|
||||
translation_key=BringSensor.CONVENIENT,
|
||||
value_fn=lambda lst, _: sum_attributes(lst, "convenient"),
|
||||
native_unit_of_measurement=UNIT_ITEMS,
|
||||
),
|
||||
BringSensorEntityDescription(
|
||||
key=BringSensor.DISCOUNTED,
|
||||
translation_key=BringSensor.DISCOUNTED,
|
||||
value_fn=lambda lst, _: sum_attributes(lst, "discounted"),
|
||||
native_unit_of_measurement=UNIT_ITEMS,
|
||||
),
|
||||
BringSensorEntityDescription(
|
||||
key=BringSensor.LIST_LANGUAGE,
|
||||
translation_key=BringSensor.LIST_LANGUAGE,
|
||||
value_fn=(
|
||||
lambda lst, settings: x.lower()
|
||||
if (x := list_language(lst["listUuid"], settings))
|
||||
else None
|
||||
),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
options=[x.lower() for x in BRING_SUPPORTED_LOCALES],
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: BringConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the sensor platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
|
||||
async_add_entities(
|
||||
BringSensorEntity(
|
||||
coordinator,
|
||||
bring_list,
|
||||
description,
|
||||
)
|
||||
for description in SENSOR_DESCRIPTIONS
|
||||
for bring_list in coordinator.data.values()
|
||||
)
|
||||
|
||||
|
||||
class BringSensorEntity(BringBaseEntity, SensorEntity):
|
||||
"""A sensor entity."""
|
||||
|
||||
entity_description: BringSensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: BringDataUpdateCoordinator,
|
||||
bring_list: BringData,
|
||||
entity_description: BringSensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
super().__init__(coordinator, bring_list)
|
||||
self.entity_description = entity_description
|
||||
self._attr_unique_id = f"{coordinator.config_entry.unique_id}_{self._list_uuid}_{self.entity_description.key}"
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the state of the sensor."""
|
||||
|
||||
return self.entity_description.value_fn(
|
||||
self.coordinator.data[self._list_uuid],
|
||||
self.coordinator.user_settings,
|
||||
)
|
|
@ -26,6 +26,44 @@
|
|||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"urgent": {
|
||||
"name": "Urgent"
|
||||
},
|
||||
"convenient": {
|
||||
"name": "On occasion"
|
||||
},
|
||||
"discounted": {
|
||||
"name": "Discount only"
|
||||
},
|
||||
"list_language": {
|
||||
"name": "Region & language",
|
||||
"state": {
|
||||
"de-at": "Austria",
|
||||
"de-ch": "Switzerland (German)",
|
||||
"de-de": "Germany",
|
||||
"en-au": "Australia",
|
||||
"en-ca": "Canada",
|
||||
"en-gb": "United Kingdom",
|
||||
"en-us": "United States",
|
||||
"es-es": "Spain",
|
||||
"fr-ch": "Switzerland (French)",
|
||||
"fr-fr": "France",
|
||||
"hu-hu": "Hungary",
|
||||
"it-ch": "Switzerland (Italian)",
|
||||
"it-it": "Italy",
|
||||
"nb-no": "Norway",
|
||||
"nl-nl": "Netherlands",
|
||||
"pl-pl": "Poland",
|
||||
"pt-br": "Portugal",
|
||||
"ru-ru": "Russia",
|
||||
"sv-se": "Sweden",
|
||||
"tr-tr": "Turkey"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"todo_save_item_failed": {
|
||||
"message": "Failed to save item {name} to Bring! list"
|
||||
|
|
|
@ -31,7 +31,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
SERVICE_PUSH_NOTIFICATION,
|
||||
)
|
||||
from .coordinator import BringData
|
||||
from .coordinator import BringData, BringDataUpdateCoordinator
|
||||
from .entity import BringBaseEntity
|
||||
|
||||
|
||||
|
@ -77,6 +77,13 @@ class BringTodoListEntity(BringBaseEntity, TodoListEntity):
|
|||
| TodoListEntityFeature.SET_DESCRIPTION_ON_ITEM
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self, coordinator: BringDataUpdateCoordinator, bring_list: BringData
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
super().__init__(coordinator, bring_list)
|
||||
self._attr_unique_id = f"{coordinator.config_entry.unique_id}_{self._list_uuid}"
|
||||
|
||||
@property
|
||||
def todo_items(self) -> list[TodoItem]:
|
||||
"""Return the todo items."""
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
"""Utility functions for Bring."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from bring_api import BringUserSettingsResponse
|
||||
|
||||
from .coordinator import BringData
|
||||
|
||||
|
||||
def list_language(
|
||||
list_uuid: str,
|
||||
user_settings: BringUserSettingsResponse,
|
||||
) -> str | None:
|
||||
"""Get the lists language setting."""
|
||||
try:
|
||||
list_settings = next(
|
||||
filter(
|
||||
lambda x: x["listUuid"] == list_uuid,
|
||||
user_settings["userlistsettings"],
|
||||
)
|
||||
)
|
||||
|
||||
return next(
|
||||
filter(
|
||||
lambda x: x["key"] == "listArticleLanguage",
|
||||
list_settings["usersettings"],
|
||||
)
|
||||
)["value"]
|
||||
|
||||
except (StopIteration, KeyError):
|
||||
return None
|
||||
|
||||
|
||||
def sum_attributes(bring_list: BringData, attribute: str) -> int:
|
||||
"""Count items with given attribute set."""
|
||||
return sum(
|
||||
item["attributes"][0]["content"][attribute]
|
||||
for item in bring_list["purchase"]
|
||||
if len(item.get("attributes", []))
|
||||
)
|
|
@ -46,6 +46,9 @@ def mock_bring_client() -> Generator[AsyncMock]:
|
|||
client.login.return_value = cast(BringAuthResponse, {"name": "Bring"})
|
||||
client.load_lists.return_value = load_json_object_fixture("lists.json", DOMAIN)
|
||||
client.get_list.return_value = load_json_object_fixture("items.json", DOMAIN)
|
||||
client.get_all_user_settings.return_value = load_json_object_fixture(
|
||||
"usersettings.json", DOMAIN
|
||||
)
|
||||
yield client
|
||||
|
||||
|
||||
|
|
|
@ -6,13 +6,31 @@
|
|||
"uuid": "b5d0790b-5f32-4d5c-91da-e29066f167de",
|
||||
"itemId": "Paprika",
|
||||
"specification": "Rot",
|
||||
"attributes": []
|
||||
"attributes": [
|
||||
{
|
||||
"type": "PURCHASE_CONDITIONS",
|
||||
"content": {
|
||||
"urgent": true,
|
||||
"convenient": true,
|
||||
"discounted": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uuid": "72d370ab-d8ca-4e41-b956-91df94795b4e",
|
||||
"itemId": "Pouletbrüstli",
|
||||
"specification": "Bio",
|
||||
"attributes": []
|
||||
"attributes": [
|
||||
{
|
||||
"type": "PURCHASE_CONDITIONS",
|
||||
"content": {
|
||||
"urgent": true,
|
||||
"convenient": true,
|
||||
"discounted": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"recently": [
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"userlistsettings": [
|
||||
{
|
||||
"listUuid": "e542eef6-dba7-4c31-a52c-29e6ab9d83a5",
|
||||
"usersettings": [
|
||||
{
|
||||
"key": "listSectionOrder",
|
||||
"value": "[\"Früchte & Gemüse\",\"Brot & Gebäck\",\"Milch & Käse\",\"Fleisch & Fisch\",\"Zutaten & Gewürze\",\"Fertig- & Tiefkühlprodukte\",\"Getreideprodukte\",\"Snacks & Süsswaren\",\"Getränke & Tabak\",\"Haushalt & Gesundheit\",\"Pflege & Gesundheit\",\"Tierbedarf\",\"Baumarkt & Garten\",\"Eigene Artikel\"]"
|
||||
},
|
||||
{
|
||||
"key": "listArticleLanguage",
|
||||
"value": "de-DE"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"listUuid": "b4776778-7f6c-496e-951b-92a35d3db0dd",
|
||||
"usersettings": [
|
||||
{
|
||||
"key": "listSectionOrder",
|
||||
"value": "[\"Früchte & Gemüse\",\"Brot & Gebäck\",\"Milch & Käse\",\"Fleisch & Fisch\",\"Zutaten & Gewürze\",\"Fertig- & Tiefkühlprodukte\",\"Getreideprodukte\",\"Snacks & Süsswaren\",\"Getränke & Tabak\",\"Haushalt & Gesundheit\",\"Pflege & Gesundheit\",\"Tierbedarf\",\"Baumarkt & Garten\",\"Eigene Artikel\"]"
|
||||
},
|
||||
{
|
||||
"key": "listArticleLanguage",
|
||||
"value": "en-US"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"usersettings": [
|
||||
{
|
||||
"key": "autoPush",
|
||||
"value": "ON"
|
||||
},
|
||||
{
|
||||
"key": "premiumHideOffersBadge",
|
||||
"value": "ON"
|
||||
},
|
||||
{
|
||||
"key": "premiumHideSponsoredCategories",
|
||||
"value": "ON"
|
||||
},
|
||||
{
|
||||
"key": "premiumHideInspirationsBadge",
|
||||
"value": "ON"
|
||||
},
|
||||
{
|
||||
"key": "onboardClient",
|
||||
"value": "android"
|
||||
},
|
||||
{
|
||||
"key": "premiumHideOffersOnMain",
|
||||
"value": "ON"
|
||||
},
|
||||
{
|
||||
"key": "defaultListUUID",
|
||||
"value": "e542eef6-dba7-4c31-a52c-29e6ab9d83a5"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,467 @@
|
|||
# serializer version: 1
|
||||
# name: test_setup[sensor.baumarkt_discount_only-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.baumarkt_discount_only',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Discount only',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.DISCOUNTED: 'discounted'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_b4776778-7f6c-496e-951b-92a35d3db0dd_discounted',
|
||||
'unit_of_measurement': 'items',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.baumarkt_discount_only-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Baumarkt Discount only',
|
||||
'unit_of_measurement': 'items',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.baumarkt_discount_only',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.baumarkt_on_occasion-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.baumarkt_on_occasion',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'On occasion',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.CONVENIENT: 'convenient'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_b4776778-7f6c-496e-951b-92a35d3db0dd_convenient',
|
||||
'unit_of_measurement': 'items',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.baumarkt_on_occasion-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Baumarkt On occasion',
|
||||
'unit_of_measurement': 'items',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.baumarkt_on_occasion',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.baumarkt_region_language-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'de-at',
|
||||
'de-ch',
|
||||
'de-de',
|
||||
'en-au',
|
||||
'en-ca',
|
||||
'en-gb',
|
||||
'en-us',
|
||||
'es-es',
|
||||
'fr-ch',
|
||||
'fr-fr',
|
||||
'hu-hu',
|
||||
'it-ch',
|
||||
'it-it',
|
||||
'nb-no',
|
||||
'nl-nl',
|
||||
'pl-pl',
|
||||
'pt-br',
|
||||
'ru-ru',
|
||||
'sv-se',
|
||||
'tr-tr',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.baumarkt_region_language',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Region & language',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.LIST_LANGUAGE: 'list_language'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_b4776778-7f6c-496e-951b-92a35d3db0dd_list_language',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.baumarkt_region_language-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'enum',
|
||||
'friendly_name': 'Baumarkt Region & language',
|
||||
'options': list([
|
||||
'de-at',
|
||||
'de-ch',
|
||||
'de-de',
|
||||
'en-au',
|
||||
'en-ca',
|
||||
'en-gb',
|
||||
'en-us',
|
||||
'es-es',
|
||||
'fr-ch',
|
||||
'fr-fr',
|
||||
'hu-hu',
|
||||
'it-ch',
|
||||
'it-it',
|
||||
'nb-no',
|
||||
'nl-nl',
|
||||
'pl-pl',
|
||||
'pt-br',
|
||||
'ru-ru',
|
||||
'sv-se',
|
||||
'tr-tr',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.baumarkt_region_language',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'en-us',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.baumarkt_urgent-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.baumarkt_urgent',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Urgent',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.URGENT: 'urgent'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_b4776778-7f6c-496e-951b-92a35d3db0dd_urgent',
|
||||
'unit_of_measurement': 'items',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.baumarkt_urgent-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Baumarkt Urgent',
|
||||
'unit_of_measurement': 'items',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.baumarkt_urgent',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_discount_only-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.einkauf_discount_only',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Discount only',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.DISCOUNTED: 'discounted'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_e542eef6-dba7-4c31-a52c-29e6ab9d83a5_discounted',
|
||||
'unit_of_measurement': 'items',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_discount_only-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Einkauf Discount only',
|
||||
'unit_of_measurement': 'items',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.einkauf_discount_only',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_on_occasion-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.einkauf_on_occasion',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'On occasion',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.CONVENIENT: 'convenient'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_e542eef6-dba7-4c31-a52c-29e6ab9d83a5_convenient',
|
||||
'unit_of_measurement': 'items',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_on_occasion-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Einkauf On occasion',
|
||||
'unit_of_measurement': 'items',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.einkauf_on_occasion',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_region_language-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'de-at',
|
||||
'de-ch',
|
||||
'de-de',
|
||||
'en-au',
|
||||
'en-ca',
|
||||
'en-gb',
|
||||
'en-us',
|
||||
'es-es',
|
||||
'fr-ch',
|
||||
'fr-fr',
|
||||
'hu-hu',
|
||||
'it-ch',
|
||||
'it-it',
|
||||
'nb-no',
|
||||
'nl-nl',
|
||||
'pl-pl',
|
||||
'pt-br',
|
||||
'ru-ru',
|
||||
'sv-se',
|
||||
'tr-tr',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.einkauf_region_language',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Region & language',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.LIST_LANGUAGE: 'list_language'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_e542eef6-dba7-4c31-a52c-29e6ab9d83a5_list_language',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_region_language-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'enum',
|
||||
'friendly_name': 'Einkauf Region & language',
|
||||
'options': list([
|
||||
'de-at',
|
||||
'de-ch',
|
||||
'de-de',
|
||||
'en-au',
|
||||
'en-ca',
|
||||
'en-gb',
|
||||
'en-us',
|
||||
'es-es',
|
||||
'fr-ch',
|
||||
'fr-fr',
|
||||
'hu-hu',
|
||||
'it-ch',
|
||||
'it-it',
|
||||
'nb-no',
|
||||
'nl-nl',
|
||||
'pl-pl',
|
||||
'pt-br',
|
||||
'ru-ru',
|
||||
'sv-se',
|
||||
'tr-tr',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.einkauf_region_language',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'de-de',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_urgent-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.einkauf_urgent',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Urgent',
|
||||
'platform': 'bring',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': <BringSensor.URGENT: 'urgent'>,
|
||||
'unique_id': '00000000-00000000-00000000-00000000_e542eef6-dba7-4c31-a52c-29e6ab9d83a5_urgent',
|
||||
'unit_of_measurement': 'items',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.einkauf_urgent-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Einkauf Urgent',
|
||||
'unit_of_measurement': 'items',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.einkauf_urgent',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2',
|
||||
})
|
||||
# ---
|
|
@ -90,7 +90,14 @@ async def test_init_exceptions(
|
|||
|
||||
|
||||
@pytest.mark.parametrize("exception", [BringRequestException, BringParseException])
|
||||
@pytest.mark.parametrize("bring_method", ["load_lists", "get_list"])
|
||||
@pytest.mark.parametrize(
|
||||
"bring_method",
|
||||
[
|
||||
"load_lists",
|
||||
"get_list",
|
||||
"get_all_user_settings",
|
||||
],
|
||||
)
|
||||
async def test_config_entry_not_ready(
|
||||
hass: HomeAssistant,
|
||||
bring_config_entry: MockConfigEntry,
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
"""Test for sensor platform of the Bring! integration."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def sensor_only() -> Generator[None]:
|
||||
"""Enable only the sensor platform."""
|
||||
with patch(
|
||||
"homeassistant.components.bring.PLATFORMS",
|
||||
[Platform.SENSOR],
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_bring_client")
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
bring_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Snapshot test states of sensor platform."""
|
||||
|
||||
bring_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(bring_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert bring_config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
await snapshot_platform(
|
||||
hass, entity_registry, snapshot, bring_config_entry.entry_id
|
||||
)
|
|
@ -1,7 +1,8 @@
|
|||
"""Test for todo platform of the Bring! integration."""
|
||||
|
||||
from collections.abc import Generator
|
||||
import re
|
||||
from unittest.mock import AsyncMock
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from bring_api import BringItemOperation, BringRequestException
|
||||
import pytest
|
||||
|
@ -15,7 +16,7 @@ from homeassistant.components.todo import (
|
|||
TodoServices,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
@ -23,6 +24,16 @@ from homeassistant.helpers import entity_registry as er
|
|||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def todo_only() -> Generator[None]:
|
||||
"""Enable only the todo platform."""
|
||||
with patch(
|
||||
"homeassistant.components.bring.PLATFORMS",
|
||||
[Platform.TODO],
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_bring_client")
|
||||
async def test_todo(
|
||||
hass: HomeAssistant,
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
"""Test for utility functions of the Bring! integration."""
|
||||
|
||||
from typing import cast
|
||||
|
||||
from bring_api import BringUserSettingsResponse
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.bring import DOMAIN
|
||||
from homeassistant.components.bring.coordinator import BringData
|
||||
from homeassistant.components.bring.util import list_language, sum_attributes
|
||||
|
||||
from tests.common import load_json_object_fixture
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("list_uuid", "expected"),
|
||||
[
|
||||
("e542eef6-dba7-4c31-a52c-29e6ab9d83a5", "de-DE"),
|
||||
("b4776778-7f6c-496e-951b-92a35d3db0dd", "en-US"),
|
||||
("00000000-0000-0000-0000-00000000", None),
|
||||
],
|
||||
)
|
||||
def test_list_language(list_uuid: str, expected: str | None) -> None:
|
||||
"""Test function list_language."""
|
||||
|
||||
result = list_language(
|
||||
list_uuid,
|
||||
cast(
|
||||
BringUserSettingsResponse,
|
||||
load_json_object_fixture("usersettings.json", DOMAIN),
|
||||
),
|
||||
)
|
||||
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("attribute", "expected"),
|
||||
[
|
||||
("urgent", 2),
|
||||
("convenient", 2),
|
||||
("discounted", 2),
|
||||
],
|
||||
)
|
||||
def test_sum_attributes(attribute: str, expected: int) -> None:
|
||||
"""Test function sum_attributes."""
|
||||
|
||||
result = sum_attributes(
|
||||
cast(
|
||||
BringData,
|
||||
load_json_object_fixture("items.json", DOMAIN),
|
||||
),
|
||||
attribute,
|
||||
)
|
||||
|
||||
assert result == expected
|
Loading…
Reference in New Issue