Compare commits

..

7 Commits

Author SHA1 Message Date
abmantis
9f485084da Remove receiver stuff 2026-02-28 01:46:49 +00:00
abmantis
63db1cc080 Fix merge 2026-02-28 01:43:38 +00:00
abmantis
91fab62af6 Narrow exception; fix tests 2026-02-28 01:25:16 +00:00
abmantis
e6f45bd9f6 Merge branch 'dev' of github.com:home-assistant/core into esphome_infrared 2026-02-28 00:43:00 +00:00
abmantis
ed1bb685da Dynamic modulation + cleanup 2026-02-05 22:23:29 +00:00
abmantis
6c610dfe73 Add infrared platform to ESPHome 2026-02-05 20:23:19 +00:00
abmantis
90bacbb98e Add infrared entity integration 2026-02-05 20:06:33 +00:00
53 changed files with 395 additions and 438 deletions

View File

@@ -29,6 +29,7 @@ from aioesphomeapi import (
Event,
EventInfo,
FanInfo,
InfraredInfo,
LightInfo,
LockInfo,
MediaPlayerInfo,
@@ -85,6 +86,7 @@ INFO_TYPE_TO_PLATFORM: dict[type[EntityInfo], Platform] = {
DateTimeInfo: Platform.DATETIME,
EventInfo: Platform.EVENT,
FanInfo: Platform.FAN,
InfraredInfo: Platform.INFRARED,
LightInfo: Platform.LIGHT,
LockInfo: Platform.LOCK,
MediaPlayerInfo: Platform.MEDIA_PLAYER,

View File

@@ -0,0 +1,106 @@
"""Infrared platform for ESPHome."""
from __future__ import annotations
import logging
from aioesphomeapi import (
APIConnectionError,
EntityInfo,
EntityState,
InfraredCapability,
InfraredInfo,
)
from homeassistant.components.infrared import InfraredCommand, InfraredEntity
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_platform
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN
from .entity import EsphomeEntity, async_static_info_updated
from .entry_data import ESPHomeConfigEntry
_LOGGER = logging.getLogger(__name__)
PARALLEL_UPDATES = 0
class EsphomeInfraredEntity(EsphomeEntity[InfraredInfo, EntityState], InfraredEntity):
"""ESPHome infrared entity using native API."""
_attr_has_entity_name = True
_attr_name = "Infrared Transmitter"
@callback
def _on_device_update(self) -> None:
"""Call when device updates or entry data changes."""
super()._on_device_update()
if self._entry_data.available:
# Infrared entities should go available as soon as the device comes online
self.async_write_ha_state()
async def async_send_command(self, command: InfraredCommand) -> None:
"""Send an IR command.
Raises:
HomeAssistantError: If transmission fails.
"""
timings = [
interval
for timing in command.get_raw_timings()
for interval in (timing.high_us, -timing.low_us)
]
_LOGGER.debug("Sending command: %s", timings)
try:
self._client.infrared_rf_transmit_raw_timings(
self._static_info.key,
carrier_frequency=command.modulation,
timings=timings,
)
except APIConnectionError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="error_sending_ir_command",
translation_placeholders={
"device_name": self._device_info.name,
"error": str(err),
},
) from err
async def async_setup_entry(
hass: HomeAssistant,
entry: ESPHomeConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up ESPHome infrared entities, filtering out receiver-only devices."""
entry_data = entry.runtime_data
entry_data.info[InfraredInfo] = {}
platform = entity_platform.async_get_current_platform()
def filtered_static_info_update(infos: list[EntityInfo]) -> None:
transmitter_infos: list[EntityInfo] = [
info
for info in infos
if isinstance(info, InfraredInfo)
and info.capabilities & InfraredCapability.TRANSMITTER
]
async_static_info_updated(
hass,
entry_data,
platform,
async_add_entities,
InfraredInfo,
EsphomeInfraredEntity,
EntityState,
transmitter_infos,
)
entry_data.cleanup_callbacks.append(
entry_data.async_register_static_info_callback(
InfraredInfo, filtered_static_info_update
)
)

View File

@@ -137,6 +137,9 @@
"error_compiling": {
"message": "Error compiling {configuration}. Try again in ESPHome dashboard for more information."
},
"error_sending_ir_command": {
"message": "Error sending IR command to {device_name}: {error}"
},
"error_uploading": {
"message": "Error during OTA (Over-The-Air) update of {configuration}. Try again in ESPHome dashboard for more information."
},

View File

@@ -78,12 +78,6 @@ query ($owner: String!, $repository: String!) {
number
}
}
merged_pull_request: pullRequests(
first:1
states: MERGED
) {
total: totalCount
}
release: latestRelease {
name
url

View File

@@ -28,9 +28,6 @@
"latest_tag": {
"default": "mdi:tag"
},
"merged_pulls_count": {
"default": "mdi:source-merge"
},
"pulls_count": {
"default": "mdi:source-pull"
},

View File

@@ -75,13 +75,6 @@ SENSOR_DESCRIPTIONS: tuple[GitHubSensorEntityDescription, ...] = (
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: data["pull_request"]["total"],
),
GitHubSensorEntityDescription(
key="merged_pulls_count",
translation_key="merged_pulls_count",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
value_fn=lambda data: data["merged_pull_request"]["total"],
),
GitHubSensorEntityDescription(
key="latest_commit",
translation_key="latest_commit",

View File

@@ -48,10 +48,6 @@
"latest_tag": {
"name": "Latest tag"
},
"merged_pulls_count": {
"name": "Merged pull requests",
"unit_of_measurement": "pull requests"
},
"pulls_count": {
"name": "Pull requests",
"unit_of_measurement": "pull requests"

View File

@@ -177,12 +177,6 @@
"on": "mdi:lightbulb-on"
}
},
"do_not_disturb": {
"default": "mdi:minus-circle-off",
"state": {
"on": "mdi:minus-circle"
}
},
"dry_plus": {
"default": "mdi:heat-wave"
},

View File

@@ -34,5 +34,5 @@
"iot_class": "cloud_push",
"loggers": ["pysmartthings"],
"quality_scale": "bronze",
"requirements": ["pysmartthings==3.6.0"]
"requirements": ["pysmartthings==3.5.3"]
}

View File

@@ -859,9 +859,6 @@
"display_lighting": {
"name": "Display lighting"
},
"do_not_disturb": {
"name": "Do not disturb"
},
"dry_plus": {
"name": "Dry plus"
},

View File

@@ -162,14 +162,6 @@ CAPABILITY_TO_SWITCHES: dict[Capability | str, SmartThingsSwitchEntityDescriptio
status_attribute=Attribute.STATUS,
entity_category=EntityCategory.CONFIG,
),
Capability.CUSTOM_DO_NOT_DISTURB_MODE: SmartThingsSwitchEntityDescription(
key=Capability.CUSTOM_DO_NOT_DISTURB_MODE,
translation_key="do_not_disturb",
status_attribute=Attribute.DO_NOT_DISTURB,
entity_category=EntityCategory.CONFIG,
on_command=Command.DO_NOT_DISTURB_ON,
off_command=Command.DO_NOT_DISTURB_OFF,
),
}
DISHWASHER_WASHING_OPTIONS_TO_SWITCHES: dict[
Attribute | str, SmartThingsDishwasherWashingOptionSwitchEntityDescription

2
requirements_all.txt generated
View File

@@ -2476,7 +2476,7 @@ pysmappee==0.2.29
pysmarlaapi==1.0.1
# homeassistant.components.smartthings
pysmartthings==3.6.0
pysmartthings==3.5.3
# homeassistant.components.smarty
pysmarty2==0.10.3

View File

@@ -2108,7 +2108,7 @@ pysmappee==0.2.29
pysmarlaapi==1.0.1
# homeassistant.components.smartthings
pysmartthings==3.6.0
pysmartthings==3.5.3
# homeassistant.components.smarty
pysmarty2==0.10.3

View File

@@ -70,15 +70,6 @@ def dummy_client_fixture() -> Generator[MagicMock]:
yield client.return_value
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.arcam_fmj.async_setup_entry", return_value=True
) as mock_setup:
yield mock_setup
async def test_ssdp(hass: HomeAssistant) -> None:
"""Test a ssdp import flow."""
result = await hass.config_entries.flow.async_init(

View File

@@ -19,16 +19,18 @@ async def test_setup_entry(config_entry_setup: MockConfigEntry) -> None:
async def test_setup_entry_fails(
hass: HomeAssistant, config_entry: MockConfigEntry
) -> None:
"""Test failed setup of entry."""
"""Test successful setup of entry."""
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.axis.get_axis_api",
side_effect=axis.CannotConnect,
):
await hass.config_entries.async_setup(config_entry.entry_id)
mock_device = Mock()
mock_device.async_setup = AsyncMock(return_value=False)
assert config_entry.state is ConfigEntryState.SETUP_RETRY
with patch.object(axis, "AxisHub") as mock_device_class:
mock_device_class.return_value = mock_device
assert not await hass.config_entries.async_setup(config_entry.entry_id)
assert config_entry.state is ConfigEntryState.SETUP_ERROR
async def test_unload_entry(

View File

@@ -79,9 +79,7 @@ async def test_form_invalid_host(
assert result2["type"] is FlowResultType.CREATE_ENTRY
async def test_form_cannot_connect(
hass: HomeAssistant, mock_setup_entry: AsyncMock
) -> None:
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
@@ -113,9 +111,7 @@ async def test_form_cannot_connect(
assert result2["type"] is FlowResultType.CREATE_ENTRY
async def test_form_unexpected_error(
hass: HomeAssistant, mock_setup_entry: AsyncMock
) -> None:
async def test_form_unexpected_error(hass: HomeAssistant) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}

View File

@@ -1,8 +1,7 @@
"""Tests for the Daikin config flow."""
from collections.abc import Generator
from ipaddress import ip_address
from unittest.mock import AsyncMock, PropertyMock, patch
from unittest.mock import PropertyMock, patch
from aiohttp import ClientError, web_exceptions
from pydaikin.exceptions import DaikinException
@@ -21,15 +20,6 @@ MAC = "AABBCCDDEEFF"
HOST = "127.0.0.1"
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.daikin.async_setup_entry", return_value=True
) as mock_setup:
yield mock_setup
@pytest.fixture
def mock_daikin():
"""Mock pydaikin."""

View File

@@ -849,19 +849,15 @@ async def test_unknown_exception(hass: HomeAssistant) -> None:
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
"""Test we handle invalid auth error."""
with _patch_discovery(no_device=True):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
mocked_elk = mock_elk(invalid_auth=True, sync_complete=True)
with (
_patch_discovery(no_device=True),
patch(
"homeassistant.components.elkm1.config_flow.Elk",
return_value=mocked_elk,
),
with patch(
"homeassistant.components.elkm1.config_flow.Elk",
return_value=mocked_elk,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -918,19 +914,15 @@ async def test_form_invalid_auth(hass: HomeAssistant) -> None:
async def test_form_invalid_auth_no_password(hass: HomeAssistant) -> None:
"""Test we handle invalid auth error when no password is provided."""
with _patch_discovery(no_device=True):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
mocked_elk = mock_elk(invalid_auth=True, sync_complete=True)
with (
_patch_discovery(no_device=True),
patch(
"homeassistant.components.elkm1.config_flow.Elk",
return_value=mocked_elk,
),
with patch(
"homeassistant.components.elkm1.config_flow.Elk",
return_value=mocked_elk,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -1999,7 +1991,6 @@ async def test_reconfigure_nonsecure(
mocked_elk = mock_elk(invalid_auth=False, sync_complete=True)
with (
_patch_discovery(no_device=True),
_patch_elk(mocked_elk),
patch(
"homeassistant.components.elkm1.async_setup_entry",

View File

@@ -1,10 +1,5 @@
"""Tests for emulated_roku config flow."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
import pytest
from homeassistant import config_entries
from homeassistant.components.emulated_roku import config_flow
from homeassistant.core import HomeAssistant
@@ -13,15 +8,6 @@ from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.emulated_roku.async_setup_entry", return_value=True
) as mock_setup:
yield mock_setup
async def test_flow_works(hass: HomeAssistant) -> None:
"""Test that config flow works."""
result = await hass.config_entries.flow.async_init(

View File

@@ -0,0 +1,172 @@
"""Test ESPHome infrared platform."""
from aioesphomeapi import (
APIClient,
APIConnectionError,
InfraredCapability,
InfraredInfo,
)
from infrared_protocols import NECCommand
import pytest
from homeassistant.components import infrared
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from .conftest import MockESPHomeDeviceType
ENTITY_ID = "infrared.test_ir"
async def _mock_ir_device(
mock_esphome_device: MockESPHomeDeviceType,
mock_client: APIClient,
capabilities: InfraredCapability = InfraredCapability.TRANSMITTER,
) -> MockESPHomeDeviceType:
entity_info = [
InfraredInfo(object_id="ir", key=1, name="IR", capabilities=capabilities)
]
return await mock_esphome_device(
mock_client=mock_client, entity_info=entity_info, states=[]
)
@pytest.mark.parametrize(
("capabilities", "entity_created"),
[
(InfraredCapability.TRANSMITTER, True),
(InfraredCapability.RECEIVER, False),
(InfraredCapability.TRANSMITTER | InfraredCapability.RECEIVER, True),
(0, False),
],
)
async def test_infrared_entity_transmitter(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
capabilities: InfraredCapability,
entity_created: bool,
) -> None:
"""Test infrared entity with transmitter capability is created."""
await _mock_ir_device(mock_esphome_device, mock_client, capabilities)
state = hass.states.get(ENTITY_ID)
assert (state is not None) == entity_created
emitters = infrared.async_get_emitters(hass)
assert (len(emitters) == 1) == entity_created
async def test_infrared_multiple_entities_mixed_capabilities(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
) -> None:
"""Test multiple infrared entities with mixed capabilities."""
entity_info = [
InfraredInfo(
object_id="ir_transmitter",
key=1,
name="IR Transmitter",
capabilities=InfraredCapability.TRANSMITTER,
),
InfraredInfo(
object_id="ir_receiver",
key=2,
name="IR Receiver",
capabilities=InfraredCapability.RECEIVER,
),
InfraredInfo(
object_id="ir_transceiver",
key=3,
name="IR Transceiver",
capabilities=InfraredCapability.TRANSMITTER | InfraredCapability.RECEIVER,
),
]
await mock_esphome_device(
mock_client=mock_client,
entity_info=entity_info,
states=[],
)
# Only transmitter and transceiver should be created
assert hass.states.get("infrared.test_ir_transmitter") is not None
assert hass.states.get("infrared.test_ir_receiver") is None
assert hass.states.get("infrared.test_ir_transceiver") is not None
emitters = infrared.async_get_emitters(hass)
assert len(emitters) == 2
async def test_infrared_send_command_success(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
) -> None:
"""Test sending IR command successfully."""
await _mock_ir_device(mock_esphome_device, mock_client)
command = NECCommand(address=0x04, command=0x08, modulation=38000)
await infrared.async_send_command(hass, ENTITY_ID, command)
# Verify the command was sent to the ESPHome client
mock_client.infrared_rf_transmit_raw_timings.assert_called_once()
call_args = mock_client.infrared_rf_transmit_raw_timings.call_args
assert call_args[0][0] == 1 # key
assert call_args[1]["carrier_frequency"] == 38000
# Verify timings (alternating positive/negative values)
timings = call_args[1]["timings"]
assert len(timings) > 0
for i in range(0, len(timings), 2):
assert timings[i] >= 0
for i in range(1, len(timings), 2):
assert timings[i] <= 0
async def test_infrared_send_command_failure(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
) -> None:
"""Test sending IR command with APIConnectionError raises HomeAssistantError."""
await _mock_ir_device(mock_esphome_device, mock_client)
mock_client.infrared_rf_transmit_raw_timings.side_effect = APIConnectionError(
"Connection lost"
)
command = NECCommand(address=0x04, command=0x08, modulation=38000)
with pytest.raises(HomeAssistantError) as exc_info:
await infrared.async_send_command(hass, ENTITY_ID, command)
assert exc_info.value.translation_domain == "esphome"
assert exc_info.value.translation_key == "error_sending_ir_command"
async def test_infrared_entity_availability(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
) -> None:
"""Test infrared entity becomes available after device reconnects."""
mock_device = await _mock_ir_device(mock_esphome_device, mock_client)
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state != STATE_UNAVAILABLE
await mock_device.mock_disconnect(False)
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state == STATE_UNAVAILABLE
await mock_device.mock_connect()
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state != STATE_UNAVAILABLE

View File

@@ -76,10 +76,6 @@ async def test_config_flow(hass: HomeAssistant, config_entry: MockConfigEntry) -
"homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request",
autospec=True,
) as mock_get_request,
patch(
"homeassistant.components.forked_daapd.async_setup_entry",
return_value=True,
),
):
mock_get_request.return_value = SAMPLE_CONFIG
mock_test_connection.return_value = ["ok", "My Music on myhost"]
@@ -233,16 +229,10 @@ async def test_config_flow_zeroconf_valid(hass: HomeAssistant) -> None:
async def test_options_flow(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Test config flow options."""
with (
patch(
"homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request",
autospec=True,
) as mock_get_request,
patch(
"homeassistant.components.forked_daapd.async_setup_entry",
return_value=True,
),
):
with patch(
"homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request",
autospec=True,
) as mock_get_request:
mock_get_request.return_value = SAMPLE_CONFIG
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)

View File

@@ -168,7 +168,6 @@ async def test_duplicate_updates_existing_entry(
async def test_dhcp_discovery_updates_entry(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
) -> None:
"""Test DHCP discovery updates config entries."""
mock_config_entry.add_to_hass(hass)

View File

@@ -49,9 +49,6 @@
}
]
},
"merged_pull_request": {
"total": 42
},
"release": {
"name": "v1.0.0",
"url": "https://github.com/octocat/Hello-World/releases/v1.0.0",

View File

@@ -336,13 +336,7 @@ async def test_entity_migration(
config_entry=config_entry_v1_1,
)
with (
patch("homeassistant.components.home_connect.PLATFORMS", platforms),
patch(
"homeassistant.components.home_connect.async_setup_entry",
return_value=True,
),
):
with patch("homeassistant.components.home_connect.PLATFORMS", platforms):
await hass.config_entries.async_setup(config_entry_v1_1.entry_id)
await hass.async_block_till_done()
@@ -370,12 +364,8 @@ async def test_config_entry_unique_id_migration(
assert config_entry_v1_2.unique_id != "1234567890"
assert config_entry_v1_2.minor_version == 2
with patch(
"homeassistant.components.home_connect.async_setup_entry",
return_value=True,
):
await hass.config_entries.async_setup(config_entry_v1_2.entry_id)
await hass.async_block_till_done()
await hass.config_entries.async_setup(config_entry_v1_2.entry_id)
await hass.async_block_till_done()
assert config_entry_v1_2.unique_id == "1234567890"
assert config_entry_v1_2.minor_version == 3

View File

@@ -1,7 +1,5 @@
"""The tests for the Homematic notification platform."""
from unittest.mock import MagicMock, patch
from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
@@ -11,15 +9,11 @@ from tests.common import assert_setup_component
async def test_setup_full(hass: HomeAssistant) -> None:
"""Test valid configuration."""
with patch(
"homeassistant.components.homematic.HMConnection",
return_value=MagicMock(),
):
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
with assert_setup_component(1, domain="notify") as handle_config:
assert await async_setup_component(
hass,
@@ -41,15 +35,11 @@ async def test_setup_full(hass: HomeAssistant) -> None:
async def test_setup_without_optional(hass: HomeAssistant) -> None:
"""Test valid configuration without optional."""
with patch(
"homeassistant.components.homematic.HMConnection",
return_value=MagicMock(),
):
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
with assert_setup_component(1, domain="notify") as handle_config:
assert await async_setup_component(
hass,

View File

@@ -136,7 +136,6 @@ def fixture_mock_config_entry() -> MockConfigEntry:
async def fixture_mock_integration(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_device: MagicMock,
) -> MockConfigEntry:
"""Return a mock ConfigEntry setup for the integration."""
with (

View File

@@ -1,7 +1,6 @@
"""Tests for JVC Projector config flow."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
from unittest.mock import AsyncMock
from jvcprojector import JvcProjectorAuthError, JvcProjectorTimeoutError
import pytest
@@ -19,16 +18,6 @@ from tests.common import MockConfigEntry
TARGET = "homeassistant.components.jvc_projector.config_flow.JvcProjector"
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.jvc_projector.async_setup_entry",
return_value=True,
) as mock_setup_entry:
yield mock_setup_entry
@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True)
async def test_user_config_flow_success(
hass: HomeAssistant, mock_device: AsyncMock

View File

@@ -400,18 +400,14 @@ async def test_reconfigure(
return_value={"scb:network": {"Hostname": "scb"}}
)
with patch(
"homeassistant.components.kostal_plenticore.async_setup_entry",
return_value=True,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "1.1.1.1",
"password": "test-password",
},
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "1.1.1.1",
"password": "test-password",
},
)
await hass.async_block_till_done()
mock_apiclient_class.assert_called_once_with(ANY, "1.1.1.1")
mock_apiclient.__aenter__.assert_called_once()

