Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
34c5748
Align Shelly `async_setup_entry` in platforms (#154142)
thecode Oct 12, 2025
de4bfd6
Bump pyOverkiz to 1.19.0 in Overkiz (#154310)
iMicknl Oct 12, 2025
d457787
Move URL out of Overkiz Config Flow descriptions (#154315)
iMicknl Oct 12, 2025
3c1496d
Add gpt-image-1-mini support (#154316)
Shulyaka Oct 12, 2025
bf4f8b4
Update pylint to 4.0.0 + astroid to 4.0.1 (#154311)
cdce8p Oct 12, 2025
ef60d16
Fix Environment Canada camera entity initialization (#154302)
michaeldavie Oct 12, 2025
38e46f7
Bump plugwise to v1.8.0 - add initial support for Emma (#154277)
bouwew Oct 12, 2025
6ef1b3b
Bump aioesphomeapi to 41.14.0 (#154275)
bdraco Oct 12, 2025
09e539b
Fix home wiziard total increasing sensors returning 0 (#154264)
jbouwh Oct 12, 2025
ac7be97
Bump aioamazondevices to 6.4.3 (#154293)
chemelli74 Oct 12, 2025
53b65b2
Bump env-canada to v0.12.1 (#154303)
michaeldavie Oct 12, 2025
be84397
bump tilt-ble to 1.0.1 (#154320)
Ernst79 Oct 12, 2025
7948b35
Fix Yale integration to handle unavailable OAuth implementation at st…
bdraco Oct 12, 2025
c9d67d5
Fix August integration to handle unavailable OAuth implementation at …
bdraco Oct 12, 2025
9b9c55b
Updated prowlpy to 1.1.1 and changed the usage to do asynchronous cal…
mgust Oct 12, 2025
083277d
Add model_id to Husqvarna Automower (#154335)
Thomas55555 Oct 12, 2025
5978142
Update Snoo strings.json to include weaning_baseline (#154268)
dschafer Oct 12, 2025
19dedb0
Update nhc requirement to version 0.7.0 (#154250)
VandeurenGlenn Oct 12, 2025
2b38f33
Bump aioshelly to 13.13.0 (#154337)
thecode Oct 12, 2025
3d130a9
Simplify generic camera tests (#154313)
davet2001 Oct 12, 2025
4ca1ae6
Environment Canada station selector (#154307)
michaeldavie Oct 12, 2025
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/alexa_devices/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["aioamazondevices"],
"quality_scale": "platinum",
"requirements": ["aioamazondevices==6.4.1"]
"requirements": ["aioamazondevices==6.4.3"]
}
11 changes: 7 additions & 4 deletions homeassistant/components/august/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: AugustConfigEntry) -> bo
raise ConfigEntryAuthFailed("Migration to OAuth required")

session = async_create_august_clientsession(hass)
implementation = (
await config_entry_oauth2_flow.async_get_config_entry_implementation(
hass, entry
try:
implementation = (
await config_entry_oauth2_flow.async_get_config_entry_implementation(
hass, entry
)
)
)
except ValueError as err:
raise ConfigEntryNotReady("OAuth implementation not available") from err
oauth_session = config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation)
august_gateway = AugustGateway(Path(hass.config.config_dir), session, oauth_session)
try:
Expand Down
11 changes: 5 additions & 6 deletions homeassistant/components/environment_canada/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ECConfigEntry) ->
radar_coordinator = ECDataUpdateCoordinator(
hass, config_entry, radar_data, "radar", DEFAULT_RADAR_UPDATE_INTERVAL
)
try:
await radar_coordinator.async_config_entry_first_refresh()
except ConfigEntryNotReady:
errors = errors + 1
_LOGGER.warning("Unable to retrieve Environment Canada radar")
# Skip initial refresh for radar since the camera entity is disabled by default.
# The coordinator will fetch data when the entity is enabled.

aqhi_data = ECAirQuality(coordinates=(lat, lon))
aqhi_coordinator = ECDataUpdateCoordinator(
Expand All @@ -63,7 +60,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ECConfigEntry) ->
errors = errors + 1
_LOGGER.warning("Unable to retrieve Environment Canada AQHI")

if errors == 3:
# Require at least one coordinator to succeed (weather or AQHI)
# Radar is optional since the camera entity is disabled by default
if errors >= 2:
raise ConfigEntryNotReady

config_entry.runtime_data = ECRuntimeData(
Expand Down
8 changes: 8 additions & 0 deletions homeassistant/components/environment_canada/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ def __init__(self, coordinator: ECDataUpdateCoordinator[ECRadar]) -> None:

self.content_type = "image/gif"

async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
# Trigger coordinator refresh when entity is enabled
# since radar coordinator skips initial refresh during setup
if not self.coordinator.last_update_success:
await self.coordinator.async_request_refresh()

def camera_image(
self, width: int | None = None, height: int | None = None
) -> bytes | None:
Expand Down
40 changes: 34 additions & 6 deletions homeassistant/components/environment_canada/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@

import aiohttp
from env_canada import ECWeather, ec_exc
from env_canada.ec_weather import get_ec_sites_list
import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_LANGUAGE, CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.selector import (
SelectOptionDict,
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
)

from .const import CONF_STATION, CONF_TITLE, DOMAIN

Expand All @@ -25,14 +32,16 @@ async def validate_input(data):
lang = data.get(CONF_LANGUAGE).lower()

if station:
# When station is provided, use it and get the coordinates from ECWeather
weather_data = ECWeather(station_id=station, language=lang)
else:
weather_data = ECWeather(coordinates=(lat, lon), language=lang)
await weather_data.update()

if lat is None or lon is None:
await weather_data.update()
# Always use the station's coordinates, not the user-provided ones
lat = weather_data.lat
lon = weather_data.lon
else:
# When no station is provided, use coordinates to find nearest station
weather_data = ECWeather(coordinates=(lat, lon), language=lang)
await weather_data.update()

return {
CONF_TITLE: weather_data.metadata.location,
Expand All @@ -46,6 +55,13 @@ class EnvironmentCanadaConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Environment Canada weather."""

VERSION = 1
_station_codes: list[dict[str, str]] | None = None

async def _get_station_codes(self) -> list[dict[str, str]]:
"""Get station codes, cached after first call."""
if self._station_codes is None:
self._station_codes = await get_ec_sites_list()
return self._station_codes

async def async_step_user(
self, user_input: dict[str, Any] | None = None
Expand Down Expand Up @@ -80,9 +96,21 @@ async def async_step_user(
self._abort_if_unique_id_configured()
return self.async_create_entry(title=info[CONF_TITLE], data=user_input)

station_codes = await self._get_station_codes()

data_schema = vol.Schema(
{
vol.Optional(CONF_STATION): str,
vol.Optional(CONF_STATION): SelectSelector(
SelectSelectorConfig(
options=[
SelectOptionDict(
value=station["value"], label=station["label"]
)
for station in station_codes
],
mode=SelectSelectorMode.DROPDOWN,
)
),
vol.Optional(
CONF_LATITUDE, default=self.hass.config.latitude
): cv.latitude,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/environment_canada/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
"iot_class": "cloud_polling",
"loggers": ["env_canada"],
"requirements": ["env-canada==0.11.3"]
"requirements": ["env-canada==0.12.1"]
}
6 changes: 3 additions & 3 deletions homeassistant/components/environment_canada/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"config": {
"step": {
"user": {
"title": "Environment Canada: Location and language",
"description": "You can specify a location using either a station code or latitude/longitude coordinates.\n\nDefault behavior: If no station code is entered, the system uses the latitude/longitude values configured in your Home Assistant installation.\n\nStation code format: Station codes follow the format \"s0000123\" or simply \"123\".\n\nFind station codes at https://dd.weather.gc.ca/today/citypage_weather/docs/site_list_towns_en.csv.",
"title": "Environment Canada: weather location and language",
"description": "Select a weather station from the dropdown, or specify coordinates to use the closest station. The default coordinates are from your Home Assistant installation. Weather information can be retrieved in English or French.",
"data": {
"latitude": "[%key:common::config_flow::data::latitude%]",
"longitude": "[%key:common::config_flow::data::longitude%]",
"station": "Station code",
"station": "Weather station",
"language": "Weather information language"
}
}
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/esphome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"mqtt": ["esphome/discover/#"],
"quality_scale": "platinum",
"requirements": [
"aioesphomeapi==41.13.0",
"aioesphomeapi==41.14.0",
"esphome-dashboard-api==1.3.0",
"bleak-esphome==3.4.0"
],
Expand Down
20 changes: 10 additions & 10 deletions homeassistant/components/homewizard/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def uptime_to_datetime(value: int) -> datetime:
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_import_kwh is not None,
value_fn=lambda data: data.measurement.energy_import_kwh,
value_fn=lambda data: data.measurement.energy_import_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_import_t1_kwh",
Expand All @@ -172,7 +172,7 @@ def uptime_to_datetime(value: int) -> datetime:
data.measurement.energy_import_t1_kwh is not None
and data.measurement.energy_export_t2_kwh is not None
),
value_fn=lambda data: data.measurement.energy_import_t1_kwh,
value_fn=lambda data: data.measurement.energy_import_t1_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_import_t2_kwh",
Expand All @@ -182,7 +182,7 @@ def uptime_to_datetime(value: int) -> datetime:
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_import_t2_kwh is not None,
value_fn=lambda data: data.measurement.energy_import_t2_kwh,
value_fn=lambda data: data.measurement.energy_import_t2_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_import_t3_kwh",
Expand All @@ -192,7 +192,7 @@ def uptime_to_datetime(value: int) -> datetime:
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_import_t3_kwh is not None,
value_fn=lambda data: data.measurement.energy_import_t3_kwh,
value_fn=lambda data: data.measurement.energy_import_t3_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_import_t4_kwh",
Expand All @@ -202,7 +202,7 @@ def uptime_to_datetime(value: int) -> datetime:
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_import_t4_kwh is not None,
value_fn=lambda data: data.measurement.energy_import_t4_kwh,
value_fn=lambda data: data.measurement.energy_import_t4_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_export_kwh",
Expand All @@ -212,7 +212,7 @@ def uptime_to_datetime(value: int) -> datetime:
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_export_kwh is not None,
enabled_fn=lambda data: data.measurement.energy_export_kwh != 0,
value_fn=lambda data: data.measurement.energy_export_kwh,
value_fn=lambda data: data.measurement.energy_export_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_export_t1_kwh",
Expand All @@ -227,7 +227,7 @@ def uptime_to_datetime(value: int) -> datetime:
and data.measurement.energy_export_t2_kwh is not None
),
enabled_fn=lambda data: data.measurement.energy_export_t1_kwh != 0,
value_fn=lambda data: data.measurement.energy_export_t1_kwh,
value_fn=lambda data: data.measurement.energy_export_t1_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_export_t2_kwh",
Expand All @@ -238,7 +238,7 @@ def uptime_to_datetime(value: int) -> datetime:
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_export_t2_kwh is not None,
enabled_fn=lambda data: data.measurement.energy_export_t2_kwh != 0,
value_fn=lambda data: data.measurement.energy_export_t2_kwh,
value_fn=lambda data: data.measurement.energy_export_t2_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_export_t3_kwh",
Expand All @@ -249,7 +249,7 @@ def uptime_to_datetime(value: int) -> datetime:
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_export_t3_kwh is not None,
enabled_fn=lambda data: data.measurement.energy_export_t3_kwh != 0,
value_fn=lambda data: data.measurement.energy_export_t3_kwh,
value_fn=lambda data: data.measurement.energy_export_t3_kwh or None,
),
HomeWizardSensorEntityDescription(
key="total_power_export_t4_kwh",
Expand All @@ -260,7 +260,7 @@ def uptime_to_datetime(value: int) -> datetime:
state_class=SensorStateClass.TOTAL_INCREASING,
has_fn=lambda data: data.measurement.energy_export_t4_kwh is not None,
enabled_fn=lambda data: data.measurement.energy_export_t4_kwh != 0,
value_fn=lambda data: data.measurement.energy_export_t4_kwh,
value_fn=lambda data: data.measurement.energy_export_t4_kwh or None,
),
HomeWizardSensorEntityDescription(
key="active_power_w",
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/husqvarna_automower/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ def __init__(
"""Initialize AutomowerEntity."""
super().__init__(coordinator)
self.mower_id = mower_id
parts = self.mower_attributes.system.model.split(maxsplit=2)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, mower_id)},
manufacturer="Husqvarna",
model=self.mower_attributes.system.model.removeprefix(
"HUSQVARNA "
).removeprefix("Husqvarna "),
manufacturer=parts[0],
model=parts[1],
model_id=parts[2],
name=self.mower_attributes.system.name,
serial_number=self.mower_attributes.system.serial_number,
suggested_area="Garden",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/niko_home_control/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/niko_home_control",
"iot_class": "local_push",
"loggers": ["nikohomecontrol"],
"requirements": ["nhc==0.6.1"]
"requirements": ["nhc==0.7.0"]
}
10 changes: 8 additions & 2 deletions homeassistant/components/openai_conversation/ai_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util.json import json_loads

from .const import CONF_CHAT_MODEL, RECOMMENDED_CHAT_MODEL, UNSUPPORTED_IMAGE_MODELS
from .const import (
CONF_CHAT_MODEL,
CONF_IMAGE_MODEL,
RECOMMENDED_CHAT_MODEL,
RECOMMENDED_IMAGE_MODEL,
UNSUPPORTED_IMAGE_MODELS,
)
from .entity import OpenAIBaseLLMEntity

if TYPE_CHECKING:
Expand Down Expand Up @@ -142,7 +148,7 @@ async def _async_generate_image(
mime_type=mime_type,
width=int(width) if width else None,
height=int(height) if height else None,
model="gpt-image-1",
model=self.subentry.data.get(CONF_IMAGE_MODEL, RECOMMENDED_IMAGE_MODEL),
revised_prompt=image_call.revised_prompt
if hasattr(image_call, "revised_prompt")
else None,
Expand Down
15 changes: 15 additions & 0 deletions homeassistant/components/openai_conversation/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from .const import (
CONF_CHAT_MODEL,
CONF_CODE_INTERPRETER,
CONF_IMAGE_MODEL,
CONF_MAX_TOKENS,
CONF_PROMPT,
CONF_REASONING_EFFORT,
Expand All @@ -64,6 +65,7 @@
RECOMMENDED_CHAT_MODEL,
RECOMMENDED_CODE_INTERPRETER,
RECOMMENDED_CONVERSATION_OPTIONS,
RECOMMENDED_IMAGE_MODEL,
RECOMMENDED_MAX_TOKENS,
RECOMMENDED_REASONING_EFFORT,
RECOMMENDED_TEMPERATURE,
Expand All @@ -72,6 +74,7 @@
RECOMMENDED_WEB_SEARCH,
RECOMMENDED_WEB_SEARCH_CONTEXT_SIZE,
RECOMMENDED_WEB_SEARCH_USER_LOCATION,
UNSUPPORTED_IMAGE_MODELS,
UNSUPPORTED_MODELS,
UNSUPPORTED_WEB_SEARCH_MODELS,
)
Expand Down Expand Up @@ -411,6 +414,18 @@ async def async_step_model(
)
}

if self._subentry_type == "ai_task_data" and not model.startswith(
tuple(UNSUPPORTED_IMAGE_MODELS)
):
step_schema[
vol.Optional(CONF_IMAGE_MODEL, default=RECOMMENDED_IMAGE_MODEL)
] = SelectSelector(
SelectSelectorConfig(
options=["gpt-image-1", "gpt-image-1-mini"],
mode=SelectSelectorMode.DROPDOWN,
)
)

if user_input is not None:
if user_input.get(CONF_WEB_SEARCH):
if user_input.get(CONF_WEB_SEARCH_USER_LOCATION):
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/openai_conversation/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
DEFAULT_NAME = "OpenAI Conversation"

CONF_CHAT_MODEL = "chat_model"
CONF_IMAGE_MODEL = "image_model"
CONF_CODE_INTERPRETER = "code_interpreter"
CONF_FILENAMES = "filenames"
CONF_MAX_TOKENS = "max_tokens"
Expand All @@ -31,6 +32,7 @@
CONF_WEB_SEARCH_TIMEZONE = "timezone"
RECOMMENDED_CODE_INTERPRETER = False
RECOMMENDED_CHAT_MODEL = "gpt-4o-mini"
RECOMMENDED_IMAGE_MODEL = "gpt-image-1"
RECOMMENDED_MAX_TOKENS = 3000
RECOMMENDED_REASONING_EFFORT = "low"
RECOMMENDED_TEMPERATURE = 1.0
Expand Down
Loading
Loading