mirror of
https://github.com/home-assistant/core.git
synced 2025-09-05 12:51:37 +02:00
Ensure Tuya fans have at least one valid DPCode (#150550)
This commit is contained in:
@@ -26,6 +26,16 @@ from .entity import TuyaEntity
|
|||||||
from .models import EnumTypeData, IntegerTypeData
|
from .models import EnumTypeData, IntegerTypeData
|
||||||
from .util import get_dpcode
|
from .util import get_dpcode
|
||||||
|
|
||||||
|
_DIRECTION_DPCODES = (DPCode.FAN_DIRECTION,)
|
||||||
|
_OSCILLATE_DPCODES = (DPCode.SWITCH_HORIZONTAL, DPCode.SWITCH_VERTICAL)
|
||||||
|
_SPEED_DPCODES = (
|
||||||
|
DPCode.FAN_SPEED_PERCENT,
|
||||||
|
DPCode.FAN_SPEED,
|
||||||
|
DPCode.SPEED,
|
||||||
|
DPCode.FAN_SPEED_ENUM,
|
||||||
|
)
|
||||||
|
_SWITCH_DPCODES = (DPCode.SWITCH_FAN, DPCode.FAN_SWITCH, DPCode.SWITCH)
|
||||||
|
|
||||||
TUYA_SUPPORT_TYPE = {
|
TUYA_SUPPORT_TYPE = {
|
||||||
# Dehumidifier
|
# Dehumidifier
|
||||||
# https://developer.tuya.com/en/docs/iot/categorycs?id=Kaiuz1vcz4dha
|
# https://developer.tuya.com/en/docs/iot/categorycs?id=Kaiuz1vcz4dha
|
||||||
@@ -47,6 +57,19 @@ TUYA_SUPPORT_TYPE = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _has_a_valid_dpcode(device: CustomerDevice) -> bool:
|
||||||
|
"""Check if the device has at least one valid DP code."""
|
||||||
|
properties_to_check: list[DPCode | tuple[DPCode, ...] | None] = [
|
||||||
|
# Main control switch
|
||||||
|
_SWITCH_DPCODES,
|
||||||
|
# Other properties
|
||||||
|
_SPEED_DPCODES,
|
||||||
|
_OSCILLATE_DPCODES,
|
||||||
|
_DIRECTION_DPCODES,
|
||||||
|
]
|
||||||
|
return any(get_dpcode(device, code) for code in properties_to_check)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry: TuyaConfigEntry,
|
entry: TuyaConfigEntry,
|
||||||
@@ -61,7 +84,7 @@ async def async_setup_entry(
|
|||||||
entities: list[TuyaFanEntity] = []
|
entities: list[TuyaFanEntity] = []
|
||||||
for device_id in device_ids:
|
for device_id in device_ids:
|
||||||
device = hass_data.manager.device_map[device_id]
|
device = hass_data.manager.device_map[device_id]
|
||||||
if device and device.category in TUYA_SUPPORT_TYPE:
|
if device.category in TUYA_SUPPORT_TYPE and _has_a_valid_dpcode(device):
|
||||||
entities.append(TuyaFanEntity(device, hass_data.manager))
|
entities.append(TuyaFanEntity(device, hass_data.manager))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
@@ -91,9 +114,7 @@ class TuyaFanEntity(TuyaEntity, FanEntity):
|
|||||||
"""Init Tuya Fan Device."""
|
"""Init Tuya Fan Device."""
|
||||||
super().__init__(device, device_manager)
|
super().__init__(device, device_manager)
|
||||||
|
|
||||||
self._switch = get_dpcode(
|
self._switch = get_dpcode(self.device, _SWITCH_DPCODES)
|
||||||
self.device, (DPCode.SWITCH_FAN, DPCode.FAN_SWITCH, DPCode.SWITCH)
|
|
||||||
)
|
|
||||||
|
|
||||||
self._attr_preset_modes = []
|
self._attr_preset_modes = []
|
||||||
if enum_type := self.find_dpcode(
|
if enum_type := self.find_dpcode(
|
||||||
@@ -104,31 +125,23 @@ class TuyaFanEntity(TuyaEntity, FanEntity):
|
|||||||
self._attr_preset_modes = enum_type.range
|
self._attr_preset_modes = enum_type.range
|
||||||
|
|
||||||
# Find speed controls, can be either percentage or a set of speeds
|
# Find speed controls, can be either percentage or a set of speeds
|
||||||
dpcodes = (
|
|
||||||
DPCode.FAN_SPEED_PERCENT,
|
|
||||||
DPCode.FAN_SPEED,
|
|
||||||
DPCode.SPEED,
|
|
||||||
DPCode.FAN_SPEED_ENUM,
|
|
||||||
)
|
|
||||||
if int_type := self.find_dpcode(
|
if int_type := self.find_dpcode(
|
||||||
dpcodes, dptype=DPType.INTEGER, prefer_function=True
|
_SPEED_DPCODES, dptype=DPType.INTEGER, prefer_function=True
|
||||||
):
|
):
|
||||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||||
self._speed = int_type
|
self._speed = int_type
|
||||||
elif enum_type := self.find_dpcode(
|
elif enum_type := self.find_dpcode(
|
||||||
dpcodes, dptype=DPType.ENUM, prefer_function=True
|
_SPEED_DPCODES, dptype=DPType.ENUM, prefer_function=True
|
||||||
):
|
):
|
||||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||||
self._speeds = enum_type
|
self._speeds = enum_type
|
||||||
|
|
||||||
if dpcode := get_dpcode(
|
if dpcode := get_dpcode(self.device, _OSCILLATE_DPCODES):
|
||||||
self.device, (DPCode.SWITCH_HORIZONTAL, DPCode.SWITCH_VERTICAL)
|
|
||||||
):
|
|
||||||
self._oscillate = dpcode
|
self._oscillate = dpcode
|
||||||
self._attr_supported_features |= FanEntityFeature.OSCILLATE
|
self._attr_supported_features |= FanEntityFeature.OSCILLATE
|
||||||
|
|
||||||
if enum_type := self.find_dpcode(
|
if enum_type := self.find_dpcode(
|
||||||
DPCode.FAN_DIRECTION, dptype=DPType.ENUM, prefer_function=True
|
_DIRECTION_DPCODES, dptype=DPType.ENUM, prefer_function=True
|
||||||
):
|
):
|
||||||
self._direction = enum_type
|
self._direction = enum_type
|
||||||
self._attr_supported_features |= FanEntityFeature.DIRECTION
|
self._attr_supported_features |= FanEntityFeature.DIRECTION
|
||||||
|
@@ -204,9 +204,9 @@
|
|||||||
'platform': 'tuya',
|
'platform': 'tuya',
|
||||||
'previous_unique_id': None,
|
'previous_unique_id': None,
|
||||||
'suggested_object_id': None,
|
'suggested_object_id': None,
|
||||||
'supported_features': 0,
|
'supported_features': <FanEntityFeature: 48>,
|
||||||
'translation_key': None,
|
'translation_key': None,
|
||||||
'unique_id': 'tuya.ilms5pwjzzsxuxmvsc',
|
'unique_id': 'tuya.2myxayqtud9aqbizsc',
|
||||||
'unit_of_measurement': None,
|
'unit_of_measurement': None,
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
@@ -214,116 +214,16 @@
|
|||||||
StateSnapshot({
|
StateSnapshot({
|
||||||
'attributes': ReadOnlyDict({
|
'attributes': ReadOnlyDict({
|
||||||
'friendly_name': 'Dehumidifier',
|
'friendly_name': 'Dehumidifier',
|
||||||
'supported_features': <FanEntityFeature: 0>,
|
'supported_features': <FanEntityFeature: 48>,
|
||||||
}),
|
}),
|
||||||
'context': <ANY>,
|
'context': <ANY>,
|
||||||
'entity_id': 'fan.dehumidifier',
|
'entity_id': 'fan.dehumidifier',
|
||||||
'last_changed': <ANY>,
|
'last_changed': <ANY>,
|
||||||
'last_reported': <ANY>,
|
'last_reported': <ANY>,
|
||||||
'last_updated': <ANY>,
|
'last_updated': <ANY>,
|
||||||
'state': 'unknown',
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
# name: test_platform_setup_and_discovery[fan.dehumidifier_2-entry]
|
|
||||||
EntityRegistryEntrySnapshot({
|
|
||||||
'aliases': set({
|
|
||||||
}),
|
|
||||||
'area_id': None,
|
|
||||||
'capabilities': dict({
|
|
||||||
}),
|
|
||||||
'config_entry_id': <ANY>,
|
|
||||||
'config_subentry_id': <ANY>,
|
|
||||||
'device_class': None,
|
|
||||||
'device_id': <ANY>,
|
|
||||||
'disabled_by': None,
|
|
||||||
'domain': 'fan',
|
|
||||||
'entity_category': None,
|
|
||||||
'entity_id': 'fan.dehumidifier_2',
|
|
||||||
'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': None,
|
|
||||||
'platform': 'tuya',
|
|
||||||
'previous_unique_id': None,
|
|
||||||
'suggested_object_id': None,
|
|
||||||
'supported_features': <FanEntityFeature: 48>,
|
|
||||||
'translation_key': None,
|
|
||||||
'unique_id': 'tuya.2myxayqtud9aqbizsc',
|
|
||||||
'unit_of_measurement': None,
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
# name: test_platform_setup_and_discovery[fan.dehumidifier_2-state]
|
|
||||||
StateSnapshot({
|
|
||||||
'attributes': ReadOnlyDict({
|
|
||||||
'friendly_name': 'Dehumidifier',
|
|
||||||
'supported_features': <FanEntityFeature: 48>,
|
|
||||||
}),
|
|
||||||
'context': <ANY>,
|
|
||||||
'entity_id': 'fan.dehumidifier_2',
|
|
||||||
'last_changed': <ANY>,
|
|
||||||
'last_reported': <ANY>,
|
|
||||||
'last_updated': <ANY>,
|
|
||||||
'state': 'on',
|
'state': 'on',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_platform_setup_and_discovery[fan.dryfix-entry]
|
|
||||||
EntityRegistryEntrySnapshot({
|
|
||||||
'aliases': set({
|
|
||||||
}),
|
|
||||||
'area_id': None,
|
|
||||||
'capabilities': dict({
|
|
||||||
}),
|
|
||||||
'config_entry_id': <ANY>,
|
|
||||||
'config_subentry_id': <ANY>,
|
|
||||||
'device_class': None,
|
|
||||||
'device_id': <ANY>,
|
|
||||||
'disabled_by': None,
|
|
||||||
'domain': 'fan',
|
|
||||||
'entity_category': None,
|
|
||||||
'entity_id': 'fan.dryfix',
|
|
||||||
'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': None,
|
|
||||||
'platform': 'tuya',
|
|
||||||
'previous_unique_id': None,
|
|
||||||
'suggested_object_id': None,
|
|
||||||
'supported_features': 0,
|
|
||||||
'translation_key': None,
|
|
||||||
'unique_id': 'tuya.hz4pau766eavmxhqsc',
|
|
||||||
'unit_of_measurement': None,
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
# name: test_platform_setup_and_discovery[fan.dryfix-state]
|
|
||||||
StateSnapshot({
|
|
||||||
'attributes': ReadOnlyDict({
|
|
||||||
'friendly_name': 'DryFix',
|
|
||||||
'supported_features': <FanEntityFeature: 0>,
|
|
||||||
}),
|
|
||||||
'context': <ANY>,
|
|
||||||
'entity_id': 'fan.dryfix',
|
|
||||||
'last_changed': <ANY>,
|
|
||||||
'last_reported': <ANY>,
|
|
||||||
'last_updated': <ANY>,
|
|
||||||
'state': 'unavailable',
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
# name: test_platform_setup_and_discovery[fan.hl400-entry]
|
# name: test_platform_setup_and_discovery[fan.hl400-entry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
@@ -556,53 +456,3 @@
|
|||||||
'state': 'off',
|
'state': 'off',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_platform_setup_and_discovery[fan.ventilador_cama-entry]
|
|
||||||
EntityRegistryEntrySnapshot({
|
|
||||||
'aliases': set({
|
|
||||||
}),
|
|
||||||
'area_id': None,
|
|
||||||
'capabilities': dict({
|
|
||||||
}),
|
|
||||||
'config_entry_id': <ANY>,
|
|
||||||
'config_subentry_id': <ANY>,
|
|
||||||
'device_class': None,
|
|
||||||
'device_id': <ANY>,
|
|
||||||
'disabled_by': None,
|
|
||||||
'domain': 'fan',
|
|
||||||
'entity_category': None,
|
|
||||||
'entity_id': 'fan.ventilador_cama',
|
|
||||||
'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': None,
|
|
||||||
'platform': 'tuya',
|
|
||||||
'previous_unique_id': None,
|
|
||||||
'suggested_object_id': None,
|
|
||||||
'supported_features': 0,
|
|
||||||
'translation_key': None,
|
|
||||||
'unique_id': 'tuya.c1tfgunpf6optybisf',
|
|
||||||
'unit_of_measurement': None,
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
# name: test_platform_setup_and_discovery[fan.ventilador_cama-state]
|
|
||||||
StateSnapshot({
|
|
||||||
'attributes': ReadOnlyDict({
|
|
||||||
'friendly_name': 'Ventilador Cama',
|
|
||||||
'supported_features': <FanEntityFeature: 0>,
|
|
||||||
}),
|
|
||||||
'context': <ANY>,
|
|
||||||
'entity_id': 'fan.ventilador_cama',
|
|
||||||
'last_changed': <ANY>,
|
|
||||||
'last_reported': <ANY>,
|
|
||||||
'last_updated': <ANY>,
|
|
||||||
'state': 'unknown',
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
|
@@ -1601,7 +1601,7 @@
|
|||||||
'labels': set({
|
'labels': set({
|
||||||
}),
|
}),
|
||||||
'manufacturer': 'Tuya',
|
'manufacturer': 'Tuya',
|
||||||
'model': 'Tower bladeless fan ',
|
'model': 'Tower bladeless fan (unsupported)',
|
||||||
'model_id': 'ibytpo6fpnugft1c',
|
'model_id': 'ibytpo6fpnugft1c',
|
||||||
'name': 'Ventilador Cama',
|
'name': 'Ventilador Cama',
|
||||||
'name_by_user': None,
|
'name_by_user': None,
|
||||||
@@ -2593,7 +2593,7 @@
|
|||||||
'labels': set({
|
'labels': set({
|
||||||
}),
|
}),
|
||||||
'manufacturer': 'Tuya',
|
'manufacturer': 'Tuya',
|
||||||
'model': '',
|
'model': ' (unsupported)',
|
||||||
'model_id': 'qhxmvae667uap4zh',
|
'model_id': 'qhxmvae667uap4zh',
|
||||||
'name': 'DryFix',
|
'name': 'DryFix',
|
||||||
'name_by_user': None,
|
'name_by_user': None,
|
||||||
@@ -2779,7 +2779,7 @@
|
|||||||
'labels': set({
|
'labels': set({
|
||||||
}),
|
}),
|
||||||
'manufacturer': 'Tuya',
|
'manufacturer': 'Tuya',
|
||||||
'model': 'the Smart Dry Plus™ Connect Dehumidifier ',
|
'model': 'the Smart Dry Plus™ Connect Dehumidifier (unsupported)',
|
||||||
'model_id': 'vmxuxszzjwp5smli',
|
'model_id': 'vmxuxszzjwp5smli',
|
||||||
'name': 'Dehumidifier ',
|
'name': 'Dehumidifier ',
|
||||||
'name_by_user': None,
|
'name_by_user': None,
|
||||||
|
Reference in New Issue
Block a user