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
1 change: 1 addition & 0 deletions .core_files.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ components: &components
- homeassistant/components/input_number/**
- homeassistant/components/input_select/**
- homeassistant/components/input_text/**
- homeassistant/components/labs/**
- homeassistant/components/logbook/**
- homeassistant/components/logger/**
- homeassistant/components/lovelace/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"documentation": "https://www.home-assistant.io/integrations/google_generative_ai_conversation",
"integration_type": "service",
"iot_class": "cloud_polling",
"requirements": ["google-genai==1.56.0"]
"requirements": ["google-genai==1.59.0"]
}
2 changes: 2 additions & 0 deletions homeassistant/components/hdfury/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from .coordinator import HDFuryConfigEntry
from .entity import HDFuryEntity

PARALLEL_UPDATES = 1


@dataclass(kw_only=True, frozen=True)
class HDFuryButtonEntityDescription(ButtonEntityDescription):
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/hdfury/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/hdfury",
"integration_type": "device",
"iot_class": "local_polling",
"quality_scale": "bronze",
"quality_scale": "silver",
"requirements": ["hdfury==1.3.1"]
}
4 changes: 2 additions & 2 deletions homeassistant/components/hdfury/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ rules:
entity-unavailable: done
integration-owner: done
log-when-unavailable: done
parallel-updates: todo
parallel-updates: done
reauthentication-flow:
status: exempt
comment: Integration has no authentication flow.
test-coverage: todo
test-coverage: done

# Gold
devices: done
Expand Down
14 changes: 7 additions & 7 deletions homeassistant/components/hdfury/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from .coordinator import HDFuryConfigEntry, HDFuryCoordinator
from .entity import HDFuryEntity

PARALLEL_UPDATES = 1


@dataclass(kw_only=True, frozen=True)
class HDFurySelectEntityDescription(SelectEntityDescription):
Expand Down Expand Up @@ -77,13 +79,11 @@ async def async_setup_entry(

coordinator = entry.runtime_data

entities: list[HDFuryEntity] = []

for description in SELECT_PORTS:
if description.key not in coordinator.data.info:
continue

entities.append(HDFurySelect(coordinator, description))
entities: list[HDFuryEntity] = [
HDFurySelect(coordinator, description)
for description in SELECT_PORTS
if description.key in coordinator.data.info
]

# Add OPMODE select if present
if "opmode" in coordinator.data.info:
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/hdfury/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from .coordinator import HDFuryConfigEntry
from .entity import HDFuryEntity

PARALLEL_UPDATES = 0

SENSORS: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="RX0",
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/hdfury/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from .coordinator import HDFuryConfigEntry
from .entity import HDFuryEntity

PARALLEL_UPDATES = 1


@dataclass(kw_only=True, frozen=True)
class HDFurySwitchEntityDescription(SwitchEntityDescription):
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/proxmoxve/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"codeowners": ["@jhollowe", "@Corbeno", "@erwindouna"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/proxmoxve",
"integration_type": "service",
"iot_class": "local_polling",
"loggers": ["proxmoxer"],
"quality_scale": "legacy",
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/shelly/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from dataclasses import dataclass
from typing import Final, cast

from aioshelly.const import RPC_GENERATIONS
from aioshelly.const import MODEL_FLOOD_G4, RPC_GENERATIONS

from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_PLATFORM,
Expand Down Expand Up @@ -335,6 +335,7 @@ def __init__(
device_class=BinarySensorDeviceClass.PROBLEM,
entity_category=EntityCategory.DIAGNOSTIC,
supported=lambda status: status.get("alarm") is not None,
models={MODEL_FLOOD_G4},
),
"presence_num_objects": RpcBinarySensorDescription(
key="presence",
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/xbox/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ async def async_mute_volume(self, mute: bool) -> None:
await self.client.smartglass.mute(self._console.id)
else:
await self.client.smartglass.unmute(self._console.id)
self._attr_is_volume_muted = mute
self.async_write_ha_state()

async def async_volume_up(self) -> None:
"""Turn volume up for media player."""
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/xiaomi_ble/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@
"documentation": "https://www.home-assistant.io/integrations/xiaomi_ble",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["xiaomi-ble==1.4.1"]
"requirements": ["xiaomi-ble==1.4.3"]
}
2 changes: 1 addition & 1 deletion homeassistant/generated/integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -5245,7 +5245,7 @@
},
"proxmoxve": {
"name": "Proxmox VE",
"integration_type": "hub",
"integration_type": "service",
"config_flow": true,
"iot_class": "local_polling"
},
Expand Down
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.

20 changes: 12 additions & 8 deletions tests/components/hdfury/test_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.const import Platform
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.entity_registry as er
Expand Down Expand Up @@ -47,9 +48,9 @@ async def test_button_presses(
await setup_integration(hass, mock_config_entry, [Platform.BUTTON])

await hass.services.async_call(
"button",
"press",
{"entity_id": entity_id},
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)

Expand All @@ -67,10 +68,13 @@ async def test_button_press_error(

await setup_integration(hass, mock_config_entry, [Platform.BUTTON])

with pytest.raises(HomeAssistantError):
with pytest.raises(
HomeAssistantError,
match="An error occurred while communicating with HDFury device",
):
await hass.services.async_call(
"button",
"press",
{"entity_id": "button.hdfury_vrroom_02_restart"},
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: "button.hdfury_vrroom_02_restart"},
blocking=True,
)
145 changes: 143 additions & 2 deletions tests/components/hdfury/test_select.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
"""Tests for the HDFury select platform."""

from datetime import timedelta
from unittest.mock import AsyncMock

from freezegun.api import FrozenDateTimeFactory
from hdfury import HDFuryError
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.const import Platform
from homeassistant.components.select import (
DOMAIN as SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
)
from homeassistant.const import ATTR_ENTITY_ID, ATTR_OPTION, STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.entity_registry as er

from . import setup_integration

from tests.common import MockConfigEntry, snapshot_platform
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform


async def test_select_entities(
Expand All @@ -21,3 +32,133 @@ async def test_select_entities(

await setup_integration(hass, mock_config_entry, [Platform.SELECT])
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)


async def test_select_operation_mode(
hass: HomeAssistant,
mock_hdfury_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test selecting operation mode."""

await setup_integration(hass, mock_config_entry, [Platform.SELECT])

await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.hdfury_vrroom_02_operation_mode",
ATTR_OPTION: "1",
},
blocking=True,
)

mock_hdfury_client.set_operation_mode.assert_awaited_once_with("1")


@pytest.mark.parametrize(
("entity_id"),
[
("select.hdfury_vrroom_02_port_select_tx0"),
("select.hdfury_vrroom_02_port_select_tx1"),
],
)
async def test_select_tx_ports(
hass: HomeAssistant,
mock_hdfury_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_id: str,
) -> None:
"""Test selecting TX ports."""

await setup_integration(hass, mock_config_entry, [Platform.SELECT])

await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: entity_id,
ATTR_OPTION: "1",
},
blocking=True,
)

mock_hdfury_client.set_port_selection.assert_awaited()


async def test_select_operation_mode_error(
hass: HomeAssistant,
mock_hdfury_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test operation mode select raises HomeAssistantError."""

mock_hdfury_client.set_operation_mode.side_effect = HDFuryError()

await setup_integration(hass, mock_config_entry, [Platform.SELECT])

with pytest.raises(
HomeAssistantError,
match="An error occurred while communicating with HDFury device",
):
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.hdfury_vrroom_02_operation_mode",
ATTR_OPTION: "1",
},
blocking=True,
)


async def test_select_ports_missing_state(
hass: HomeAssistant,
mock_hdfury_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test TX port selection fails when TX state is incomplete."""

mock_hdfury_client.get_info.return_value = {
"portseltx0": "0",
"portseltx1": None,
"opmode": "0",
}

await setup_integration(hass, mock_config_entry, [Platform.SELECT])

with pytest.raises(
HomeAssistantError,
match="An error occurred while validating TX states",
):
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.hdfury_vrroom_02_port_select_tx0",
ATTR_OPTION: "0",
},
blocking=True,
)


async def test_select_entities_unavailable_on_error(
hass: HomeAssistant,
mock_hdfury_client: AsyncMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test API error causes entities to become unavailable."""

await setup_integration(hass, mock_config_entry, [Platform.SELECT])

mock_hdfury_client.get_info.side_effect = HDFuryError()

freezer.tick(timedelta(seconds=61))
async_fire_time_changed(hass)
await hass.async_block_till_done()

assert (
hass.states.get("select.hdfury_vrroom_02_port_select_tx0").state
== STATE_UNAVAILABLE
)
Loading
Loading