Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5aa8bbc
Remove clearing of via_device self references from integrations (#178…
emontnemery Aug 21, 2026
a497ede
Add number platform to Lyngdorf (#179448)
fishloa Aug 21, 2026
1e7d853
Add OpenEVSE switch platform (#179660)
firstof9 Aug 21, 2026
fde9c53
Add activation and skip reason to gardena (#169919)
elupus Aug 21, 2026
b7016f7
Recompute the local calendar event instead of caching it (#178763)
soldier2008 Aug 21, 2026
83ddd41
Use latest HueBLE (#179721)
flip-dots Aug 21, 2026
5f6ab83
Bump nice-go to 1.0.3 (#179747)
IceBotYT Aug 21, 2026
11768c7
Update numpy to 2.5.2 (#178633)
cdce8p Aug 21, 2026
4763a19
Fix derivative sensor staying unavailable after total_increasing rese…
manan-tech Aug 21, 2026
2cc0f1a
Switchbot Cloud:Add a night light control to the fan (#177514)
XiaoLing-git Aug 21, 2026
a4bb1d0
Pass config entry explicitly in Supla coordinator (#178347)
Fistacho Aug 21, 2026
a1b783d
Fix missing device trackers after initial setup in devolo Home Networ…
Shutgun Aug 21, 2026
7d730cb
Fix LiteLLM conversation subentry not remembering unselected LLM APIs…
luismalves Aug 21, 2026
4712c54
Fix HomeWizard setup flow giving error already_in_progress when tryin…
DCSBL Aug 21, 2026
28d1494
fix enphase envoy diagnostics report error (#177849)
catsmanac Aug 21, 2026
b28592f
Fix OpenRGB turn_off being a no-op for devices without Off mode in no…
Wescholm Aug 21, 2026
63f60b5
Map SmartThings aIComfort AC mode to HVAC auto (#174513)
moridew Aug 21, 2026
0ac7efc
Fix swallowed exceptions in action handlers for Simplepush (#178012)
mstu01 Aug 21, 2026
2087243
Bump lyngdorf to 1.10.0 (#179739)
fishloa Aug 21, 2026
ca732cb
bump pyenphase to 4.0 and add required None handling and tests (#179673)
catsmanac Aug 21, 2026
90fceb8
Fix missing Z-Wave power monitoring sensors in isy994 integration (#1…
SoundMatt Aug 21, 2026
770da0a
Add OCI image labels to Portainer (#176678)
erwindouna Aug 21, 2026
9926296
Remove just go2rtc sessions of the failing camera (#179534)
edenhaus Aug 21, 2026
9c52465
Remove system_timezone in local_calendar diagnostics (#178237)
soldier2008 Aug 21, 2026
78134fc
Migrate to ha-utils for datetime.now for fyta (#177924)
dontinelli Aug 21, 2026
8978003
Bump aiowebostv to 0.9.2 (#179757)
thecode Aug 21, 2026
df00965
Avoid a naive datetime.now() in broadlink (#179181)
soldier2008 Aug 21, 2026
124a081
Type the caldav warned-calendar cache with HassKey (#176143)
David-Wu1119 Aug 21, 2026
64d00b7
Fix unused Gardena Bluetooth aqua contour sensor snapshots (#179763)
balloob Aug 21, 2026
9f55544
Add preferred_bitrate option to TTS audio conversion (#179760)
bboe Aug 21, 2026
c387c48
Split user flow init and data submission in gdacs config flow tests (…
exxamalte Aug 21, 2026
f670ebb
Split user flow init and data submission in wolflink config flow test…
EnjoyingM Aug 21, 2026
d75fc21
Split user flow init and data submission in fritzbox config flow test…
mib1185 Aug 21, 2026
39e1106
Bump pyyardian to 1.4.2 (#179717)
aeon-matrix Aug 21, 2026
a13300c
USB Websocket API to list serial ports (#179524)
puddly Aug 21, 2026
daef5e9
Bump guntamatic to v1.11.0 (#179767)
JensTimmerman Aug 21, 2026
bdd2069
Avoid a naive datetime.now() in august (#179182)
soldier2008 Aug 21, 2026
f6c9b6f
Add Hotspring sensor platform (#179697)
Moustachauve Aug 21, 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
5 changes: 3 additions & 2 deletions homeassistant/components/august/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""August util functions."""

from datetime import datetime, timedelta
from datetime import timedelta
from functools import partial

import aiohttp
Expand All @@ -11,6 +11,7 @@

from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import aiohttp_client
from homeassistant.util import dt as dt_util

from . import AugustData

Expand Down Expand Up @@ -61,7 +62,7 @@ def _activity_time_based(latest: Activity) -> Activity | None:
"""Get the latest state of the sensor."""
start = latest.activity_start_time
end = latest.activity_end_time + TIME_TO_DECLARE_DETECTION
if start <= datetime.now() <= end: # pylint: disable=home-assistant-enforce-naive-now
if start <= dt_util.naive_now() <= end:
return latest
return None

Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/broadlink/heartbeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from homeassistant.const import CONF_HOST
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import event
from homeassistant.util import dt as dt_util

from .const import DOMAIN

Expand All @@ -31,7 +32,7 @@ def __init__(self, hass: HomeAssistant) -> None:
async def async_setup(self) -> None:
"""Set up the heartbeat."""
if self._unsubscribe is None:
await self.async_heartbeat(dt.datetime.now()) # pylint: disable=home-assistant-enforce-naive-now
await self.async_heartbeat(dt_util.utcnow())
self._unsubscribe = event.async_track_time_interval(
self._hass, self.async_heartbeat, self.HEARTBEAT_INTERVAL
)
Expand Down
7 changes: 2 additions & 5 deletions homeassistant/components/caldav/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Library for working with CalDAV api."""
# pylint: disable=home-assistant-use-runtime-data # Uses legacy hass.data[DOMAIN] pattern

import logging

Expand All @@ -8,7 +7,7 @@

from homeassistant.core import HomeAssistant

from .const import DOMAIN
from .const import WARNED_CALENDARS

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -45,9 +44,7 @@ def _get_calendars() -> tuple[
calendars, needs_warning = await hass.async_add_executor_job(_get_calendars)

if needs_warning:
warned_calendars: set[tuple[str, str]] = hass.data.setdefault(
DOMAIN, {}
).setdefault("warned_calendars", set())
warned_calendars = hass.data.setdefault(WARNED_CALENDARS, set())
for url, name, comp in needs_warning:
# This workaround and warning can be removed when we upgrade to caldav 3.0
if (url, comp) not in warned_calendars:
Expand Down
7 changes: 7 additions & 0 deletions homeassistant/components/caldav/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@

from typing import Final

from homeassistant.util.hass_dict import HassKey

DOMAIN: Final = "caldav"
TIMEOUT: Final = 30

# Calendars we have already warned about, keyed by (url, component). This is
# deliberately not stored on a config entry: the warning is per CalDAV server
# and must survive reloads, and the same server may back more than one entry.
WARNED_CALENDARS: HassKey[set[tuple[str, str]]] = HassKey(f"{DOMAIN}_warned_calendars")
2 changes: 1 addition & 1 deletion homeassistant/components/compensation/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/compensation",
"iot_class": "calculated",
"quality_scale": "legacy",
"requirements": ["numpy==2.3.2"]
"requirements": ["numpy==2.5.2"]
}
9 changes: 8 additions & 1 deletion homeassistant/components/derivative/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,8 @@ def calc_derivative(
old_timestamp: datetime,
) -> None:
"""Handle the sensor state changes."""
if not _is_decimal_state(old_value):
recovered_from_invalid = not _is_decimal_state(old_value)
if recovered_from_invalid:
if self._last_valid_state_time:
old_value = self._last_valid_state_time[0]
old_timestamp = self._last_valid_state_time[1]
Expand Down Expand Up @@ -550,6 +551,12 @@ def calc_derivative(
"%s: Dropping sample as source total_increasing sensor decreased",
self.entity_id,
)
if recovered_from_invalid:
# Reset while recovering from an invalid source: re-baseline
# and report zero so the entity doesn't stay stuck unavailable.
self._state_list = []
self._last_valid_state_time = (new_state.state, new_timestamp)
self._write_native_value(Decimal(0))
return

# add latest derivative to the window list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def restore_entities() -> None:
async_add_entities(missing)

restore_entities()
new_device_callback()
entry.async_on_unload(
coordinators[CONNECTED_WIFI_CLIENTS].async_add_listener(new_device_callback)
)
Expand Down
6 changes: 5 additions & 1 deletion homeassistant/components/enphase_envoy/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any

from aiohttp import ClientResponse
from aiohttp import ClientError, ClientResponse
from pyenphase.envoy import Envoy
from pyenphase.exceptions import EnvoyError

Expand Down Expand Up @@ -92,6 +92,10 @@ async def _get_fixture_collection(envoy: Envoy, serial: str) -> dict[str, Any]:
"code": response.status,
}
)
except ClientError as err:
fixture_data[f"{end_point}_log"] = {
"Error": f"Aiohttp Client error {type(err).__name__ if not hasattr(err, 'status') else err.status}"
}
except EnvoyError as err:
fixture_data[f"{end_point}_log"] = {"Error": repr(err)}
return fixture_data
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/enphase_envoy/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"iot_class": "local_polling",
"loggers": ["pyenphase"],
"quality_scale": "platinum",
"requirements": ["pyenphase==3.2.1"],
"requirements": ["pyenphase==4.0.0"],
"zeroconf": [
{
"type": "_enphase-envoy._tcp.local."
Expand Down
86 changes: 62 additions & 24 deletions homeassistant/components/enphase_envoy/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
EnvoySystemConsumption,
EnvoySystemProduction,
)
from pyenphase.const import PHASENAMES
from pyenphase.const import PHASENAMES, SupportedFeatures
from pyenphase.models.acb import ACBChargeStatus, ACBSleepState
from pyenphase.models.meters import (
CtMeterStatus,
Expand Down Expand Up @@ -383,7 +383,7 @@ class EnvoyCTSensorEntityDescription(SensorEntityDescription):
"""Describes an Envoy CT sensor entity."""

value_fn: Callable[
[EnvoyMeterData],
[EnvoyMeterData | None],
int | float | str | CtType | CtMeterStatus | CtStatusFlags | CtState | None,
]
on_phase: str | None = None
Expand Down Expand Up @@ -586,7 +586,9 @@ class EnvoyCTSensorEntityDescription(SensorEntityDescription):
translation_key=(translation_key if translation_key != "" else key),
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
value_fn=lambda ct: 0 if ct.status_flags is None else len(ct.status_flags),
value_fn=lambda ct: (
0 if ct is None or ct.status_flags is None else len(ct.status_flags)
),
cttype=cttype,
)
for cttype, key, translation_key in (
Expand Down Expand Up @@ -1020,47 +1022,67 @@ async def async_setup_entry(
) -> None:
"""Set up envoy sensor platform."""
coordinator = config_entry.runtime_data
envoy_data = coordinator.envoy.data
envoy = coordinator.envoy
assert envoy is not None
envoy_data = envoy.data
assert envoy_data is not None
_LOGGER.debug("Envoy data: %s", envoy_data)

entities: list[Entity] = [
EnvoyProductionEntity(coordinator, description)
for description in PRODUCTION_SENSORS
]
if envoy_data.system_consumption:
# add unconditionally if TOTAL_CONSUMPTION is available to overcome
# None value at startup caused by envoy fw issues
if envoy.supported_features & SupportedFeatures.TOTAL_CONSUMPTION:
entities.extend(
EnvoyConsumptionEntity(coordinator, description)
for description in CONSUMPTION_SENSORS
)
if envoy_data.system_net_consumption:
# add unconditionally if NET_CONSUMPTION is available to overcome
# None value at startup caused by envoy fw issues
if envoy.supported_features & SupportedFeatures.NET_CONSUMPTION:
entities.extend(
EnvoyNetConsumptionEntity(coordinator, description)
for description in NET_CONSUMPTION_SENSORS
)
# For each production phase reported add production entities
if envoy_data.system_production_phases:
# if PRODUCTION is available and phases detected even if None
# to overcome None value at startup caused by envoy fw issues
if envoy.active_phase_count and (
envoy.supported_features & SupportedFeatures.PRODUCTION
):
entities.extend(
EnvoyProductionPhaseEntity(coordinator, description)
for use_phase, phase in envoy_data.system_production_phases.items()
for index, use_phase in enumerate(PHASENAMES)
for description in PRODUCTION_PHASE_SENSORS[use_phase]
if phase is not None
if index < (envoy.phase_count if envoy.phase_count > 1 else 0)
)
# For each consumption phase reported add consumption entities
if envoy_data.system_consumption_phases:
# if TOTAL_CONSUMPTION is available and phases detected even if None
# to overcome None value at startup caused by envoy fw issues
if (
envoy.active_phase_count
and envoy.phase_count > 1
and (envoy.supported_features & SupportedFeatures.TOTAL_CONSUMPTION)
):
entities.extend(
EnvoyConsumptionPhaseEntity(coordinator, description)
for use_phase, phase in envoy_data.system_consumption_phases.items()
for index, use_phase in enumerate(PHASENAMES)
for description in CONSUMPTION_PHASE_SENSORS[use_phase]
if phase is not None
if index < (envoy.phase_count if envoy.phase_count > 1 else 0)
)
# For each net_consumption phase reported add consumption entities
if envoy_data.system_net_consumption_phases:
# if NET_CONSUMPTION is available and phases detected even if None
# to overcome None value at startup caused by envoy fw issues
if envoy.active_phase_count and (
envoy.supported_features & SupportedFeatures.NET_CONSUMPTION
):
entities.extend(
EnvoyNetConsumptionPhaseEntity(coordinator, description)
for use_phase, phase in envoy_data.system_net_consumption_phases.items()
for index, use_phase in enumerate(PHASENAMES)
for description in NET_CONSUMPTION_PHASE_SENSORS[use_phase]
if phase is not None
if index < (envoy.phase_count if envoy.phase_count > 1 else 0)
)
# Add Current Transformer entities
if envoy_data.ctmeters:
Expand Down Expand Up @@ -1181,8 +1203,8 @@ class EnvoyProductionEntity(EnvoySystemSensorEntity):
@override
def native_value(self) -> int | None:
"""Return the state of the sensor."""
system_production = self.data.system_production
assert system_production is not None
if (system_production := self.data.system_production) is None:
return None
return self.entity_description.value_fn(system_production)


Expand All @@ -1195,8 +1217,8 @@ class EnvoyConsumptionEntity(EnvoySystemSensorEntity):
@override
def native_value(self) -> int | None:
"""Return the state of the sensor."""
system_consumption = self.data.system_consumption
assert system_consumption is not None
if (system_consumption := self.data.system_consumption) is None:
return None
return self.entity_description.value_fn(system_consumption)


Expand All @@ -1209,8 +1231,8 @@ class EnvoyNetConsumptionEntity(EnvoySystemSensorEntity):
@override
def native_value(self) -> int | None:
"""Return the state of the sensor."""
system_net_consumption = self.data.system_net_consumption
assert system_net_consumption is not None
if (system_net_consumption := self.data.system_net_consumption) is None:
return None
return self.entity_description.value_fn(system_net_consumption)


Expand All @@ -1225,8 +1247,11 @@ def native_value(self) -> int | None:
"""Return the state of the sensor."""
if TYPE_CHECKING:
assert self.entity_description.on_phase
assert self.data.system_production_phases

if self.data.system_production_phases is None:
return None
if self.entity_description.on_phase not in self.data.system_production_phases:
return None
if (
system_production := self.data.system_production_phases[
self.entity_description.on_phase
Expand All @@ -1247,8 +1272,11 @@ def native_value(self) -> int | None:
"""Return the state of the sensor."""
if TYPE_CHECKING:
assert self.entity_description.on_phase
assert self.data.system_consumption_phases

if self.data.system_consumption_phases is None:
return None
if self.entity_description.on_phase not in self.data.system_consumption_phases:
return None
if (
system_consumption := self.data.system_consumption_phases[
self.entity_description.on_phase
Expand All @@ -1269,8 +1297,14 @@ def native_value(self) -> int | None:
"""Return the state of the sensor."""
if TYPE_CHECKING:
assert self.entity_description.on_phase
assert self.data.system_net_consumption_phases

if self.data.system_net_consumption_phases is None:
return None
if (
self.entity_description.on_phase
not in self.data.system_net_consumption_phases
):
return None
if (
system_net_consumption := self.data.system_net_consumption_phases[
self.entity_description.on_phase
Expand All @@ -1293,6 +1327,8 @@ def native_value(
"""Return the state of the CT sensor."""
if (cttype := self.entity_description.cttype) not in self.data.ctmeters:
return None
if self.data.ctmeters[cttype] is None:
return None
return self.entity_description.value_fn(self.data.ctmeters[cttype])


Expand All @@ -1315,6 +1351,8 @@ def native_value(
cttype
]:
return None
if self.data.ctmeters_phases[cttype][phase] is None:
return None
return self.entity_description.value_fn(
self.data.ctmeters_phases[cttype][phase]
)
Expand Down
8 changes: 3 additions & 5 deletions homeassistant/components/fyta/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Coordinator for FYTA integration."""

from collections.abc import Callable
from datetime import datetime, timedelta
from datetime import timedelta
import logging
from typing import override

Expand All @@ -20,6 +20,7 @@
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util

from .const import CONF_EXPIRATION, DOMAIN

Expand Down Expand Up @@ -54,10 +55,7 @@ async def _async_update_data(
) -> dict[int, Plant]:
"""Fetch data from API endpoint."""

if (
self.fyta.expiration is None
or self.fyta.expiration.timestamp() < datetime.now().timestamp() # pylint: disable=home-assistant-enforce-naive-now
):
if self.fyta.expiration is None or self.fyta.expiration < dt_util.now():
await self.renew_authentication()

try:
Expand Down
Loading
Loading