mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 07:51:46 -05:00
Add button platform to Persang Infrared (#181161)
This commit is contained in:
@@ -4,7 +4,7 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
PLATFORMS = [Platform.MEDIA_PLAYER]
|
||||
PLATFORMS = [Platform.BUTTON, Platform.MEDIA_PLAYER]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
"""Button platform for the Persang Infrared integration.
|
||||
|
||||
Only commands the media player has no slot for live here: the mode and EQ
|
||||
cycles, scan and repeat, and the numeric keypad.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import override
|
||||
|
||||
from infrared_protocols.codes.persang.speaker import PersangSpeakerCode
|
||||
|
||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import CONF_INFRARED_EMITTER_ENTITY_ID
|
||||
from .entity import PersangIrEntity
|
||||
|
||||
PARALLEL_UPDATES = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class PersangIrButtonEntityDescription(ButtonEntityDescription):
|
||||
"""Describes a Persang IR button entity."""
|
||||
|
||||
command_code: PersangSpeakerCode
|
||||
|
||||
|
||||
BUTTON_DESCRIPTIONS: tuple[PersangIrButtonEntityDescription, ...] = (
|
||||
PersangIrButtonEntityDescription(
|
||||
key="mode",
|
||||
translation_key="mode",
|
||||
command_code=PersangSpeakerCode.MODE,
|
||||
),
|
||||
PersangIrButtonEntityDescription(
|
||||
key="eq",
|
||||
translation_key="eq",
|
||||
command_code=PersangSpeakerCode.EQ,
|
||||
),
|
||||
PersangIrButtonEntityDescription(
|
||||
key="scan",
|
||||
translation_key="scan",
|
||||
command_code=PersangSpeakerCode.SCAN,
|
||||
),
|
||||
PersangIrButtonEntityDescription(
|
||||
key="repeat",
|
||||
translation_key="repeat",
|
||||
command_code=PersangSpeakerCode.REPEAT,
|
||||
),
|
||||
*(
|
||||
PersangIrButtonEntityDescription(
|
||||
key=f"num_{digit}",
|
||||
translation_key=f"num_{digit}",
|
||||
command_code=PersangSpeakerCode[f"NUM_{digit}"],
|
||||
)
|
||||
for digit in range(10)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Persang IR buttons from a config entry."""
|
||||
infrared_entity_id = entry.data[CONF_INFRARED_EMITTER_ENTITY_ID]
|
||||
async_add_entities(
|
||||
PersangIrButton(entry, infrared_entity_id, description)
|
||||
for description in BUTTON_DESCRIPTIONS
|
||||
)
|
||||
|
||||
|
||||
class PersangIrButton(PersangIrEntity, ButtonEntity):
|
||||
"""Persang IR button entity."""
|
||||
|
||||
entity_description: PersangIrButtonEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
entry: ConfigEntry,
|
||||
infrared_entity_id: str,
|
||||
description: PersangIrButtonEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize Persang IR button."""
|
||||
super().__init__(entry, infrared_entity_id, unique_id_suffix=description.key)
|
||||
self.entity_description = description
|
||||
|
||||
@override
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
await self._send_command(self.entity_description.command_code.to_command())
|
||||
@@ -12,10 +12,19 @@ class PersangIrEntity(InfraredEmitterConsumerEntity):
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(self, entry: ConfigEntry, infrared_entity_id: str) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
entry: ConfigEntry,
|
||||
infrared_entity_id: str,
|
||||
unique_id_suffix: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize Persang IR entity."""
|
||||
self._infrared_emitter_entity_id = infrared_entity_id
|
||||
self._attr_unique_id = entry.entry_id
|
||||
self._attr_unique_id = (
|
||||
entry.entry_id
|
||||
if unique_id_suffix is None
|
||||
else f"{entry.entry_id}_{unique_id_suffix}"
|
||||
)
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, entry.entry_id)},
|
||||
name="Persang speaker",
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"entity": {
|
||||
"button": {
|
||||
"eq": {
|
||||
"default": "mdi:equalizer"
|
||||
},
|
||||
"mode": {
|
||||
"default": "mdi:playlist-music"
|
||||
},
|
||||
"num_0": {
|
||||
"default": "mdi:numeric-0"
|
||||
},
|
||||
"num_1": {
|
||||
"default": "mdi:numeric-1"
|
||||
},
|
||||
"num_2": {
|
||||
"default": "mdi:numeric-2"
|
||||
},
|
||||
"num_3": {
|
||||
"default": "mdi:numeric-3"
|
||||
},
|
||||
"num_4": {
|
||||
"default": "mdi:numeric-4"
|
||||
},
|
||||
"num_5": {
|
||||
"default": "mdi:numeric-5"
|
||||
},
|
||||
"num_6": {
|
||||
"default": "mdi:numeric-6"
|
||||
},
|
||||
"num_7": {
|
||||
"default": "mdi:numeric-7"
|
||||
},
|
||||
"num_8": {
|
||||
"default": "mdi:numeric-8"
|
||||
},
|
||||
"num_9": {
|
||||
"default": "mdi:numeric-9"
|
||||
},
|
||||
"repeat": {
|
||||
"default": "mdi:repeat"
|
||||
},
|
||||
"scan": {
|
||||
"default": "mdi:motion-play"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,10 +100,7 @@ rules:
|
||||
status: exempt
|
||||
comment: |
|
||||
This integration does not raise exceptions.
|
||||
icon-translations:
|
||||
status: exempt
|
||||
comment: |
|
||||
This integration does not use custom icons.
|
||||
icon-translations: done
|
||||
reconfiguration-flow: todo
|
||||
repair-issues:
|
||||
status: exempt
|
||||
|
||||
@@ -16,5 +16,51 @@
|
||||
"title": "Set up Persang IR speaker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"button": {
|
||||
"eq": {
|
||||
"name": "Equalizer"
|
||||
},
|
||||
"mode": {
|
||||
"name": "Mode"
|
||||
},
|
||||
"num_0": {
|
||||
"name": "[%key:common::entity::button::num_0::name%]"
|
||||
},
|
||||
"num_1": {
|
||||
"name": "[%key:common::entity::button::num_1::name%]"
|
||||
},
|
||||
"num_2": {
|
||||
"name": "[%key:common::entity::button::num_2::name%]"
|
||||
},
|
||||
"num_3": {
|
||||
"name": "[%key:common::entity::button::num_3::name%]"
|
||||
},
|
||||
"num_4": {
|
||||
"name": "[%key:common::entity::button::num_4::name%]"
|
||||
},
|
||||
"num_5": {
|
||||
"name": "[%key:common::entity::button::num_5::name%]"
|
||||
},
|
||||
"num_6": {
|
||||
"name": "[%key:common::entity::button::num_6::name%]"
|
||||
},
|
||||
"num_7": {
|
||||
"name": "[%key:common::entity::button::num_7::name%]"
|
||||
},
|
||||
"num_8": {
|
||||
"name": "[%key:common::entity::button::num_8::name%]"
|
||||
},
|
||||
"num_9": {
|
||||
"name": "[%key:common::entity::button::num_9::name%]"
|
||||
},
|
||||
"repeat": {
|
||||
"name": "Repeat"
|
||||
},
|
||||
"scan": {
|
||||
"name": "Scan"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,701 @@
|
||||
# serializer version: 1
|
||||
# name: test_entities[button.persang_speaker_equalizer-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_equalizer',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Equalizer',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Equalizer',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'eq',
|
||||
'unique_id': '01JTEST0000000000000000000_eq',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_equalizer-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Equalizer',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_equalizer',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_mode-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_mode',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Mode',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Mode',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'mode',
|
||||
'unique_id': '01JTEST0000000000000000000_mode',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_mode-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Mode',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_mode',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_0-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_0',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 0',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 0',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_0',
|
||||
'unique_id': '01JTEST0000000000000000000_num_0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_0-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 0',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_0',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_1-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_1',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 1',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 1',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_1',
|
||||
'unique_id': '01JTEST0000000000000000000_num_1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_1-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 1',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_1',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_2-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_2',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 2',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 2',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_2',
|
||||
'unique_id': '01JTEST0000000000000000000_num_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_2-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 2',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_2',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_3-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_3',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 3',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 3',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_3',
|
||||
'unique_id': '01JTEST0000000000000000000_num_3',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_3-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 3',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_3',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_4-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_4',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 4',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 4',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_4',
|
||||
'unique_id': '01JTEST0000000000000000000_num_4',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_4-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 4',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_4',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_5-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_5',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 5',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 5',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_5',
|
||||
'unique_id': '01JTEST0000000000000000000_num_5',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_5-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 5',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_5',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_6-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_6',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 6',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 6',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_6',
|
||||
'unique_id': '01JTEST0000000000000000000_num_6',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_6-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 6',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_6',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_7-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_7',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 7',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 7',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_7',
|
||||
'unique_id': '01JTEST0000000000000000000_num_7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_7-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 7',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_7',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_8-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_8',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 8',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 8',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_8',
|
||||
'unique_id': '01JTEST0000000000000000000_num_8',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_8-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 8',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_8',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_9-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_number_9',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Number 9',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Number 9',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'num_9',
|
||||
'unique_id': '01JTEST0000000000000000000_num_9',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_number_9-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Number 9',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_number_9',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_repeat-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_repeat',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Repeat',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Repeat',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'repeat',
|
||||
'unique_id': '01JTEST0000000000000000000_repeat',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_repeat-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Repeat',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_repeat',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_scan-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.persang_speaker_scan',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Scan',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Scan',
|
||||
'platform': 'persang_infrared',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'scan',
|
||||
'unique_id': '01JTEST0000000000000000000_scan',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_entities[button.persang_speaker_scan-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Persang speaker Scan',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.persang_speaker_scan',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
@@ -0,0 +1,92 @@
|
||||
"""Tests for the Persang Infrared button platform."""
|
||||
|
||||
from infrared_protocols.codes.persang.speaker import PersangSpeakerCode
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
from .conftest import MOCK_INFRARED_EMITTER_ENTITY_ID
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
from tests.components.common import assert_availability_follows_source_entity
|
||||
from tests.components.infrared.common import MockInfraredEmitterEntity
|
||||
|
||||
BUTTON_ENTITY_ID_MODE = "button.persang_speaker_mode"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def platforms() -> list[Platform]:
|
||||
"""Return platforms to set up."""
|
||||
return [Platform.BUTTON]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_integration")
|
||||
async def test_entities(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test all button entities are created with the correct attributes."""
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
device_entry = device_registry.async_get_device_by_identifier(
|
||||
("persang_infrared", mock_config_entry.entry_id), mock_config_entry.entry_id
|
||||
)
|
||||
assert device_entry
|
||||
entity_entries = er.async_entries_for_config_entry(
|
||||
entity_registry, mock_config_entry.entry_id
|
||||
)
|
||||
for entity_entry in entity_entries:
|
||||
assert entity_entry.device_id == device_entry.id
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_id", "expected_code"),
|
||||
[
|
||||
("button.persang_speaker_mode", PersangSpeakerCode.MODE),
|
||||
("button.persang_speaker_equalizer", PersangSpeakerCode.EQ),
|
||||
("button.persang_speaker_scan", PersangSpeakerCode.SCAN),
|
||||
("button.persang_speaker_repeat", PersangSpeakerCode.REPEAT),
|
||||
("button.persang_speaker_number_0", PersangSpeakerCode.NUM_0),
|
||||
("button.persang_speaker_number_1", PersangSpeakerCode.NUM_1),
|
||||
("button.persang_speaker_number_2", PersangSpeakerCode.NUM_2),
|
||||
("button.persang_speaker_number_3", PersangSpeakerCode.NUM_3),
|
||||
("button.persang_speaker_number_4", PersangSpeakerCode.NUM_4),
|
||||
("button.persang_speaker_number_5", PersangSpeakerCode.NUM_5),
|
||||
("button.persang_speaker_number_6", PersangSpeakerCode.NUM_6),
|
||||
("button.persang_speaker_number_7", PersangSpeakerCode.NUM_7),
|
||||
("button.persang_speaker_number_8", PersangSpeakerCode.NUM_8),
|
||||
("button.persang_speaker_number_9", PersangSpeakerCode.NUM_9),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("init_integration")
|
||||
async def test_button_press_sends_correct_code(
|
||||
hass: HomeAssistant,
|
||||
mock_infrared_emitter_entity: MockInfraredEmitterEntity,
|
||||
entity_id: str,
|
||||
expected_code: PersangSpeakerCode,
|
||||
) -> None:
|
||||
"""Test pressing a button sends the correct IR code."""
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_infrared_emitter_entity.send_command_calls) == 1
|
||||
assert mock_infrared_emitter_entity.send_command_calls[0] == expected_code
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_integration")
|
||||
async def test_button_availability_follows_ir_entity(hass: HomeAssistant) -> None:
|
||||
"""Test a button becomes unavailable when the IR entity is unavailable."""
|
||||
await assert_availability_follows_source_entity(
|
||||
hass, BUTTON_ENTITY_ID_MODE, MOCK_INFRARED_EMITTER_ENTITY_ID
|
||||
)
|
||||
Reference in New Issue
Block a user