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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ on:
type: boolean

env:
CACHE_VERSION: 5
CACHE_VERSION: 6
UV_CACHE_VERSION: 1
MYPY_CACHE_VERSION: 1
HA_SHORT_VERSION: "2025.9"
Expand Down Expand Up @@ -1341,7 +1341,7 @@ jobs:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'true'
uses: codecov/codecov-action@v5.4.3
uses: codecov/codecov-action@v5.5.0
with:
fail_ci_if_error: true
flags: full-suite
Expand Down Expand Up @@ -1491,7 +1491,7 @@ jobs:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'false'
uses: codecov/codecov-action@v5.4.3
uses: codecov/codecov-action@v5.5.0
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ jobs:
uses: actions/[email protected]

- name: Initialize CodeQL
uses: github/codeql-action/[email protected].9
uses: github/codeql-action/[email protected].10
with:
languages: python

- name: Perform CodeQL Analysis
uses: github/codeql-action/[email protected].9
uses: github/codeql-action/[email protected].10
with:
category: "/language:python"
1 change: 1 addition & 0 deletions homeassistant/components/analytics/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,5 +449,6 @@ async def async_devices_payload(hass: HomeAssistant) -> dict:

return {
"version": "home-assistant:1",
"home_assistant": HA_VERSION,
"devices": devices,
}
8 changes: 6 additions & 2 deletions homeassistant/components/asuswrt/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from asusrouter.modules.client import AsusClient
from asusrouter.modules.data import AsusData
from asusrouter.modules.homeassistant import convert_to_ha_data, convert_to_ha_sensors
from asusrouter.tools.connection import get_cookie_jar

from homeassistant.const import (
CONF_HOST,
Expand All @@ -25,7 +26,7 @@
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.update_coordinator import UpdateFailed

Expand Down Expand Up @@ -109,7 +110,10 @@ def get_bridge(
) -> AsusWrtBridge:
"""Get Bridge instance."""
if conf[CONF_PROTOCOL] in (PROTOCOL_HTTPS, PROTOCOL_HTTP):
session = async_get_clientsession(hass)
session = async_create_clientsession(
hass,
cookie_jar=get_cookie_jar(),
)
return AsusWrtHttpBridge(conf, session)
return AsusWrtLegacyBridge(conf, options)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/cast/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"documentation": "https://www.home-assistant.io/integrations/cast",
"iot_class": "local_polling",
"loggers": ["casttube", "pychromecast"],
"requirements": ["PyChromecast==14.0.7"],
"requirements": ["PyChromecast==14.0.9"],
"single_config_entry": true,
"zeroconf": ["_googlecast._tcp.local."]
}
9 changes: 7 additions & 2 deletions homeassistant/components/husqvarna_automower_ble/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

from automower_ble.mower import Mower
from automower_ble.protocol import ResponseResult
from bleak import BleakError
from bleak_retry_connector import close_stale_connections_by_address, get_device

Expand Down Expand Up @@ -37,12 +38,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: HusqvarnaConfigEntry) ->
device = bluetooth.async_ble_device_from_address(
hass, address, connectable=True
) or await get_device(address)
if not await mower.connect(device):
raise ConfigEntryNotReady
response_result = await mower.connect(device)
if response_result != ResponseResult.OK:
raise ConfigEntryNotReady(
f"Unable to connect to device {address}, mower returned {response_result}"
)
except (TimeoutError, BleakError) as exception:
raise ConfigEntryNotReady(
f"Unable to connect to device {address} due to {exception}"
) from exception

LOGGER.debug("connected and paired")

model = await mower.get_model()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import TYPE_CHECKING

from automower_ble.mower import Mower
from automower_ble.protocol import ResponseResult
from bleak import BleakError
from bleak_retry_connector import close_stale_connections_by_address

Expand Down Expand Up @@ -62,7 +63,7 @@ async def _async_find_device(self):
)

