Add AC buttons to LG Infrared (#180842)

This commit is contained in:
Dr.Blank
2026-09-01 10:24:16 +01:00
committed by GitHub
parent 3962dd13a2
commit f874e62fa3
6 changed files with 694 additions and 70 deletions
+76 -7
View File
@@ -3,11 +3,13 @@
from dataclasses import dataclass
from typing import override
from infrared_protocols.codes.lg.ac import LGACCode
from infrared_protocols.codes.lg.tv import LGTVCode
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.components.infrared import InfraredEmitterConsumerEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
@@ -21,7 +23,7 @@ PARALLEL_UPDATES = 1
class LgIrButtonEntityDescription(ButtonEntityDescription):
"""Describes LG IR button entity."""
command_code: LGTVCode
command_code: LGTVCode | LGACCode
TV_BUTTON_DESCRIPTIONS: tuple[LgIrButtonEntityDescription, ...] = (
@@ -114,6 +116,70 @@ TV_BUTTON_DESCRIPTIONS: tuple[LgIrButtonEntityDescription, ...] = (
),
)
# One-shot AC actions with no discrete on/off code, so each is a momentary button.
AC_BUTTON_DESCRIPTIONS: tuple[LgIrButtonEntityDescription, ...] = (
LgIrButtonEntityDescription(
key="jet", translation_key="jet", command_code=LGACCode.JET
),
LgIrButtonEntityDescription(
key="eco", translation_key="eco", command_code=LGACCode.ECO
),
# A separate boost from JET, only offered on LG India units, so it is
# disabled by default.
LgIrButtonEntityDescription(
key="viraat",
translation_key="viraat",
command_code=LGACCode.VIRAAT,
entity_registry_enabled_default=False,
),
LgIrButtonEntityDescription(
key="ai_convertible",
translation_key="ai_convertible",
command_code=LGACCode.AI_CONVERTIBLE,
),
LgIrButtonEntityDescription(
key="light",
translation_key="light",
command_code=LGACCode.LIGHT_TOGGLE,
entity_category=EntityCategory.CONFIG,
),
LgIrButtonEntityDescription(
key="wifi",
translation_key="wifi",
command_code=LGACCode.WIFI_TOGGLE,
entity_category=EntityCategory.CONFIG,
),
LgIrButtonEntityDescription(
key="audio",
translation_key="audio",
command_code=LGACCode.AUDIO_TOGGLE,
entity_category=EntityCategory.CONFIG,
),
LgIrButtonEntityDescription(
key="diagnose",
translation_key="diagnose",
command_code=LGACCode.DIAGNOSE,
entity_category=EntityCategory.DIAGNOSTIC,
),
# Only flips between auto-swing and off; the climate swing dropdown supersedes it,
# so it is kept for older units but disabled by default.
LgIrButtonEntityDescription(
key="swing_v_toggle",
translation_key="swing_v_toggle",
command_code=LGACCode.SWING_V_TOGGLE,
entity_registry_enabled_default=False,
),
)
_DEVICE_BUTTONS: dict[LGDeviceType, tuple[LgIrButtonEntityDescription, ...]] = {
LGDeviceType.TV: TV_BUTTON_DESCRIPTIONS,
LGDeviceType.AC: AC_BUTTON_DESCRIPTIONS,
}
_DEVICE_NAMES: dict[LGDeviceType, str] = {
LGDeviceType.TV: "LG TV",
LGDeviceType.AC: "LG AC",
}
async def async_setup_entry(
hass: HomeAssistant,
@@ -125,11 +191,11 @@ async def async_setup_entry(
return
device_type = entry.data[CONF_DEVICE_TYPE]
if device_type == LGDeviceType.TV:
async_add_entities(
LgIrButton(entry, infrared_entity_id, description)
for description in TV_BUTTON_DESCRIPTIONS
)
device_name = _DEVICE_NAMES[device_type]
async_add_entities(
LgIrButton(entry, infrared_entity_id, description, device_name)
for description in _DEVICE_BUTTONS[device_type]
)
class LgIrButton(LgIrEntity, InfraredEmitterConsumerEntity, ButtonEntity):
@@ -142,9 +208,12 @@ class LgIrButton(LgIrEntity, InfraredEmitterConsumerEntity, ButtonEntity):
entry: ConfigEntry,
infrared_entity_id: str,
description: LgIrButtonEntityDescription,
device_name: str,
) -> None:
"""Initialize LG IR button."""
super().__init__(entry, unique_id_suffix=description.key)
super().__init__(
entry, unique_id_suffix=description.key, device_name=device_name
)
self._infrared_emitter_entity_id = infrared_entity_id
self.entity_description = description
@@ -1,12 +1,24 @@
{
"entity": {
"button": {
"ai_convertible": {
"default": "mdi:brain"
},
"audio": {
"default": "mdi:volume-high"
},
"back": {
"default": "mdi:keyboard-backspace"
},
"diagnose": {
"default": "mdi:stethoscope"
},
"down": {
"default": "mdi:arrow-down"
},
"eco": {
"default": "mdi:leaf"
},
"exit": {
"default": "mdi:exit-to-app"
},
@@ -34,9 +46,15 @@
"input": {
"default": "mdi:import"
},
"jet": {
"default": "mdi:fan-chevron-up"
},
"left": {
"default": "mdi:arrow-left"
},
"light": {
"default": "mdi:led-on"
},
"menu": {
"default": "mdi:menu"
},
@@ -85,8 +103,17 @@
"right": {
"default": "mdi:arrow-right"
},
"swing_v_toggle": {
"default": "mdi:arrow-up-down"
},
"up": {
"default": "mdi:arrow-up"
},
"viraat": {
"default": "mdi:rocket-launch"
},
"wifi": {
"default": "mdi:wifi"
}
},
"climate": {
@@ -84,10 +84,7 @@ rules:
Each config entry creates a single device.
entity-category: done
entity-device-class: done
entity-disabled-by-default:
status: exempt
comment: |
No entities should be disabled by default.
entity-disabled-by-default: done
entity-translations: done
exception-translations:
status: exempt
@@ -47,12 +47,24 @@
},
"entity": {
"button": {
"ai_convertible": {
"name": "AI mode"
},
"audio": {
"name": "Toggle beep"
},
"back": {
"name": "[%key:common::entity::button::back::name%]"
},
"diagnose": {
"name": "Diagnose"
},
"down": {
"name": "[%key:common::entity::button::down::name%]"
},
"eco": {
"name": "Eco mode"
},
"exit": {
"name": "[%key:common::entity::button::exit::name%]"
},
@@ -80,9 +92,15 @@
"input": {
"name": "[%key:common::entity::button::input::name%]"
},
"jet": {
"name": "Jet mode"
},
"left": {
"name": "[%key:common::entity::button::left::name%]"
},
"light": {
"name": "Toggle light"
},
"menu": {
"name": "[%key:common::entity::button::menu::name%]"
},
@@ -131,8 +149,17 @@
"right": {
"name": "[%key:common::entity::button::right::name%]"
},
"swing_v_toggle": {
"name": "Toggle vertical swing"
},
"up": {
"name": "[%key:common::entity::button::up::name%]"
},
"viraat": {
"name": "Viraat mode"
},
"wifi": {
"name": "Start Wi-Fi pairing"
}
},
"climate": {
@@ -1,5 +1,455 @@
# serializer version: 1
# name: test_entities[button.lg_tv_back-entry]
# name: test_entities[ac][button.lg_ac_ai_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.lg_ac_ai_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'AI mode',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'AI mode',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'ai_convertible',
'unique_id': '01JTEST0000000000000000000_ai_convertible',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_ai_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC AI mode',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_ai_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_diagnose-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': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.lg_ac_diagnose',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Diagnose',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Diagnose',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'diagnose',
'unique_id': '01JTEST0000000000000000000_diagnose',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_diagnose-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Diagnose',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_diagnose',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_eco_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.lg_ac_eco_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Eco mode',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Eco mode',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'eco',
'unique_id': '01JTEST0000000000000000000_eco',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_eco_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Eco mode',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_eco_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_jet_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.lg_ac_jet_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Jet mode',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Jet mode',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'jet',
'unique_id': '01JTEST0000000000000000000_jet',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_jet_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Jet mode',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_jet_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_start_wi_fi_pairing-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': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'button.lg_ac_start_wi_fi_pairing',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Start Wi-Fi pairing',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Start Wi-Fi pairing',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'wifi',
'unique_id': '01JTEST0000000000000000000_wifi',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_start_wi_fi_pairing-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Start Wi-Fi pairing',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_start_wi_fi_pairing',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_toggle_beep-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': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'button.lg_ac_toggle_beep',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Toggle beep',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Toggle beep',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'audio',
'unique_id': '01JTEST0000000000000000000_audio',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_toggle_beep-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Toggle beep',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_toggle_beep',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_toggle_light-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': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'button.lg_ac_toggle_light',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Toggle light',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Toggle light',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'light',
'unique_id': '01JTEST0000000000000000000_light',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_toggle_light-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Toggle light',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_toggle_light',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_toggle_vertical_swing-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.lg_ac_toggle_vertical_swing',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Toggle vertical swing',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Toggle vertical swing',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'swing_v_toggle',
'unique_id': '01JTEST0000000000000000000_swing_v_toggle',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_toggle_vertical_swing-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Toggle vertical swing',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_toggle_vertical_swing',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[ac][button.lg_ac_viraat_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.lg_ac_viraat_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Viraat mode',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Viraat mode',
'platform': 'lg_infrared',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'viraat',
'unique_id': '01JTEST0000000000000000000_viraat',
'unit_of_measurement': None,
})
# ---
# name: test_entities[ac][button.lg_ac_viraat_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG AC Viraat mode',
}),
'context': <ANY>,
'entity_id': 'button.lg_ac_viraat_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_entities[tv][button.lg_tv_back-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -36,7 +486,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_back-state]
# name: test_entities[tv][button.lg_tv_back-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Back',
@@ -49,7 +499,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_down-entry]
# name: test_entities[tv][button.lg_tv_down-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -86,7 +536,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_down-state]
# name: test_entities[tv][button.lg_tv_down-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Down',
@@ -99,7 +549,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_exit-entry]
# name: test_entities[tv][button.lg_tv_exit-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -136,7 +586,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_exit-state]
# name: test_entities[tv][button.lg_tv_exit-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Exit',
@@ -149,7 +599,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_guide-entry]
# name: test_entities[tv][button.lg_tv_guide-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -186,7 +636,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_guide-state]
# name: test_entities[tv][button.lg_tv_guide-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Guide',
@@ -199,7 +649,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_hdmi_1-entry]
# name: test_entities[tv][button.lg_tv_hdmi_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -236,7 +686,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_hdmi_1-state]
# name: test_entities[tv][button.lg_tv_hdmi_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV HDMI 1',
@@ -249,7 +699,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_hdmi_2-entry]
# name: test_entities[tv][button.lg_tv_hdmi_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -286,7 +736,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_hdmi_2-state]
# name: test_entities[tv][button.lg_tv_hdmi_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV HDMI 2',
@@ -299,7 +749,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_hdmi_3-entry]
# name: test_entities[tv][button.lg_tv_hdmi_3-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -336,7 +786,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_hdmi_3-state]
# name: test_entities[tv][button.lg_tv_hdmi_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV HDMI 3',
@@ -349,7 +799,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_hdmi_4-entry]
# name: test_entities[tv][button.lg_tv_hdmi_4-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -386,7 +836,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_hdmi_4-state]
# name: test_entities[tv][button.lg_tv_hdmi_4-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV HDMI 4',
@@ -399,7 +849,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_home-entry]
# name: test_entities[tv][button.lg_tv_home-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -436,7 +886,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_home-state]
# name: test_entities[tv][button.lg_tv_home-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Home',
@@ -449,7 +899,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_info-entry]
# name: test_entities[tv][button.lg_tv_info-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -486,7 +936,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_info-state]
# name: test_entities[tv][button.lg_tv_info-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Info',
@@ -499,7 +949,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_input-entry]
# name: test_entities[tv][button.lg_tv_input-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -536,7 +986,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_input-state]
# name: test_entities[tv][button.lg_tv_input-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Input',
@@ -549,7 +999,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_left-entry]
# name: test_entities[tv][button.lg_tv_left-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -586,7 +1036,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_left-state]
# name: test_entities[tv][button.lg_tv_left-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Left',
@@ -599,7 +1049,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_menu-entry]
# name: test_entities[tv][button.lg_tv_menu-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -636,7 +1086,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_menu-state]
# name: test_entities[tv][button.lg_tv_menu-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Menu',
@@ -649,7 +1099,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_0-entry]
# name: test_entities[tv][button.lg_tv_number_0-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -686,7 +1136,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_0-state]
# name: test_entities[tv][button.lg_tv_number_0-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 0',
@@ -699,7 +1149,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_1-entry]
# name: test_entities[tv][button.lg_tv_number_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -736,7 +1186,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_1-state]
# name: test_entities[tv][button.lg_tv_number_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 1',
@@ -749,7 +1199,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_2-entry]
# name: test_entities[tv][button.lg_tv_number_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -786,7 +1236,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_2-state]
# name: test_entities[tv][button.lg_tv_number_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 2',
@@ -799,7 +1249,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_3-entry]
# name: test_entities[tv][button.lg_tv_number_3-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -836,7 +1286,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_3-state]
# name: test_entities[tv][button.lg_tv_number_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 3',
@@ -849,7 +1299,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_4-entry]
# name: test_entities[tv][button.lg_tv_number_4-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -886,7 +1336,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_4-state]
# name: test_entities[tv][button.lg_tv_number_4-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 4',
@@ -899,7 +1349,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_5-entry]
# name: test_entities[tv][button.lg_tv_number_5-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -936,7 +1386,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_5-state]
# name: test_entities[tv][button.lg_tv_number_5-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 5',
@@ -949,7 +1399,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_6-entry]
# name: test_entities[tv][button.lg_tv_number_6-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -986,7 +1436,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_6-state]
# name: test_entities[tv][button.lg_tv_number_6-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 6',
@@ -999,7 +1449,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_7-entry]
# name: test_entities[tv][button.lg_tv_number_7-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1036,7 +1486,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_7-state]
# name: test_entities[tv][button.lg_tv_number_7-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 7',
@@ -1049,7 +1499,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_8-entry]
# name: test_entities[tv][button.lg_tv_number_8-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1086,7 +1536,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_8-state]
# name: test_entities[tv][button.lg_tv_number_8-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 8',
@@ -1099,7 +1549,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_number_9-entry]
# name: test_entities[tv][button.lg_tv_number_9-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1136,7 +1586,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_number_9-state]
# name: test_entities[tv][button.lg_tv_number_9-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Number 9',
@@ -1149,7 +1599,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_ok-entry]
# name: test_entities[tv][button.lg_tv_ok-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1186,7 +1636,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_ok-state]
# name: test_entities[tv][button.lg_tv_ok-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV OK',
@@ -1199,7 +1649,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_power-entry]
# name: test_entities[tv][button.lg_tv_power-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1236,7 +1686,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_power-state]
# name: test_entities[tv][button.lg_tv_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Power',
@@ -1249,7 +1699,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_power_off-entry]
# name: test_entities[tv][button.lg_tv_power_off-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1286,7 +1736,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_power_off-state]
# name: test_entities[tv][button.lg_tv_power_off-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Power off',
@@ -1299,7 +1749,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_power_on-entry]
# name: test_entities[tv][button.lg_tv_power_on-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1336,7 +1786,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_power_on-state]
# name: test_entities[tv][button.lg_tv_power_on-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Power on',
@@ -1349,7 +1799,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_right-entry]
# name: test_entities[tv][button.lg_tv_right-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1386,7 +1836,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_right-state]
# name: test_entities[tv][button.lg_tv_right-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Right',
@@ -1399,7 +1849,7 @@
'state': 'unknown',
})
# ---
# name: test_entities[button.lg_tv_up-entry]
# name: test_entities[tv][button.lg_tv_up-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1436,7 +1886,7 @@
'unit_of_measurement': None,
})
# ---
# name: test_entities[button.lg_tv_up-state]
# name: test_entities[tv][button.lg_tv_up-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'LG TV Up',
+55 -1
View File
@@ -1,10 +1,12 @@
"""Tests for the LG Infrared button platform."""
from infrared_protocols.codes.lg.ac import LGACCode
from infrared_protocols.codes.lg.tv import LGTVCode
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.components.lg_infrared.const import LGDeviceType
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
@@ -21,7 +23,8 @@ def platforms() -> list[Platform]:
return [Platform.BUTTON]
@pytest.mark.usefixtures("init_integration")
@pytest.mark.parametrize("device_type", [LGDeviceType.TV, LGDeviceType.AC])
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
async def test_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
@@ -104,3 +107,54 @@ async def test_button_availability_follows_ir_entity(
"""Test button becomes unavailable when IR entity is unavailable."""
entity_id = "button.lg_tv_power_on"
await assert_availability_follows_source_entity(hass, entity_id, EMITTER_ENTITY_ID)
@pytest.mark.parametrize("device_type", [LGDeviceType.AC])
@pytest.mark.parametrize(
("entity_id", "expected_code"),
[
("button.lg_ac_jet_mode", LGACCode.JET),
("button.lg_ac_eco_mode", LGACCode.ECO),
("button.lg_ac_viraat_mode", LGACCode.VIRAAT),
("button.lg_ac_ai_mode", LGACCode.AI_CONVERTIBLE),
("button.lg_ac_toggle_light", LGACCode.LIGHT_TOGGLE),
("button.lg_ac_start_wi_fi_pairing", LGACCode.WIFI_TOGGLE),
("button.lg_ac_toggle_beep", LGACCode.AUDIO_TOGGLE),
("button.lg_ac_diagnose", LGACCode.DIAGNOSE),
("button.lg_ac_toggle_vertical_swing", LGACCode.SWING_V_TOGGLE),
],
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
async def test_ac_button_press_sends_correct_code(
hass: HomeAssistant,
mock_infrared_emitter_entity: MockInfraredEmitterEntity,
entity_id: str,
expected_code: LGACCode,
) -> None:
"""Test pressing an AC button sends the matching fixed 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
timings = mock_infrared_emitter_entity.send_command_calls[0].get_raw_timings()
assert timings == expected_code.to_command().get_raw_timings()
@pytest.mark.parametrize("device_type", [LGDeviceType.AC])
@pytest.mark.parametrize("key", ["swing_v_toggle", "viraat"])
@pytest.mark.usefixtures("init_integration")
async def test_ac_buttons_disabled_by_default(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
key: str,
) -> None:
"""Test the buttons only some units support are registered but disabled."""
entity_id = entity_registry.async_get_entity_id(
BUTTON_DOMAIN, "lg_infrared", f"{mock_config_entry.entry_id}_{key}"
)
assert entity_id is not None
entry = entity_registry.async_get(entity_id)
assert entry is not None
assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION