Add select entity to ToGrill (#151114)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Joakim Plate
2025-09-01 14:24:43 +02:00
committed by GitHub
co-authored by Joost Lekkerkerker
parent 8a36ec88f4
commit 7322bee4dd
6 changed files with 1310 additions and 1 deletions
+6 -1
View File
@@ -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"
}
}
}
}
+176
View File
@@ -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',
})
# ---
+172
View File
@@ -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)