mirror of
https://github.com/home-assistant/core.git
synced 2026-08-28 02:24:46 -05:00
Add select entity to ToGrill (#151114)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
co-authored by
Joost Lekkerkerker
parent
8a36ec88f4
commit
7322bee4dd
@@ -8,7 +8,12 @@ from homeassistant.exceptions import ConfigEntryNotReady
|
||||
|
||||
from .coordinator import DeviceNotFound, ToGrillConfigEntry, ToGrillCoordinator
|
||||
|
||||
_PLATFORMS: list[Platform] = [Platform.EVENT, Platform.SENSOR, Platform.NUMBER]
|
||||
_PLATFORMS: list[Platform] = [
|
||||
Platform.EVENT,
|
||||
Platform.SELECT,
|
||||
Platform.SENSOR,
|
||||
Platform.NUMBER,
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ToGrillConfigEntry) -> bool:
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"entity": {
|
||||
"select": {
|
||||
"grill_type": {
|
||||
"default": "mdi:grill",
|
||||
"state": {
|
||||
"turkey": "mdi:food-turkey",
|
||||
"sausage": "mdi:sausage",
|
||||
"fish": "mdi:fish",
|
||||
"hamburger": "mdi:hamburger",
|
||||
"bbq_smoke": "mdi:smoke",
|
||||
"hot_smoke": "mdi:smoke",
|
||||
"cold_smoke": "mdi:smoke"
|
||||
}
|
||||
},
|
||||
"taste": {
|
||||
"default": "mdi:food-steak"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
"""Support for select entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Generator, Mapping
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Any, TypeVar
|
||||
|
||||
from togrill_bluetooth.packets import (
|
||||
GrillType,
|
||||
PacketA8Notify,
|
||||
PacketA303Write,
|
||||
PacketWrite,
|
||||
Taste,
|
||||
)
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import ToGrillConfigEntry
|
||||
from .const import CONF_PROBE_COUNT, MAX_PROBE_COUNT
|
||||
from .coordinator import ToGrillCoordinator
|
||||
from .entity import ToGrillEntity
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
OPTION_NONE = "none"
|
||||
|
||||
|
||||
@dataclass(kw_only=True, frozen=True)
|
||||
class ToGrillSelectEntityDescription(SelectEntityDescription):
|
||||
"""Description of entity."""
|
||||
|
||||
get_value: Callable[[ToGrillCoordinator], str | None]
|
||||
set_packet: Callable[[ToGrillCoordinator, str], PacketWrite]
|
||||
entity_supported: Callable[[Mapping[str, Any]], bool] = lambda _: True
|
||||
probe_number: int | None = None
|
||||
|
||||
|
||||
_ENUM = TypeVar("_ENUM", bound=Enum)
|
||||
|
||||
|
||||
def _get_enum_from_name(type_: type[_ENUM], value: str) -> _ENUM | None:
|
||||
"""Return enum value or None."""
|
||||
if value == OPTION_NONE:
|
||||
return None
|
||||
return type_[value.upper()]
|
||||
|
||||
|
||||
def _get_enum_from_value(type_: type[_ENUM], value: int | None) -> _ENUM | None:
|
||||
"""Return enum value or None."""
|
||||
if value is None:
|
||||
return None
|
||||
try:
|
||||
return type_(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def _get_enum_options(type_: type[_ENUM]) -> list[str]:
|
||||
"""Return a list of enum options."""
|
||||
values = [OPTION_NONE]
|
||||
values.extend(option.name.lower() for option in type_)
|
||||
return values
|
||||
|
||||
|
||||
def _get_probe_descriptions(
|
||||
probe_number: int,
|
||||
) -> Generator[ToGrillSelectEntityDescription]:
|
||||
def _get_grill_info(
|
||||
coordinator: ToGrillCoordinator,
|
||||
) -> tuple[GrillType | None, Taste | None]:
|
||||
if not (packet := coordinator.get_packet(PacketA8Notify, probe_number)):
|
||||
return None, None
|
||||
|
||||
return _get_enum_from_value(GrillType, packet.grill_type), _get_enum_from_value(
|
||||
Taste, packet.taste
|
||||
)
|
||||
|
||||
def _set_grill_type(coordinator: ToGrillCoordinator, value: str) -> PacketWrite:
|
||||
_, taste = _get_grill_info(coordinator)
|
||||
grill_type = _get_enum_from_name(GrillType, value)
|
||||
return PacketA303Write(probe=probe_number, grill_type=grill_type, taste=taste)
|
||||
|
||||
def _set_taste(coordinator: ToGrillCoordinator, value: str) -> PacketWrite:
|
||||
grill_type, _ = _get_grill_info(coordinator)
|
||||
taste = _get_enum_from_name(Taste, value)
|
||||
return PacketA303Write(probe=probe_number, grill_type=grill_type, taste=taste)
|
||||
|
||||
def _get_grill_type(coordinator: ToGrillCoordinator) -> str | None:
|
||||
grill_type, _ = _get_grill_info(coordinator)
|
||||
if grill_type is None:
|
||||
return OPTION_NONE
|
||||
return grill_type.name.lower()
|
||||
|
||||
def _get_taste(coordinator: ToGrillCoordinator) -> str | None:
|
||||
_, taste = _get_grill_info(coordinator)
|
||||
if taste is None:
|
||||
return OPTION_NONE
|
||||
return taste.name.lower()
|
||||
|
||||
yield ToGrillSelectEntityDescription(
|
||||
key=f"grill_type_{probe_number}",
|
||||
translation_key="grill_type",
|
||||
options=_get_enum_options(GrillType),
|
||||
set_packet=_set_grill_type,
|
||||
get_value=_get_grill_type,
|
||||
entity_supported=lambda x: probe_number <= x[CONF_PROBE_COUNT],
|
||||
probe_number=probe_number,
|
||||
)
|
||||
|
||||
yield ToGrillSelectEntityDescription(
|
||||
key=f"taste_{probe_number}",
|
||||
translation_key="taste",
|
||||
options=_get_enum_options(Taste),
|
||||
set_packet=_set_taste,
|
||||
get_value=_get_taste,
|
||||
entity_supported=lambda x: probe_number <= x[CONF_PROBE_COUNT],
|
||||
probe_number=probe_number,
|
||||
)
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS = (
|
||||
*[
|
||||
description
|
||||
for probe_number in range(1, MAX_PROBE_COUNT + 1)
|
||||
for description in _get_probe_descriptions(probe_number)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ToGrillConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up select based on a config entry."""
|
||||
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
async_add_entities(
|
||||
ToGrillSelect(coordinator, entity_description)
|
||||
for entity_description in ENTITY_DESCRIPTIONS
|
||||
if entity_description.entity_supported(entry.data)
|
||||
)
|
||||
|
||||
|
||||
class ToGrillSelect(ToGrillEntity, SelectEntity):
|
||||
"""Representation of a select entity."""
|
||||
|
||||
entity_description: ToGrillSelectEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: ToGrillCoordinator,
|
||||
entity_description: ToGrillSelectEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
|
||||
super().__init__(coordinator, probe_number=entity_description.probe_number)
|
||||
self.entity_description = entity_description
|
||||
self._attr_unique_id = f"{coordinator.address}_{entity_description.key}"
|
||||
|
||||
@property
|
||||
def current_option(self) -> str | None:
|
||||
"""Return the selected entity option to represent the entity state."""
|
||||
|
||||
return self.entity_description.get_value(self.coordinator)
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Set value on device."""
|
||||
|
||||
packet = self.entity_description.set_packet(self.coordinator, option)
|
||||
await self._write_packet(packet)
|
||||
@@ -75,6 +75,40 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"taste": {
|
||||
"name": "Taste",
|
||||
"state": {
|
||||
"none": "Not set",
|
||||
"rare": "Rare",
|
||||
"medium_rare": "Medium rare",
|
||||
"medium": "Medium",
|
||||
"medium_well": "Medium well",
|
||||
"well_done": "Well done"
|
||||
}
|
||||
},
|
||||
"grill_type": {
|
||||
"name": "Grill type",
|
||||
"state": {
|
||||
"none": "[%key:component::togrill::entity::select::taste::state::none%]",
|
||||
"beef": "Beef",
|
||||
"veal": "Veal",
|
||||
"lamb": "Lamb",
|
||||
"pork": "Pork",
|
||||
"turkey": "Turkey",
|
||||
"chicken": "Chicken",
|
||||
"sausage": "Sausage",
|
||||
"fish": "Fish",
|
||||
"hamburger": "Hamburger",
|
||||
"bbq_smoke": "BBQ smoke",
|
||||
"hot_smoke": "Hot smoke",
|
||||
"cold_smoke": "Cold smoke",
|
||||
"mark_a": "Mark A",
|
||||
"mark_b": "Mark B",
|
||||
"mark_c": "Mark C"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,901 @@
|
||||
# serializer version: 1
|
||||
# name: test_setup[no_data][select.probe_1_grill_type-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_1_grill_type',
|
||||
'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': 'Grill type',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'grill_type',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_grill_type_1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[no_data][select.probe_1_grill_type-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 1 Grill type',
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_1_grill_type',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[no_data][select.probe_1_taste-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_1_taste',
|
||||
'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': 'Taste',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'taste',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_taste_1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[no_data][select.probe_1_taste-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 1 Taste',
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_1_taste',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[no_data][select.probe_2_grill_type-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_2_grill_type',
|
||||
'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': 'Grill type',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'grill_type',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_grill_type_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[no_data][select.probe_2_grill_type-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 2 Grill type',
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_2_grill_type',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[no_data][select.probe_2_taste-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_2_taste',
|
||||
'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': 'Taste',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'taste',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_taste_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[no_data][select.probe_2_taste-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 2 Taste',
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_2_taste',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_1_grill_type-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_1_grill_type',
|
||||
'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': 'Grill type',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'grill_type',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_grill_type_1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_1_grill_type-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 1 Grill type',
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_1_grill_type',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'beef',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_1_taste-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_1_taste',
|
||||
'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': 'Taste',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'taste',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_taste_1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_1_taste-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 1 Taste',
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_1_taste',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_2_grill_type-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_2_grill_type',
|
||||
'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': 'Grill type',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'grill_type',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_grill_type_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_2_grill_type-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 2 Grill type',
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_2_grill_type',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_2_taste-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_2_taste',
|
||||
'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': 'Taste',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'taste',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_taste_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_different_data][select.probe_2_taste-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 2 Taste',
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_2_taste',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_1_grill_type-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_1_grill_type',
|
||||
'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': 'Grill type',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'grill_type',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_grill_type_1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_1_grill_type-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 1 Grill type',
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_1_grill_type',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_1_taste-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_1_taste',
|
||||
'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': 'Taste',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'taste',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_taste_1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_1_taste-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 1 Taste',
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_1_taste',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_2_grill_type-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_2_grill_type',
|
||||
'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': 'Grill type',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'grill_type',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_grill_type_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_2_grill_type-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 2 Grill type',
|
||||
'options': list([
|
||||
'none',
|
||||
'beef',
|
||||
'veal',
|
||||
'lamb',
|
||||
'pork',
|
||||
'turkey',
|
||||
'chicken',
|
||||
'sausage',
|
||||
'fish',
|
||||
'hamburger',
|
||||
'bbq_smoke',
|
||||
'hot_smoke',
|
||||
'cold_smoke',
|
||||
'mark_a',
|
||||
'mark_b',
|
||||
'mark_c',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_2_grill_type',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_2_taste-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.probe_2_taste',
|
||||
'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': 'Taste',
|
||||
'platform': 'togrill',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'taste',
|
||||
'unique_id': '00000000-0000-0000-0000-000000000001_taste_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[probes_with_unknown_data][select.probe_2_taste-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Probe 2 Taste',
|
||||
'options': list([
|
||||
'none',
|
||||
'rare',
|
||||
'medium_rare',
|
||||
'medium',
|
||||
'medium_well',
|
||||
'well_done',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.probe_2_taste',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'none',
|
||||
})
|
||||
# ---
|
||||
@@ -0,0 +1,172 @@
|
||||
"""Test select for ToGrill integration."""
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from togrill_bluetooth.packets import (
|
||||
GrillType,
|
||||
PacketA0Notify,
|
||||
PacketA8Notify,
|
||||
PacketA303Write,
|
||||
Taste,
|
||||
)
|
||||
|
||||
from homeassistant.components.select import (
|
||||
ATTR_OPTION,
|
||||
DOMAIN as SELECT_DOMAIN,
|
||||
SERVICE_SELECT_OPTION,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import TOGRILL_SERVICE_INFO, setup_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"packets",
|
||||
[
|
||||
pytest.param([], id="no_data"),
|
||||
pytest.param(
|
||||
[
|
||||
PacketA0Notify(
|
||||
battery=45,
|
||||
version_major=1,
|
||||
version_minor=5,
|
||||
function_type=1,
|
||||
probe_count=2,
|
||||
ambient=False,
|
||||
alarm_interval=5,
|
||||
alarm_sound=True,
|
||||
),
|
||||
PacketA8Notify(
|
||||
probe=1,
|
||||
alarm_type=0,
|
||||
grill_type=1,
|
||||
),
|
||||
PacketA8Notify(
|
||||
probe=2,
|
||||
alarm_type=0,
|
||||
taste=1,
|
||||
),
|
||||
PacketA8Notify(probe=2, alarm_type=None),
|
||||
],
|
||||
id="probes_with_different_data",
|
||||
),
|
||||
pytest.param(
|
||||
[
|
||||
PacketA8Notify(
|
||||
probe=1,
|
||||
alarm_type=0,
|
||||
grill_type=99,
|
||||
),
|
||||
PacketA8Notify(
|
||||
probe=2,
|
||||
alarm_type=0,
|
||||
taste=99,
|
||||
),
|
||||
],
|
||||
id="probes_with_unknown_data",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_entry: MockConfigEntry,
|
||||
mock_client: Mock,
|
||||
packets,
|
||||
) -> None:
|
||||
"""Test the setup."""
|
||||
|
||||
inject_bluetooth_service_info(hass, TOGRILL_SERVICE_INFO)
|
||||
|
||||
await setup_entry(hass, mock_entry, [Platform.SELECT])
|
||||
|
||||
for packet in packets:
|
||||
mock_client.mocked_notify(packet)
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("packets", "entity_id", "value", "write_packet"),
|
||||
[
|
||||
pytest.param(
|
||||
[
|
||||
PacketA8Notify(
|
||||
probe=1,
|
||||
alarm_type=PacketA8Notify.AlarmType.TEMPERATURE_TARGET,
|
||||
temperature_1=50.0,
|
||||
),
|
||||
],
|
||||
"select.probe_1_grill_type",
|
||||
"veal",
|
||||
PacketA303Write(probe=1, grill_type=GrillType.VEAL, taste=None),
|
||||
id="grill_type",
|
||||
),
|
||||
pytest.param(
|
||||
[
|
||||
PacketA8Notify(
|
||||
probe=1,
|
||||
alarm_type=PacketA8Notify.AlarmType.TEMPERATURE_TARGET,
|
||||
grill_type=GrillType.BEEF,
|
||||
),
|
||||
],
|
||||
"select.probe_1_taste",
|
||||
"medium",
|
||||
PacketA303Write(probe=1, grill_type=GrillType.BEEF, taste=Taste.MEDIUM),
|
||||
id="taste",
|
||||
),
|
||||
pytest.param(
|
||||
[
|
||||
PacketA8Notify(
|
||||
probe=1,
|
||||
alarm_type=PacketA8Notify.AlarmType.TEMPERATURE_TARGET,
|
||||
grill_type=GrillType.BEEF,
|
||||
taste=Taste.MEDIUM,
|
||||
),
|
||||
],
|
||||
"select.probe_1_taste",
|
||||
"none",
|
||||
PacketA303Write(probe=1, grill_type=GrillType.BEEF, taste=None),
|
||||
id="taste_none",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_set_option(
|
||||
hass: HomeAssistant,
|
||||
mock_entry: MockConfigEntry,
|
||||
mock_client: Mock,
|
||||
packets,
|
||||
entity_id,
|
||||
value,
|
||||
write_packet,
|
||||
) -> None:
|
||||
"""Test the selection of option."""
|
||||
|
||||
inject_bluetooth_service_info(hass, TOGRILL_SERVICE_INFO)
|
||||
|
||||
await setup_entry(hass, mock_entry, [Platform.SELECT])
|
||||
|
||||
for packet in packets:
|
||||
mock_client.mocked_notify(packet)
|
||||
|
||||
await hass.services.async_call(
|
||||
SELECT_DOMAIN,
|
||||
SERVICE_SELECT_OPTION,
|
||||
service_data={
|
||||
ATTR_OPTION: value,
|
||||
},
|
||||
target={
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_client.write.assert_any_call(write_packet)
|
||||
Reference in New Issue
Block a user