Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion homeassistant/components/asuswrt/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["aioasuswrt", "asyncssh"],
"requirements": ["aioasuswrt==1.4.0", "asusrouter==1.18.1"]
"requirements": ["aioasuswrt==1.4.0", "asusrouter==1.18.2"]
}
12 changes: 1 addition & 11 deletions homeassistant/components/esphome/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from __future__ import annotations

import asyncio
import base64
from functools import partial
import logging
Expand All @@ -15,7 +14,6 @@
APIVersion,
DeviceInfo as EsphomeDeviceInfo,
EncryptionPlaintextAPIError,
EntityInfo,
HomeassistantServiceCall,
InvalidAuthAPIError,
InvalidEncryptionKeyAPIError,
Expand Down Expand Up @@ -63,7 +61,6 @@
)
from homeassistant.helpers.service import async_set_service_schema
from homeassistant.helpers.template import Template
from homeassistant.util.async_ import create_eager_task

from .bluetooth import async_connect_scanner
from .const import (
Expand Down Expand Up @@ -425,14 +422,7 @@ async def _on_connect(self) -> None:
unique_id_is_mac_address = unique_id and ":" in unique_id
if entry.options.get(CONF_SUBSCRIBE_LOGS):
self._async_subscribe_logs(self._async_get_equivalent_log_level())
results = await asyncio.gather(
create_eager_task(cli.device_info()),
create_eager_task(cli.list_entities_services()),
)

device_info: EsphomeDeviceInfo = results[0]
entity_infos_services: tuple[list[EntityInfo], list[UserService]] = results[1]
entity_infos, services = entity_infos_services
device_info, entity_infos, services = await cli.device_info_and_list_entities()

device_mac = format_mac(device_info.mac_address)
mac_address_matches = unique_id == device_mac
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/esphome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"mqtt": ["esphome/discover/#"],
"quality_scale": "platinum",
"requirements": [
"aioesphomeapi==38.2.1",
"aioesphomeapi==39.0.0",
"esphome-dashboard-api==1.3.0",
"bleak-esphome==3.1.0"
],
Expand Down
18 changes: 17 additions & 1 deletion homeassistant/components/tuya/humidifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ class TuyaHumidifierEntityDescription(HumidifierEntityDescription):
humidity: DPCode | None = None


def _has_a_valid_dpcode(
device: CustomerDevice, description: TuyaHumidifierEntityDescription
) -> bool:
"""Check if the device has at least one valid DP code."""
properties_to_check: list[DPCode | tuple[DPCode, ...] | None] = [
# Main control switch
description.dpcode or DPCode(description.key),
# Other humidity properties
description.current_humidity,
description.humidity,
]
return any(get_dpcode(device, code) for code in properties_to_check)


HUMIDIFIERS: dict[str, TuyaHumidifierEntityDescription] = {
# Dehumidifier
# https://developer.tuya.com/en/docs/iot/categorycs?id=Kaiuz1vcz4dha
Expand Down Expand Up @@ -71,7 +85,9 @@ def async_discover_device(device_ids: list[str]) -> None:
entities: list[TuyaHumidifierEntity] = []
for device_id in device_ids:
device = hass_data.manager.device_map[device_id]
if description := HUMIDIFIERS.get(device.category):
if (
description := HUMIDIFIERS.get(device.category)
) and _has_a_valid_dpcode(device, description):
entities.append(
TuyaHumidifierEntity(device, hass_data.manager, description)
)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/package_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ standard-telnetlib==3.13.0
typing-extensions>=4.14.0,<5.0
ulid-transform==1.4.0
urllib3>=2.0
uv==0.7.1
uv==0.8.9
voluptuous-openapi==0.1.0
voluptuous-serialize==2.6.0
voluptuous==0.15.2
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ dependencies = [
"typing-extensions>=4.14.0,<5.0",
"ulid-transform==1.4.0",
"urllib3>=2.0",
"uv==0.7.1",
"uv==0.8.9",
"voluptuous==0.15.2",
"voluptuous-serialize==2.6.0",
"voluptuous-openapi==0.1.0",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions requirements_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions requirements_test_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion script/hassfest/docker/Dockerfile

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tests/components/esphome/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@ def unsub():
mock_client.list_entities_services = AsyncMock(
return_value=mock_list_entities_services
)
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(mock_device.device_info, *mock_list_entities_services)
)

def _subscribe_home_assistant_states_and_services(
*,
Expand Down
80 changes: 53 additions & 27 deletions tests/components/esphome/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1045,8 +1045,11 @@ async def test_encryption_key_valid_psk(
assert result["step_id"] == "encryption_key"
assert result["description_placeholders"] == {"name": "ESPHome"}

mock_client.device_info = AsyncMock(
return_value=DeviceInfo(uses_password=False, name="test")
device_info = DeviceInfo(uses_password=False, name="test")
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_NOISE_PSK: VALID_NOISE_PSK}
Expand Down Expand Up @@ -1363,10 +1366,13 @@ async def test_reauth_confirm_invalid(
assert result["errors"]
assert result["errors"]["base"] == "invalid_psk"

mock_client.device_info = AsyncMock(
return_value=DeviceInfo(
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
)
device_info = DeviceInfo(
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
)
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_NOISE_PSK: VALID_NOISE_PSK}
Expand Down Expand Up @@ -1404,10 +1410,13 @@ async def test_reauth_confirm_invalid_with_unique_id(
assert result["errors"]
assert result["errors"]["base"] == "invalid_psk"

mock_client.device_info = AsyncMock(
return_value=DeviceInfo(
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
)
device_info = DeviceInfo(
uses_password=False, name="test", mac_address="11:22:33:44:55:aa"
)
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_NOISE_PSK: VALID_NOISE_PSK}
Expand Down Expand Up @@ -1460,8 +1469,11 @@ async def test_discovery_dhcp_updates_host(
unique_id="11:22:33:44:55:aa",
)
entry.add_to_hass(hass)
mock_client.device_info = AsyncMock(
return_value=DeviceInfo(name="test8266", mac_address="1122334455aa")
device_info = DeviceInfo(name="test8266", mac_address="1122334455aa")
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)

service_info = DhcpServiceInfo(
Expand Down Expand Up @@ -1496,8 +1508,11 @@ async def test_discovery_dhcp_does_not_update_host_wrong_mac(
unique_id="11:22:33:44:55:aa",
)
entry.add_to_hass(hass)
mock_client.device_info = AsyncMock(
return_value=DeviceInfo(name="test8266", mac_address="1122334455ff")
device_info = DeviceInfo(name="test8266", mac_address="1122334455ff")
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)

service_info = DhcpServiceInfo(
Expand Down Expand Up @@ -1602,7 +1617,12 @@ async def test_discovery_dhcp_no_changes(
)
entry.add_to_hass(hass)

mock_client.device_info = AsyncMock(return_value=DeviceInfo(name="test8266"))
device_info = DeviceInfo(name="test8266")
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)

service_info = DhcpServiceInfo(
ip="192.168.43.183",
Expand Down Expand Up @@ -2034,12 +2054,15 @@ async def test_user_flow_name_conflict_migrate(
unique_id="11:22:33:44:55:cc",
)
existing_entry.add_to_hass(hass)
mock_client.device_info = AsyncMock(
return_value=DeviceInfo(
uses_password=False,
name="test",
mac_address="11:22:33:44:55:AA",
)
device_info = DeviceInfo(
uses_password=False,
name="test",
mac_address="11:22:33:44:55:AA",
)
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)

result = await hass.config_entries.flow.async_init(
Expand Down Expand Up @@ -2084,12 +2107,15 @@ async def test_user_flow_name_conflict_overwrite(
unique_id="11:22:33:44:55:cc",
)
existing_entry.add_to_hass(hass)
mock_client.device_info = AsyncMock(
return_value=DeviceInfo(
uses_password=False,
name="test",
mac_address="11:22:33:44:55:AA",
)
device_info = DeviceInfo(
uses_password=False,
name="test",
mac_address="11:22:33:44:55:AA",
)
mock_client.device_info = AsyncMock(return_value=device_info)
mock_client.list_entities_services = AsyncMock(return_value=([], []))
mock_client.device_info_and_list_entities = AsyncMock(
return_value=(device_info, [], [])
)

result = await hass.config_entries.flow.async_init(
Expand Down
Loading
Loading