try:
if not await self.mower.connect(device):
if await self.mower.connect(device) is not ResponseResult.OK:
raise UpdateFailed("Failed to connect")
except BleakError as err:
raise UpdateFailed("Failed to connect") from err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from automower_ble.protocol import MowerActivity, MowerState
from automower_ble.protocol import MowerActivity, MowerState, ResponseResult

from homeassistant.components import bluetooth
from homeassistant.components.lawn_mower import (
Expand Down Expand Up @@ -107,7 +107,7 @@ async def async_start_mowing(self) -> None:
device = bluetooth.async_ble_device_from_address(
self.coordinator.hass, self.coordinator.address, connectable=True
)
if not await self.coordinator.mower.connect(device):
if await self.coordinator.mower.connect(device) is not ResponseResult.OK:
return

await self.coordinator.mower.mower_resume()
Expand All @@ -126,7 +126,7 @@ async def async_dock(self) -> None:
device = bluetooth.async_ble_device_from_address(
self.coordinator.hass, self.coordinator.address, connectable=True
)
if not await self.coordinator.mower.connect(device):
if await self.coordinator.mower.connect(device) is not ResponseResult.OK:
return

await self.coordinator.mower.mower_park()
Expand All @@ -143,7 +143,7 @@ async def async_pause(self) -> None:
device = bluetooth.async_ble_device_from_address(
self.coordinator.hass, self.coordinator.address, connectable=True
)
if not await self.coordinator.mower.connect(device):
if await self.coordinator.mower.connect(device) is not ResponseResult.OK:
return

await self.coordinator.mower.mower_pause()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/husqvarna_automower_ble",
"iot_class": "local_polling",
"requirements": ["automower-ble==0.2.1"]
"requirements": ["automower-ble==0.2.7"]
}
8 changes: 8 additions & 0 deletions homeassistant/components/miele/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,14 @@ class StateDryingStep(MieleEnum):
24813: "appliance_settings", # modify profile name
}

COFFEE_SYSTEM_PROFILE: dict[range, str] = {
range(24000, 24032): "profile_1",
range(24032, 24064): "profile_2",
range(24064, 24096): "profile_3",
range(24096, 24128): "profile_4",
range(24128, 24160): "profile_5",
}

