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
10 changes: 5 additions & 5 deletions build.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
image: ghcr.io/home-assistant/{arch}-homeassistant
build_from:
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2025.10.0
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2025.10.0
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2025.10.0
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2025.10.0
i386: ghcr.io/home-assistant/i386-homeassistant-base:2025.10.0
aarch64: ghcr.io/home-assistant/aarch64-homeassistant-base:2025.10.1
armhf: ghcr.io/home-assistant/armhf-homeassistant-base:2025.10.1
armv7: ghcr.io/home-assistant/armv7-homeassistant-base:2025.10.1
amd64: ghcr.io/home-assistant/amd64-homeassistant-base:2025.10.1
i386: ghcr.io/home-assistant/i386-homeassistant-base:2025.10.1
codenotary:
signer: [email protected]
base_image: [email protected]
Expand Down
5 changes: 4 additions & 1 deletion homeassistant/components/camera/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@
StreamType,
)
from .helper import get_camera_from_entity_id
from .img_util import scale_jpeg_camera_image
from .img_util import (
TurboJPEGSingleton, # noqa: F401
scale_jpeg_camera_image,
)
from .prefs import (
CameraPreferences,
DynamicStreamSettings, # noqa: F401
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/cloud/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
errors as alexa_errors,
smart_home as alexa_smart_home,
)
from homeassistant.components.camera.webrtc import async_register_ice_servers
from homeassistant.components.camera import async_register_ice_servers
from homeassistant.components.google_assistant import smart_home as ga
from homeassistant.const import __version__ as HA_VERSION
from homeassistant.core import Context, HassJob, HomeAssistant, callback
Expand Down
17 changes: 10 additions & 7 deletions homeassistant/components/conversation/chat_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,14 +569,17 @@ async def async_provide_llm_data(
if llm_api:
prompt_parts.append(llm_api.api_prompt)

prompt_parts.append(
await self._async_expand_prompt_template(
llm_context,
llm.BASE_PROMPT,
llm_context.language,
user_name,
# Append current date and time to the prompt if the corresponding tool is not provided
llm_tools: list[llm.Tool] = llm_api.tools if llm_api else []
if not any(tool.name.endswith("GetDateTime") for tool in llm_tools):
prompt_parts.append(
await self._async_expand_prompt_template(
llm_context,
llm.DATE_TIME_PROMPT,
llm_context.language,
user_name,
)
)
)

if extra_system_prompt := (
# Take new system prompt if one was given
Expand Down
4 changes: 3 additions & 1 deletion homeassistant/components/demo/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import datetime

from homeassistant.components.alarm_control_panel import AlarmControlPanelState
from homeassistant.components.manual.alarm_control_panel import ManualAlarm
from homeassistant.components.manual.alarm_control_panel import ( # pylint: disable=hass-component-root-import
ManualAlarm,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ARMING_TIME, CONF_DELAY_TIME, CONF_TRIGGER_TIME
from homeassistant.core import HomeAssistant
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/demo/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ async def async_close_cover(self, **kwargs: Any) -> None:
self.async_write_ha_state()
return

self._is_opening = False
self._is_closing = True
self._listen_cover()
self._requested_closing = True
Expand All @@ -162,6 +163,7 @@ async def async_open_cover(self, **kwargs: Any) -> None:
return

self._is_opening = True
self._is_closing = False
self._listen_cover()
self._requested_closing = False
self.async_write_ha_state()
Expand All @@ -181,10 +183,14 @@ async def async_set_cover_position(self, **kwargs: Any) -> None:
if self._position == position:
return

self._is_closing = position < (self._position or 0)
self._is_opening = not self._is_closing

self._listen_cover()
self._requested_closing = (
self._position is not None and position < self._position
)
self.async_write_ha_state()

async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
"""Move the cover til to a specific position."""
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/doods/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"iot_class": "local_polling",
"loggers": ["pydoods"],
"quality_scale": "legacy",
"requirements": ["pydoods==1.0.2", "Pillow==11.3.0"]
"requirements": ["pydoods==1.0.2", "Pillow==12.0.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/generic/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/generic",
"integration_type": "device",
"iot_class": "local_push",
"requirements": ["av==13.1.0", "Pillow==11.3.0"]
"requirements": ["av==13.1.0", "Pillow==12.0.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/go2rtc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
WebRTCMessage,
WebRTCSendMessage,
async_register_webrtc_provider,
get_dynamic_camera_stream_settings,
)
from homeassistant.components.camera.prefs import get_dynamic_camera_stream_settings
from homeassistant.components.default_config import DOMAIN as DEFAULT_CONFIG_DOMAIN
from homeassistant.components.stream import Orientation
from homeassistant.config_entries import SOURCE_SYSTEM, ConfigEntry
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/habitica/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"iot_class": "cloud_polling",
"loggers": ["habiticalib"],
"quality_scale": "platinum",
"requirements": ["habiticalib==0.4.5"]
"requirements": ["habiticalib==0.4.6"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/image_upload/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/image_upload",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["Pillow==11.3.0"]
"requirements": ["Pillow==12.0.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/lovelace/cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pychromecast.const import CAST_TYPE_CHROMECAST

from homeassistant.components.cast import DOMAIN as CAST_DOMAIN
from homeassistant.components.cast.home_assistant_cast import (
from homeassistant.components.cast.home_assistant_cast import ( # pylint: disable=hass-component-root-import
ATTR_URL_PATH,
ATTR_VIEW_PATH,
NO_URL_AVAILABLE_ERROR,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/matrix/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"iot_class": "cloud_push",
"loggers": ["matrix_client"],
"quality_scale": "legacy",
"requirements": ["matrix-nio==0.25.2", "Pillow==11.3.0"]
"requirements": ["matrix-nio==0.25.2", "Pillow==12.0.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/proxy/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"codeowners": [],
"documentation": "https://www.home-assistant.io/integrations/proxy",
"quality_scale": "legacy",
"requirements": ["Pillow==11.3.0"]
"requirements": ["Pillow==12.0.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/qrcode/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"iot_class": "calculated",
"loggers": ["pyzbar"],
"quality_scale": "legacy",
"requirements": ["Pillow==11.3.0", "pyzbar==0.1.7"]
"requirements": ["Pillow==12.0.0", "pyzbar==0.1.7"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/rapt_ble/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ async def async_step_user(
title=self._discovered_devices[address], data={}
)

current_addresses = self._async_current_ids()
current_addresses = self._async_current_ids(include_ignore=False)
for discovery_info in async_discovered_service_info(self.hass, False):
address = discovery_info.address
if address in current_addresses or address in self._discovered_devices:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/seven_segments/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"documentation": "https://www.home-assistant.io/integrations/seven_segments",
"iot_class": "local_polling",
"quality_scale": "legacy",
"requirements": ["Pillow==11.3.0"]
"requirements": ["Pillow==12.0.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/sighthound/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"iot_class": "cloud_polling",
"loggers": ["simplehound"],
"quality_scale": "legacy",
"requirements": ["Pillow==11.3.0", "simplehound==0.3"]
"requirements": ["Pillow==12.0.0", "simplehound==0.3"]
}
4 changes: 3 additions & 1 deletion homeassistant/components/sonos/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
async_process_play_media_url,
)
from homeassistant.components.plex import PLEX_URI_SCHEME
from homeassistant.components.plex.services import process_plex_payload
from homeassistant.components.plex.services import ( # pylint: disable=hass-component-root-import
process_plex_payload,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import entity_registry as er
Expand Down
4 changes: 1 addition & 3 deletions homeassistant/components/stream/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,7 @@ def __init__(

# Keep import here so that we can import stream integration
# without installing reqs
from homeassistant.components.camera.img_util import ( # noqa: PLC0415
TurboJPEGSingleton,
)
from homeassistant.components.camera import TurboJPEGSingleton # noqa: PLC0415

self._packet: Packet | None = None
self._event: asyncio.Event = asyncio.Event()
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/tensorflow/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
"tf-models-official==2.5.0",
"pycocotools==2.0.6",
"numpy==2.3.2",
"Pillow==11.3.0"
"Pillow==12.0.0"
]
}
6 changes: 6 additions & 0 deletions homeassistant/components/volvo/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,12 @@
"odometer": {
"default": "mdi:counter"
},
"service_warning": {
"default": "mdi:wrench-clock",
"state": {
"no_warning": "mdi:car-wrench"
}
},
"target_battery_charge_level": {
"default": "mdi:battery-medium"
},
Expand Down
19 changes: 19 additions & 0 deletions homeassistant/components/volvo/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,25 @@ def _direction_value(field: VolvoCarsApiBaseModel) -> str | None:
state_class=SensorStateClass.TOTAL_INCREASING,
suggested_display_precision=1,
),
# diagnostics endpoint
VolvoSensorDescription(
key="service_warning",
api_field="serviceWarning",
device_class=SensorDeviceClass.ENUM,
options=[
"distance_driven_almost_time_for_service",
"distance_driven_overdue_for_service",
"distance_driven_time_for_service",
"engine_hours_almost_time_for_service",
"engine_hours_overdue_for_service",
"engine_hours_time_for_service",
"no_warning",
"regular_maintenance_almost_time_for_service",
"regular_maintenance_overdue_for_service",
"regular_maintenance_time_for_service",
"unknown_warning",
],
),
# energy state endpoint
VolvoSensorDescription(
key="target_battery_charge_level",
Expand Down
16 changes: 16 additions & 0 deletions homeassistant/components/volvo/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,22 @@
"odometer": {
"name": "Odometer"
},
"service_warning": {
"name": "Service",
"state": {
"distance_driven_almost_time_for_service": "Almost time for distance service",
"distance_driven_overdue_for_service": "Distance service overdue",
"distance_driven_time_for_service": "Time for distance service",
"engine_hours_almost_time_for_service": "Almost time for engine service",
"engine_hours_overdue_for_service": "Engine service overdue",
"engine_hours_time_for_service": "Time for engine service",
"no_warning": "No warning",
"regular_maintenance_almost_time_for_service": "Almost time for service",
"regular_maintenance_overdue_for_service": "Service overdue",
"regular_maintenance_time_for_service": "Time for service",
"unknown_warning": "Unknown warning"
}
},
"target_battery_charge_level": {
"name": "Target battery charge level"
},
Expand Down
30 changes: 29 additions & 1 deletion homeassistant/helpers/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

LLM_API_ASSIST = "assist"

BASE_PROMPT = (
DATE_TIME_PROMPT = (
'Current time is {{ now().strftime("%H:%M:%S") }}. '
'Today\'s date is {{ now().strftime("%Y-%m-%d") }}.\n'
)
Expand Down Expand Up @@ -592,6 +592,8 @@ def _async_get_tools(
for intent_handler in intent_handlers
]

tools.append(GetDateTimeTool())

if exposed_entities:
if exposed_entities[CALENDAR_DOMAIN]:
names = []
Expand Down Expand Up @@ -1181,3 +1183,29 @@ async def async_call(
"success": True,
"result": "\n".join(prompt),
}


class GetDateTimeTool(Tool):
"""Tool for getting the current date and time."""

name = "GetDateTime"
description = "Provides the current date and time."

async def async_call(
self,
hass: HomeAssistant,
tool_input: ToolInput,
llm_context: LLMContext,
) -> JsonObjectType:
"""Get the current date and time."""
now = dt_util.now()

return {
"success": True,
"result": {
"date": now.strftime("%Y-%m-%d"),
"time": now.strftime("%H:%M:%S"),
"timezone": now.strftime("%Z"),
"weekday": now.strftime("%A"),
},
}
2 changes: 1 addition & 1 deletion homeassistant/package_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ mutagen==1.47.0
orjson==3.11.3
packaging>=23.1
paho-mqtt==2.1.0
Pillow==11.3.0
Pillow==12.0.0
propcache==0.4.1
psutil-home-assistant==0.0.1
PyJWT==2.10.1
Expand Down
4 changes: 0 additions & 4 deletions pylint/plugins/hass_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ class ObsoleteImportMatch:
_IGNORE_ROOT_IMPORT = (
"automation",
"bluetooth",
"camera",
"cast",
"device_automation",
"device_tracker",
"ffmpeg",
Expand All @@ -138,8 +136,6 @@ class ObsoleteImportMatch:
"homeassistant",
"homeassistant_hardware",
"http",
"manual",
"plex",
"recorder",
"rest",
"script",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ dependencies = [
"PyJWT==2.10.1",
# PyJWT has loose dependency. We want the latest one.
"cryptography==46.0.2",
"Pillow==11.3.0",
"Pillow==12.0.0",
"propcache==0.4.1",
"pyOpenSSL==25.3.0",
"orjson==3.11.3",
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.

Loading
Loading