View File

@@ -1,7 +1,7 @@
"""Tests for the LaMetric config flow."""
from http import HTTPStatus
from unittest.mock import AsyncMock, MagicMock
from unittest.mock import MagicMock
from demetriek import (
LaMetricConnectionError,
@@ -686,7 +686,6 @@ async def test_cloud_errors(
async def test_dhcp_discovery_updates_entry(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
) -> None:
"""Test DHCP discovery updates config entries."""
mock_config_entry.add_to_hass(hass)

View File

@@ -90,7 +90,6 @@ async def test_device_already_configured(
async def test_user_step_fail_with_error(
hass: HomeAssistant,
mock_lunatone_info: AsyncMock,
mock_setup_entry: AsyncMock,
exception: Exception,
expected_error: str,
) -> None:
@@ -125,7 +124,6 @@ async def test_user_step_fail_with_error(
async def test_reconfigure(
hass: HomeAssistant,
mock_lunatone_info: AsyncMock,
mock_setup_entry: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconfigure flow."""
@@ -155,7 +153,6 @@ async def test_reconfigure(
async def test_reconfigure_fail_with_error(
hass: HomeAssistant,
mock_lunatone_info: AsyncMock,
mock_setup_entry: AsyncMock,
mock_config_entry: MockConfigEntry,
exception: Exception,
expected_error: str,

View File

@@ -46,6 +46,6 @@
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
'state': 'off',
})
# ---

View File

@@ -20,7 +20,6 @@ from tests.common import MockConfigEntry, snapshot_platform
async def test_binary_sensor_setup(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_madvr_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:

View File

@@ -38,7 +38,6 @@ from tests.common import MockConfigEntry, snapshot_platform
async def test_remote_setup(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_madvr_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:

View File

@@ -9,9 +9,7 @@ import pytest
@pytest.fixture
def mock_simple_manager_fail():
"""Mock datapoint Manager with default values for testing in config_flow."""
with patch(
"homeassistant.components.metoffice.config_flow.Manager"
) as mock_manager:
with patch("datapoint.Manager.Manager") as mock_manager:
instance = mock_manager.return_value
instance.get_forecast = APIException()
instance.latitude = None

View File

@@ -1,14 +1,3 @@
"""mochad conftest."""
from unittest import mock
import pytest
from tests.components.light.conftest import mock_light_profiles # noqa: F401
@pytest.fixture(autouse=True)
def mock_pymochad_controller():
"""Mock pymochad controller to prevent real socket connections."""
with mock.patch("homeassistant.components.mochad.controller.PyMochad"):
yield

View File

@@ -687,11 +687,10 @@ async def test_discovered_by_dhcp_updates_host(
assert config_entry.data[CONF_HOST] == "1.2.3.4"
await hass.config_entries.async_unload(config_entry.entry_id)
with patch("homeassistant.components.onvif.async_setup_entry", return_value=True):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_DHCP}, data=DHCP_DISCOVERY
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_DHCP}, data=DHCP_DISCOVERY
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"

View File

@@ -1,10 +1,8 @@
"""Test the Panasonic Viera config flow."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
from unittest.mock import patch
from panasonic_viera import SOAPError
import pytest
from homeassistant import config_entries
from homeassistant.components.panasonic_viera.const import (
@@ -28,16 +26,6 @@ from .conftest import (
from tests.common import MockConfigEntry
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Mock setting up a config entry."""
with patch(
"homeassistant.components.panasonic_viera.async_setup_entry",
return_value=True,
) as mock_setup:
yield mock_setup
async def test_flow_non_encrypted(hass: HomeAssistant) -> None:
"""Test flow without encryption."""

View File

@@ -122,12 +122,9 @@ async def test_unknown_error(hass: HomeAssistant) -> None:
async def test_zero_conf(hass: HomeAssistant) -> None:
"""Test the manual flow for zero config."""
with (
patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
),
patch_async_setup_entry(),
with patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
@@ -142,12 +139,9 @@ async def test_zero_conf(hass: HomeAssistant) -> None:
async def test_url_rewrite(hass: HomeAssistant) -> None:
"""Test auth flow url rewrite."""
with (
patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
),
patch_async_setup_entry(),
with patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
):
result = await hass.config_entries.flow.async_init(
DOMAIN,

View File

@@ -264,9 +264,7 @@ async def test_ssdp_discovery(
async def test_options_flow(
hass: HomeAssistant,
mock_setup_entry: None,
mock_config_entry: MockConfigEntry,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test options config flow."""
mock_config_entry.add_to_hass(hass)

View File

@@ -77,7 +77,7 @@ async def test_setup_h_j_model(
assert "H and J series use an encrypted protocol" in caplog.text
@pytest.mark.usefixtures("remote_websocket", "rest_api")
@pytest.mark.usefixtures("remote_websocket")
async def test_setup_updates_from_ssdp(hass: HomeAssistant) -> None:
"""Test setting up the entry fetches data from ssdp cache."""
entry = MockConfigEntry(

View File

@@ -31,8 +31,7 @@ async def test_setup_success_no_region(hass: HomeAssistant) -> None:
)
mock_config.add_to_hass(hass)
with patch("homeassistant.components.sharkiq.async_setup_entry", return_value=True):
result = await async_setup_component(hass=hass, domain=DOMAIN, config={})
result = await async_setup_component(hass=hass, domain=DOMAIN, config={})
assert result is True

View File

@@ -149,9 +149,7 @@ async def test_dhcp_discovery(
async def test_dhcp_already_configured(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test starting a flow by dhcp when already configured."""
mock_config_entry.add_to_hass(hass)
@@ -164,9 +162,7 @@ async def test_dhcp_already_configured(
async def test_dhcp_already_configured_duplicate(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_sma_client: MagicMock,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test starting a flow by DHCP when already configured and MAC is added."""
mock_config_entry.add_to_hass(hass)
@@ -284,7 +280,6 @@ async def test_full_flow_reauth(
async def test_reauth_flow_exceptions(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
exception: Exception,
error: str,
) -> None:

View File

@@ -244,55 +244,6 @@
'state': 'on',
})
# ---
# name: test_all_entities[da_ks_hood_01001][switch.range_hood_do_not_disturb-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.range_hood_do_not_disturb',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Do not disturb',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Do not disturb',
'platform': 'smartthings',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'do_not_disturb',
'unique_id': 'fa5fca25-fa7a-1807-030a-2f72ee0f7bff_main_custom.doNotDisturbMode_doNotDisturb_doNotDisturb',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ks_hood_01001][switch.range_hood_do_not_disturb-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Range hood Do not disturb',
}),
'context': <ANY>,
'entity_id': 'switch.range_hood_do_not_disturb',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_all_entities[da_ks_walloven_0107x][switch.four_sabbath_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -1028,55 +979,6 @@
'state': 'on',
})
# ---
# name: test_all_entities[da_rvc_map_01011][switch.robot_vacuum_do_not_disturb-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.robot_vacuum_do_not_disturb',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Do not disturb',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Do not disturb',
'platform': 'smartthings',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'do_not_disturb',
'unique_id': '05accb39-2017-c98b-a5ab-04a81f4d3d9a_main_custom.doNotDisturbMode_doNotDisturb_doNotDisturb',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_rvc_map_01011][switch.robot_vacuum_do_not_disturb-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Robot vacuum Do not disturb',
}),
'context': <ANY>,
'entity_id': 'switch.robot_vacuum_do_not_disturb',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_all_entities[da_rvc_normal_000001][switch.robot_vacuum-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -7,16 +7,6 @@ import pytest
from . import MOCK_SERVERS
@pytest.fixture
def mock_setup_entry():
"""Mock setting up a config entry."""
with patch(
"homeassistant.components.speedtestdotnet.async_setup_entry",
return_value=True,
) as mock_setup:
yield mock_setup
@pytest.fixture
def mock_api():
"""Mock entry setup."""

View File

@@ -14,7 +14,7 @@ from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
async def test_flow_works(hass: HomeAssistant, mock_setup_entry: MagicMock) -> None:
async def test_flow_works(hass: HomeAssistant) -> None:
"""Test user config."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}

View File

@@ -25,15 +25,12 @@ async def test_flow_user(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"] == {}
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -51,15 +48,12 @@ async def test_flow_user_cannot_connect(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"]["base"] == "cannot_connect"
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -77,15 +71,12 @@ async def test_flow_user_invalid_auth(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"]["base"] == "invalid_auth"
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -103,15 +94,12 @@ async def test_flow_user_unknown_error(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"]["base"] == "unknown"
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -150,15 +138,12 @@ async def test_flow_user_multiple_entries_allowed(hass: HomeAssistant) -> None:
CONF_API_KEY: "efgh",
CONF_VERIFY_SSL: True,
}
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=user_input,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME

View File

@@ -183,21 +183,18 @@ async def test_failed_coordinator_update(hass: HomeAssistant, api: AsyncMock) ->
"""Test a failed data coordinator update is handled correctly."""
api.get_tasks.side_effect = Exception("API error")
with patch(
"homeassistant.components.todoist.calendar.TodoistAPIAsync", return_value=api
):
assert await setup.async_setup_component(
hass,
"calendar",
{
"calendar": {
"platform": DOMAIN,
CONF_TOKEN: "token",
"custom_projects": [{"name": "All projects", "labels": ["Label1"]}],
}
},
)
await hass.async_block_till_done()
assert await setup.async_setup_component(
hass,
"calendar",
{
"calendar": {
"platform": DOMAIN,
CONF_TOKEN: "token",
"custom_projects": [{"name": "All projects", "labels": ["Label1"]}],
}
},
)
await hass.async_block_till_done()
await async_update_entity(hass, "calendar.all_projects")
state = hass.states.get("calendar.all_projects")

View File

@@ -57,8 +57,6 @@ async def test_service_reconnect_client(
async def test_service_reconnect_failed_with_invalid_entry(
hass: HomeAssistant,
mock_omada_site_client: MagicMock,
mock_omada_client: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconnect with invalid config entry raises ServiceValidationError."""
@@ -104,8 +102,6 @@ async def test_service_reconnect_without_config_entry_id(
async def test_service_reconnect_entry_not_loaded(
hass: HomeAssistant,
mock_omada_site_client: MagicMock,
mock_omada_client: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconnect service raises error when entry is not loaded."""

View File

@@ -30,7 +30,6 @@ from tests.common import MockConfigEntry, async_fire_time_changed
async def test_config_flow_entry_migrate_1_1_to_1_2(
hass: HomeAssistant,
mock_transmission_client: AsyncMock,
) -> None:
"""Test that config flow entry is migrated correctly from v1.1 to v1.2."""
entry = MockConfigEntry(
@@ -151,7 +150,6 @@ async def test_unload_entry(
)
async def test_migrate_unique_id(
hass: HomeAssistant,
mock_transmission_client: AsyncMock,
entity_registry: er.EntityRegistry,
domain: str,
old_unique_id: str,

View File

@@ -523,10 +523,6 @@ async def test_form_reauth_auth(
"homeassistant.components.unifiprotect.async_setup",
return_value=True,
) as mock_setup,
patch(
"homeassistant.components.unifiprotect.async_setup_entry",
return_value=True,
),
patch(
"homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_meta_info",
return_value=None,
@@ -1921,15 +1917,9 @@ async def test_reauth_empty_credentials_keeps_existing(
nvr.mac = _async_unifi_mac_from_hass(MAC_ADDR)
bootstrap.nvr = nvr
with (
patch(
"homeassistant.components.unifiprotect.async_setup",
return_value=True,
),
patch(
"homeassistant.components.unifiprotect.async_setup_entry",
return_value=True,
),
with patch(
"homeassistant.components.unifiprotect.async_setup",
return_value=True,
):
# Submit with empty credentials - should keep existing
result = await hass.config_entries.flow.async_configure(
@@ -2013,15 +2003,9 @@ async def test_reauth_credential_update(
nvr.mac = _async_unifi_mac_from_hass(MAC_ADDR)
bootstrap.nvr = nvr
with (
patch(
"homeassistant.components.unifiprotect.async_setup",
return_value=True,
),
patch(
"homeassistant.components.unifiprotect.async_setup_entry",
return_value=True,
),
with patch(
"homeassistant.components.unifiprotect.async_setup",
return_value=True,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],

View File

@@ -153,9 +153,12 @@ async def test_reboot_gateway_service_raises_on_exception(
async def test_reboot_gateway_service_raises_validation_error(
hass: HomeAssistant,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test that reboot_gateway service raises ServiceValidationError when no gateway is loaded."""
# Add the config entry but don't set it up
mock_config_entry.add_to_hass(hass)
# Set up the velux integration's async_setup to register the service
await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()

View File

@@ -159,10 +159,9 @@ async def test_full_ssdp_flow_implementation(hass: HomeAssistant) -> None:
"components": "light",
}
with patch("homeassistant.components.wilight.async_setup_entry", return_value=True):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == f"WL{WILIGHT_ID}"

View File

@@ -33,13 +33,10 @@ async def test_full_flow(hass: HomeAssistant) -> None:
mock_youless = _get_mock_youless_api(
initialize={"homes": [{"id": 1, "name": "myhome"}]}
)
with (
patch(
"homeassistant.components.youless.config_flow.YoulessAPI",
return_value=mock_youless,
) as mocked_youless,
patch("homeassistant.components.youless.async_setup_entry", return_value=True),
):
with patch(
"homeassistant.components.youless.config_flow.YoulessAPI",
return_value=mock_youless,
) as mocked_youless:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"host": "localhost"},