STEAM_OVEN_MICRO_PROGRAM_ID: dict[int, str] = {
8: "steam_cooking",
19: "microwave",
Expand Down
42 changes: 39 additions & 3 deletions homeassistant/components/miele/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from __future__ import annotations

from collections.abc import Callable
from collections.abc import Callable, Mapping
from dataclasses import dataclass
import logging
from typing import Final, cast
from typing import Any, Final, cast

from pymiele import MieleDevice, MieleTemperature

Expand All @@ -30,6 +30,7 @@
from homeassistant.helpers.typing import StateType

from .const import (
COFFEE_SYSTEM_PROFILE,
DISABLED_TEMP_ENTITIES,
DOMAIN,
STATE_PROGRAM_ID,
Expand Down Expand Up @@ -61,6 +62,8 @@
"KMX": 6,
}

ATTRIBUTE_PROFILE = "profile"


def _get_plate_count(tech_type: str) -> int:
"""Get number of zones for hob."""
Expand Down Expand Up @@ -88,11 +91,21 @@ def _convert_temperature(
return raw_value


def _get_coffee_profile(value: MieleDevice) -> str | None:
"""Get coffee profile from value."""
if value.state_program_id is not None:
for key_range, profile in COFFEE_SYSTEM_PROFILE.items():
if value.state_program_id in key_range:
return profile
return None


@dataclass(frozen=True, kw_only=True)
class MieleSensorDescription(SensorEntityDescription):
"""Class describing Miele sensor entities."""

value_fn: Callable[[MieleDevice], StateType]
extra_attributes: dict[str, Callable[[MieleDevice], StateType]] | None = None
zone: int | None = None
unique_id_fn: Callable[[str, MieleSensorDescription], str] | None = None

Expand Down Expand Up @@ -157,7 +170,6 @@ class MieleSensorDefinition:
MieleAppliance.OVEN_MICROWAVE,
MieleAppliance.STEAM_OVEN,
MieleAppliance.MICROWAVE,
MieleAppliance.COFFEE_SYSTEM,
MieleAppliance.ROBOT_VACUUM_CLEANER,
MieleAppliance.WASHER_DRYER,
MieleAppliance.STEAM_OVEN_COMBI,
Expand All @@ -172,6 +184,18 @@ class MieleSensorDefinition:
value_fn=lambda value: value.state_program_id,
),
),
MieleSensorDefinition(
types=(MieleAppliance.COFFEE_SYSTEM,),
description=MieleSensorDescription(
key="state_program_id",
translation_key="program_id",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda value: value.state_program_id,
extra_attributes={
ATTRIBUTE_PROFILE: _get_coffee_profile,
},
),
),
MieleSensorDefinition(
types=(
MieleAppliance.WASHING_MACHINE,
Expand Down Expand Up @@ -710,6 +734,16 @@ def native_value(self) -> StateType:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.device)

@property
def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return extra_state_attributes."""
if self.entity_description.extra_attributes is None:
return None
attr = {}
for key, value in self.entity_description.extra_attributes.items():
attr[key] = value(self.device)
return attr


class MielePlateSensor(MieleSensor):
"""Representation of a Sensor."""
Expand Down Expand Up @@ -792,6 +826,8 @@ def options(self) -> list[str]:
class MieleProgramIdSensor(MieleSensor):
"""Representation of the program id sensor."""

_unrecorded_attributes = frozenset({ATTRIBUTE_PROFILE})

@property
def native_value(self) -> StateType:
"""Return the state of the sensor."""
Expand Down
12 changes: 12 additions & 0 deletions homeassistant/components/miele/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,18 @@
"yom_tov": "Yom tov",
"yorkshire_pudding": "Yorkshire pudding",
"zander_fillet": "Zander (fillet)"
},
"state_attributes": {
"profile": {
"name": "Profile",
"state": {
"profile_1": "Profile 1",
"profile_2": "Profile 2",
"profile_3": "Profile 3",
"profile_4": "Profile 4",
"profile_5": "Profile 5"
}
}
}
},
"spin_speed": {
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.

1 change: 1 addition & 0 deletions script/licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ def from_dict(cls, data: PackageMetadata) -> PackageDefinition:
"pysabnzbd", # https://github.com/jeradM/pysabnzbd/pull/6
"sharp_aquos_rc", # https://github.com/jmoore987/sharp_aquos_rc/pull/14
"tapsaff", # https://github.com/bazwilliams/python-taps-aff/pull/5
"ujson", # https://github.com/ultrajson/ultrajson/blob/main/LICENSE.txt
}

# fmt: off
Expand Down
2 changes: 2 additions & 0 deletions tests/components/analytics/test_analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ async def test_devices_payload(
assert await async_setup_component(hass, "analytics", {})
assert await async_devices_payload(hass) == {
"version": "home-assistant:1",
"home_assistant": MOCK_VERSION,
"devices": [],
}

Expand Down Expand Up @@ -1052,6 +1053,7 @@ async def test_devices_payload(

assert await async_devices_payload(hass) == {
"version": "home-assistant:1",
"home_assistant": MOCK_VERSION,
"devices": [
{
"manufacturer": "test-manufacturer",
Expand Down
3 changes: 2 additions & 1 deletion tests/components/husqvarna_automower_ble/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections.abc import Generator
from unittest.mock import AsyncMock, patch

from automower_ble.protocol import ResponseResult
import pytest

from homeassistant.components.husqvarna_automower_ble.const import DOMAIN
Expand Down Expand Up @@ -37,7 +38,7 @@ def mock_automower_client(enable_bluetooth: None) -> Generator[AsyncMock]:
),
):
client = mock_client.return_value
client.connect.return_value = True
client.connect.return_value = ResponseResult.OK
client.is_connected.return_value = True
client.get_model.return_value = "305"
client.battery_level.return_value = 100
Expand Down
Loading
Loading