Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
805abfb
Add Z-Wave JS node status, configuration parameter, and value conditi…
raman325 Sep 10, 2026
813beb8
Report UniFi WAN latency as unknown when a monitor is unresponsive (#…
sdelmas Sep 10, 2026
8ac1e83
Retry sftp_storage setup when the SSH connection fails (#181769)
lackas Sep 10, 2026
5145ccd
Align IQS rules status for Midea (#181799)
chemelli74 Sep 10, 2026
4679f18
Fix atag climate snapshot (#181832)
justanotherariel Sep 10, 2026
986e983
Bump iseo-argo-ble to 0.9.10 (#181828)
FezVrasta Sep 10, 2026
fa89b22
Fix Flexit unit ID range (#181788)
troelde Sep 10, 2026
d1d6e9b
Fix zwave_js condition._async_resolve_nodes (#181841)
emontnemery Sep 10, 2026
689a5d6
Bump openai to 3.10.0 (#181779)
Shulyaka Sep 10, 2026
29ce6d0
Nest climate: recompute supported_features from live device traits (#…
rqi14 Sep 10, 2026
3521db1
Discover newly shared ScorpionTrack vehicles (#181659)
Herbertmt978 Sep 10, 2026
86501aa
Add air alert levels to Ukraine Alarm (#181558)
alexeytokar Sep 10, 2026
4302e92
Defer the next ViCare refresh to the API quota reset (#181634)
lackas Sep 10, 2026
06206cf
Add Besen charging current control (#180617)
moryoav Sep 10, 2026
2d8957b
Add parent device name part to generated entity IDs (#179996)
arturpragacz Sep 10, 2026
bb2e7f1
Fix Yoto card slot sensor name (#181844)
piitaya Sep 10, 2026
76bf132
Avoid duplicates when using HassShoppingListAddItem to modify shoppin…
AlCalzone Sep 10, 2026
562f27d
Add Button platform to my-PV integration (#181835)
rrooggiieerr Sep 10, 2026
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 homeassistant/components/besen/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
DOMAIN: Final = "besen"
NAME: Final = "Besen"

PLATFORMS: Final = [Platform.SENSOR, Platform.SWITCH]
PLATFORMS: Final = [Platform.NUMBER, Platform.SENSOR, Platform.SWITCH]
5 changes: 5 additions & 0 deletions homeassistant/components/besen/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ async def async_stop_charging(self) -> None:

await self._async_run_command(self.client.async_stop_charging())

async def async_set_charge_amps(self, amps: int) -> None:
"""Set the charging current."""

await self._async_run_command(self.client.async_set_charge_amps(amps))

async def _async_run_command(self, command: Awaitable[None]) -> None:
"""Run a charger command and translate command failures."""

Expand Down
62 changes: 62 additions & 0 deletions homeassistant/components/besen/number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Number platform for Besen."""

from typing import override

from besen.const import FALLBACK_MAX_CHARGE_AMPS, MIN_CHARGE_AMPS

from homeassistant.components.number import NumberDeviceClass, NumberEntity, NumberMode
from homeassistant.const import EntityCategory, UnitOfElectricCurrent
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import BesenConfigEntry
from .coordinator import BesenCoordinator
from .entity import BesenEntity

PARALLEL_UPDATES = 0


async def async_setup_entry(
hass: HomeAssistant,
entry: BesenConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Besen number platform."""

async_add_entities([BesenChargingCurrentNumber(entry.runtime_data)])


class BesenChargingCurrentNumber(BesenEntity, NumberEntity):
"""Charging current control."""

_attr_device_class = NumberDeviceClass.CURRENT
_attr_entity_category = EntityCategory.CONFIG
_attr_mode = NumberMode.BOX
_attr_native_min_value = MIN_CHARGE_AMPS
_attr_native_step = 1
_attr_native_unit_of_measurement = UnitOfElectricCurrent.AMPERE

def __init__(self, coordinator: BesenCoordinator) -> None:
"""Initialize the charging current control."""

super().__init__(coordinator, "charging_current")

@property
@override
def native_max_value(self) -> float:
"""Return the maximum charging current."""

return self.coordinator.data.info.output_max_amps or FALLBACK_MAX_CHARGE_AMPS

@property
@override
def native_value(self) -> float | None:
"""Return the configured charging current."""

return self.coordinator.data.config.charge_amps

@override
async def async_set_native_value(self, value: float) -> None:
"""Set the charging current."""

await self.coordinator.async_set_charge_amps(int(value))
3 changes: 3 additions & 0 deletions homeassistant/components/besen/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
}
},
"entity": {
"number": {
"charging_current": { "name": "Charging current" }
},
"sensor": {
"charging_power": { "name": "Charging power" },
"external_temperature": { "name": "External temperature" },
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/cloud/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
"learn_more_url": "https://support.nabucasa.com/hc/en-us/articles/29718084245149-Speech-to-text-STT"
}
},
"requirements": ["hass-nabucasa==2.7.0", "openai==2.45.0"],
"requirements": ["hass-nabucasa==2.7.0", "openai==3.10.0"],
"single_config_entry": true
}
2 changes: 1 addition & 1 deletion homeassistant/components/flexit/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
_LOGGER = logging.getLogger(__name__)

UNIT_SELECTOR = vol.All(
NumberSelector(NumberSelectorConfig(min=1, max=247, mode=NumberSelectorMode.BOX)),
NumberSelector(NumberSelectorConfig(min=1, max=31, mode=NumberSelectorMode.BOX)),
vol.Coerce(int),
)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/iseo_argo_ble/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@
"iot_class": "local_polling",
"loggers": ["iseo_argo_ble"],
"quality_scale": "bronze",
"requirements": ["iseo-argo-ble==0.9.8"]
"requirements": ["iseo-argo-ble==0.9.10"]
}
5 changes: 3 additions & 2 deletions homeassistant/components/litellm/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Config flow for LiteLLM integration."""

import logging
from typing import Any, override
from typing import Any, cast, override

from openai import AsyncOpenAI, AuthenticationError, OpenAIError, PermissionDeniedError
import voluptuous as vol
Expand Down Expand Up @@ -65,7 +65,8 @@ async def _get_models(hass: HomeAssistant, url: str, api_key: str | None) -> lis
client = AsyncOpenAI(
base_url=url,
api_key=api_key or PLACEHOLDER_API_KEY,
http_client=get_async_client(hass),
# Legacy HTTPX clients are supported at runtime only.
http_client=cast(Any, get_async_client(hass)),
)
try:
return [
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/litellm/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Coordinator for the LiteLLM integration."""

from datetime import timedelta
from typing import override
from typing import Any, cast, override

from openai import AsyncOpenAI, AuthenticationError, OpenAIError, PermissionDeniedError

Expand Down Expand Up @@ -40,7 +40,8 @@ def __init__(self, hass: HomeAssistant, config_entry: LiteLLMConfigEntry) -> Non
self.client = AsyncOpenAI(
base_url=config_entry.data[CONF_URL],
api_key=config_entry.data.get(CONF_API_KEY) or PLACEHOLDER_API_KEY,
http_client=get_async_client(hass),
# Legacy HTTPX clients are supported at runtime only.
http_client=cast(Any, get_async_client(hass)),
)

@override
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/litellm/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"integration_type": "service",
"iot_class": "cloud_polling",
"quality_scale": "bronze",
"requirements": ["openai==2.45.0"]
"requirements": ["openai==3.10.0"]
}
3 changes: 2 additions & 1 deletion homeassistant/components/llama_cpp/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ async def async_create_client(
client = openai.AsyncOpenAI(
api_key=api_key,
base_url=config_entry_data[CONF_BASE_URL],
http_client=get_async_client(hass),
# Legacy HTTPX clients are supported at runtime only.
http_client=cast(Any, get_async_client(hass)),
)
# Cache current platform data which gets added to each request
# (caching done by library)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/llama_cpp/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"integration_type": "service",
"iot_class": "local_polling",
"quality_scale": "bronze",
"requirements": ["openai==2.45.0"]
"requirements": ["openai==3.10.0"]
}
6 changes: 3 additions & 3 deletions homeassistant/components/midea/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ rules:
discovery-update-info: todo
discovery: todo
docs-data-update: done
docs-examples: todo
docs-examples: done
docs-known-limitations: done
docs-supported-devices: done
docs-supported-functions: done
docs-troubleshooting: todo
docs-use-cases: todo
docs-troubleshooting: done
docs-use-cases: done
dynamic-devices: todo
entity-category: todo
entity-device-class: todo
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/my_pv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .coordinator import MyPVConfigEntry, MyPVCoordinator

PLATFORMS: list[Platform] = [
Platform.BUTTON,
Platform.WATER_HEATER,
]

Expand Down
58 changes: 58 additions & 0 deletions homeassistant/components/my_pv/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# pylint: disable=duplicate-code
"""Creates Button entities for the my-PV Home Assistant integration."""

from typing import Any, override

from homeassistant.components.button import (
ButtonDeviceClass,
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import MyPVConfigEntry
from .const import DOMAIN
from .entity import MyPVBaseEntity


async def async_setup_entry(
hass: HomeAssistant,
config_entry: MyPVConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the my-PV button."""
coordinator = config_entry.runtime_data
entities = []

config = coordinator.device.get_command_configuration("reboot_device")
if config and config.get("type") in ["any", "fixed"]:
entity_description = ButtonEntityDescription(
key="reboot_device",
device_class=ButtonDeviceClass.RESTART,
entity_category=EntityCategory.DIAGNOSTIC,
)
entities.append(
MyPVCommandButton(
coordinator,
entity_description,
coordinator.device.serial_number,
)
)

async_add_entities(entities)


class MyPVCommandButton(MyPVBaseEntity, ButtonEntity):
"""Base my-PV Button."""

@override
async def async_press(self, **kwargs: Any) -> None:
"""Handle the button press."""

if not await self.coordinator.send_command(self.entity_description.key):
raise HomeAssistantError(
translation_domain=DOMAIN, translation_key="unknown_error"
)
9 changes: 9 additions & 0 deletions homeassistant/components/my_pv/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@ async def set_target_temperature(self, temperature: float) -> bool:
self.async_update_listeners()
return result

@_my_pv_connection
async def send_command(
self, key: str, value: bool | float | str | None = None
) -> bool:
"""Send command."""
result = await self.device.send_command(key, value)
self.async_update_listeners()
return result

@_my_pv_connection
async def turn_on(self) -> bool:
"""Turn on the device."""
Expand Down
16 changes: 14 additions & 2 deletions homeassistant/components/my_pv/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from .coordinator import MyPVCoordinator


class MyPVDataEntity(CoordinatorEntity[MyPVCoordinator]):
"""The my-PV data entity."""
class MyPVBaseEntity(CoordinatorEntity[MyPVCoordinator]):
"""The my-PV base entity."""

_attr_has_entity_name = True

Expand All @@ -35,6 +35,18 @@ def available(self) -> bool:
super().available
and self.coordinator.device.connected
and self.coordinator.device.is_on is not None
)


class MyPVDataEntity(MyPVBaseEntity):
"""The my-PV data entity."""

@property
@override
def available(self) -> bool:
"""Return if entity is available."""
return (
super().available
and self.coordinator.device.get_data_value(self.entity_description.key)
is not None
)
7 changes: 6 additions & 1 deletion homeassistant/components/nest/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ def available(self) -> bool:
@override
async def async_added_to_hass(self) -> None:
"""Run when entity is added to register update signal handler."""
self._attr_supported_features = self._get_supported_features()
self.async_on_remove(
self._device.add_update_listener(self.async_write_ha_state)
)
Expand Down Expand Up @@ -264,6 +263,12 @@ def fan_modes(self) -> list[str]:
return FAN_INV_MODES
return []

@property
@override
def supported_features(self) -> ClimateEntityFeature:
"""Return the bitmap of supported features, computed from current traits."""
return self._get_supported_features()

def _get_supported_features(self) -> ClimateEntityFeature:
"""Compute the bitmap of supported features from the current state."""
features = ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
Expand Down
5 changes: 4 additions & 1 deletion homeassistant/components/open_router/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""The OpenRouter integration."""

from typing import Any, cast

from openai import AsyncOpenAI, AuthenticationError, OpenAIError

from homeassistant.config_entries import ConfigEntry
Expand All @@ -20,7 +22,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: OpenRouterConfigEntry) -
client = AsyncOpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=entry.data[CONF_API_KEY],
http_client=get_async_client(hass),
# Legacy HTTPX clients are supported at runtime only.
http_client=cast(Any, get_async_client(hass)),
)

# Cache current platform data which gets added to each request
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/open_router/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"integration_type": "service",
"iot_class": "cloud_polling",
"quality_scale": "bronze",
"requirements": ["openai==2.45.0", "python-open-router==0.4.0"]
"requirements": ["openai==3.10.0", "python-open-router==0.4.0"]
}
6 changes: 4 additions & 2 deletions homeassistant/components/openai_conversation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pathlib import Path
from types import MappingProxyType
from typing import Any, cast

import openai
from openai.types.images_response import ImagesResponse
Expand Down Expand Up @@ -282,15 +283,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: OpenAIConfigEntry) -> bo
"""Set up OpenAI Conversation from a config entry."""
client = openai.AsyncOpenAI(
api_key=entry.data[CONF_API_KEY],
http_client=get_async_client(hass),
# Legacy HTTPX clients are supported at runtime only.
http_client=cast(Any, get_async_client(hass)),
)

# Cache current platform data which gets added to each request
# (caching done by library)
_ = await hass.async_add_executor_job(client.platform_headers)

try:
await hass.async_add_executor_job(client.with_options(timeout=10.0).models.list)
await client.models.list(timeout=10.0)
except openai.AuthenticationError as err:
raise ConfigEntryAuthFailed(err) from err
except openai.OpenAIError as err:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/openai_conversation/ai_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ async def _async_generate_image(
else:
mime_type = "image/png"

if hasattr(image_call, "size") and (size := image_call.size):
if size := image_call.size:
width, height = tuple(size.split("x"))
else:
width, height = None, None
Expand Down
Loading
Loading