Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3930f64
Use LightEntityStateAttribute enum in MQTT light template (#175947)
epenet Jul 10, 2026
7296d1b
Add new codeowner to HomeWizard (#176199)
DCSBL Jul 10, 2026
70c90f1
Add logger to Portainer (#176197)
erwindouna Jul 10, 2026
c0ce4d1
Bump energieleser to 0.1.5 (#176198)
amitkio Jul 10, 2026
0493144
Bump wiim to 0.1.5 (#176203)
Linkplay2020 Jul 10, 2026
408dc80
Portainer dedicated endpoint button description (#176196)
erwindouna Jul 10, 2026
ec016dc
Bump dsmr_parser to 1.11.1 (#176192)
jasperslits Jul 10, 2026
58ad41b
Cleanup type ignore in find_coordinates helper (#176195)
epenet Jul 10, 2026
d905433
Call super class for `async_will_remove_from_hass` overrides in MQTT …
jbouwh Jul 10, 2026
871d722
Add active mode sensor for ViCare FloorHeating devices (#170103)
lackas Jul 10, 2026
41c9a5c
Add a stop all zones button to Yardian (#174276)
aeon-matrix Jul 10, 2026
3b02aa2
Portainer remove err translations (#176190)
erwindouna Jul 10, 2026
fe66aa0
Fix Velbus power and energy sensors for counter channels (#168201)
WilliamCoenen Jul 10, 2026
dd9754d
Remove error placeholders from Proxmox (#176188)
erwindouna Jul 10, 2026
55ac2ca
Use actions in NINA to allow accessing data (#166125)
DeerMaximum Jul 10, 2026
84f18b7
Update frontend to 20260624.5 (#176216)
bramkragten Jul 10, 2026
42e1e79
Fix Teslemetry cabin overheat protection restored temperatures (#175973)
epenet Jul 10, 2026
6772f43
Include ConnectError in Ollama config flow (#176147)
synesthesiam Jul 10, 2026
d42d115
Skip global ESPHome update lock when dashboard has a build queue (#17…
bdraco Jul 10, 2026
c0047cf
Bump tuya-device-handlers to 0.0.25 (#176213)
epenet Jul 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
4 changes: 2 additions & 2 deletions CODEOWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion homeassistant/components/dsmr/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"integration_type": "hub",
"iot_class": "local_push",
"loggers": ["dsmr_parser"],
"requirements": ["dsmr-parser==1.11.0"]
"requirements": ["dsmr-parser==1.11.1"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/energieleser/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"integration_type": "device",
"iot_class": "local_polling",
"quality_scale": "silver",
"requirements": ["energieleser==0.1.4"],
"requirements": ["energieleser==0.1.5"],
"zeroconf": [
{
"type": "_stromleser._tcp.local."
Expand Down
17 changes: 10 additions & 7 deletions homeassistant/components/esphome/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
_LOGGER = logging.getLogger(__name__)

MIN_VERSION_SUPPORTS_UPDATE = AwesomeVersion("2023.1.0")
MIN_VERSION_SUPPORTS_BUILD_QUEUE = AwesomeVersion("2026.6.0")
REFRESH_INTERVAL = timedelta(minutes=5)


Expand All @@ -34,20 +35,22 @@ def __init__(self, hass: HomeAssistant, addon_slug: str, url: str) -> None:
self.url = url
self.api = ESPHomeDashboardAPI(url, async_get_clientsession(hass))
self.supports_update: bool | None = None
self.supports_build_queue = False

@override
async def _async_update_data(self) -> dict[str, ConfiguredDevice]:
"""Fetch device data."""
devices = await self.api.get_devices()
configured_devices = devices["configured"]

if (
self.supports_update is None
and configured_devices
and (current_version := configured_devices[0].get("current_version"))
if configured_devices and (
current_version := configured_devices[0].get("current_version")
):
self.supports_update = (
AwesomeVersion(current_version) > MIN_VERSION_SUPPORTS_UPDATE
)
version = AwesomeVersion(current_version)
if self.supports_update is None:
self.supports_update = version > MIN_VERSION_SUPPORTS_UPDATE
# The dashboard has its own build queue since 2026.6.0
# and can accept multiple compile requests at once
self.supports_build_queue = version >= MIN_VERSION_SUPPORTS_BUILD_QUEUE

return {dev["name"]: dev for dev in configured_devices}
36 changes: 21 additions & 15 deletions homeassistant/components/esphome/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,27 @@ async def async_install(

# Ensure only one OTA per device at a time
async with self._install_lock:
# Ensure only one compile at a time for ALL devices
async with self.hass.data.setdefault(KEY_UPDATE_LOCK, asyncio.Lock()):
coordinator = self.coordinator
api = coordinator.api
device = coordinator.data.get(self._device_info.name)
assert device is not None
configuration = device["configuration"]
if not await api.compile(configuration):
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="error_compiling",
translation_placeholders={
"configuration": configuration,
},
)
coordinator = self.coordinator
api = coordinator.api
device = coordinator.data.get(self._device_info.name)
assert device is not None
configuration = device["configuration"]
if coordinator.supports_build_queue:
# The dashboard has its own build queue
# and can handle concurrent compile requests
compiled = await api.compile(configuration)
else:
# Ensure only one compile at a time for ALL devices
async with self.hass.data.setdefault(KEY_UPDATE_LOCK, asyncio.Lock()):
compiled = await api.compile(configuration)
if not compiled:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="error_compiling",
translation_placeholders={
"configuration": configuration,
},
)

# If the device uses deep sleep, there's a small chance it goes
# to sleep right after the dashboard connects but before the OTA
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/frontend/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
"integration_type": "system",
"preview_features": { "winter_mode": {} },
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20260624.4"]
"requirements": ["home-assistant-frontend==20260624.5"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/homewizard/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "homewizard",
"name": "HomeWizard",
"codeowners": ["@DCSBL"],
"codeowners": ["@DCSBL", "@lexpostma"],
"config_flow": true,
"dhcp": [
{
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/mqtt/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ async def async_will_remove_from_hass(self) -> None:
self._expiration_trigger()
self._expiration_trigger = None
self._expired = False
await MqttEntity.async_will_remove_from_hass(self)
await super().async_will_remove_from_hass()

@staticmethod
@override
Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/mqtt/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ async def async_will_remove_from_hass(self) -> None:
self._attributes_sub_state = async_unsubscribe_topics(
self.hass, self._attributes_sub_state
)
await super().async_will_remove_from_hass()

@callback
def _attributes_message_received(self, msg: ReceiveMessage) -> None:
Expand Down Expand Up @@ -708,6 +709,7 @@ async def async_will_remove_from_hass(self) -> None:
self._availability_sub_state = async_unsubscribe_topics(
self.hass, self._availability_sub_state
)
await super().async_will_remove_from_hass()

@property
@override
Expand Down Expand Up @@ -1253,6 +1255,7 @@ def add_to_platform_abort(self) -> None:
async def async_will_remove_from_hass(self) -> None:
"""Stop listening to signal and cleanup discovery data."""
self._cleanup_discovery_on_remove()
await super().async_will_remove_from_hass()

def _cleanup_discovery_on_remove(self) -> None:
"""Stop listening to signal and cleanup discovery data."""
Expand Down Expand Up @@ -1575,9 +1578,7 @@ async def async_will_remove_from_hass(self) -> None:
self._sub_state = subscription.async_unsubscribe_topics(
self.hass, self._sub_state
)
await MqttAttributesMixin.async_will_remove_from_hass(self)
await MqttAvailabilityMixin.async_will_remove_from_hass(self)
await MqttDiscoveryUpdateMixin.async_will_remove_from_hass(self)
await super().async_will_remove_from_hass()
debug_info.remove_entity_data(self.hass, self.entity_id)

async def async_publish_with_config(
Expand Down
25 changes: 15 additions & 10 deletions homeassistant/components/mqtt/light/schema_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
ColorMode,
LightEntity,
LightEntityFeature,
LightEntityStateAttribute,
filter_supported_color_modes,
)
from homeassistant.const import (
Expand Down Expand Up @@ -361,17 +362,21 @@ async def _subscribe_topics(self) -> None:
last_state = await self.async_get_last_state()
if self._optimistic and last_state:
self._attr_is_on = last_state.state == STATE_ON
if last_state.attributes.get(ATTR_BRIGHTNESS):
self._attr_brightness = last_state.attributes.get(ATTR_BRIGHTNESS)
if last_state.attributes.get(ATTR_HS_COLOR):
self._attr_hs_color = last_state.attributes.get(ATTR_HS_COLOR)
if brightness := last_state.attributes.get(
LightEntityStateAttribute.BRIGHTNESS
):
self._attr_brightness = brightness
if hs_color := last_state.attributes.get(
LightEntityStateAttribute.HS_COLOR
):
self._attr_hs_color = hs_color
self._update_color_mode()
if last_state.attributes.get(ATTR_COLOR_TEMP_KELVIN):
self._attr_color_temp_kelvin = last_state.attributes.get(
ATTR_COLOR_TEMP_KELVIN
)
if last_state.attributes.get(ATTR_EFFECT):
self._attr_effect = last_state.attributes.get(ATTR_EFFECT)
if color_temp_kelvin := last_state.attributes.get(
LightEntityStateAttribute.COLOR_TEMP_KELVIN
):
self._attr_color_temp_kelvin = color_temp_kelvin
if effect := last_state.attributes.get(LightEntityStateAttribute.EFFECT):
self._attr_effect = effect

@override
async def async_turn_on(self, **kwargs: Any) -> None:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/mqtt/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ async def async_will_remove_from_hass(self) -> None:
self._expiration_trigger()
self._expiration_trigger = None
self._expired = False
await MqttEntity.async_will_remove_from_hass(self)
await super().async_will_remove_from_hass()

@staticmethod
@override
Expand Down
11 changes: 11 additions & 0 deletions homeassistant/components/nina/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType

from .const import (
_LOGGER,
Expand All @@ -12,11 +14,14 @@
CONF_FILTER_CORONA,
CONF_FILTERS,
CONF_HEADLINE_FILTER,
DOMAIN,
NO_MATCH_REGEX,
)
from .coordinator import NinaConfigEntry, NINADataUpdateCoordinator
from .services import async_setup_services

PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)


async def async_setup_entry(hass: HomeAssistant, entry: NinaConfigEntry) -> bool:
Expand All @@ -32,6 +37,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: NinaConfigEntry) -> bool
return True


async def async_setup(hass: HomeAssistant, _: ConfigType) -> bool:
"""Set up services."""
async_setup_services(hass)
return True


async def async_unload_entry(hass: HomeAssistant, entry: NinaConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
Expand Down
32 changes: 32 additions & 0 deletions homeassistant/components/nina/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
ATTR_WEB,
CONF_MESSAGE_SLOTS,
CONF_REGIONS,
SERVICE_DATA_AFFECTED_AREAS,
SERVICE_DATA_DESCRIPTION,
SERVICE_DATA_EXPIRES,
SERVICE_DATA_HEADLINE,
SERVICE_DATA_ID,
SERVICE_DATA_RECOMMENDED_ACTIONS,
SERVICE_DATA_SENDER,
SERVICE_DATA_SENT,
SERVICE_DATA_SEVERITY,
SERVICE_DATA_START,
SERVICE_DATA_WEB,
)
from .coordinator import NinaConfigEntry, NINADataUpdateCoordinator
from .entity import NinaEntity
Expand Down Expand Up @@ -105,3 +116,24 @@ def extra_state_attributes(self) -> dict[str, Any]:
if data.expires
else "", # Deprecated, remove in 2026.11
}

def get_details(self) -> dict[str, str] | None:
"""Return the details of the warning."""
if not self.is_on:
return None

data = self._get_warning_data()

return {
SERVICE_DATA_HEADLINE: data.headline,
SERVICE_DATA_DESCRIPTION: data.description,
SERVICE_DATA_SENDER: data.sender,
SERVICE_DATA_SEVERITY: data.severity or "Unknown",
SERVICE_DATA_RECOMMENDED_ACTIONS: data.recommended_actions,
SERVICE_DATA_AFFECTED_AREAS: data.affected_areas,
SERVICE_DATA_WEB: data.more_info_url,
SERVICE_DATA_ID: data.id,
SERVICE_DATA_SENT: data.sent.isoformat(),
SERVICE_DATA_START: data.start.isoformat() if data.start else "",
SERVICE_DATA_EXPIRES: data.expires.isoformat() if data.expires else "",
}
14 changes: 14 additions & 0 deletions homeassistant/components/nina/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@

SEVERITY_VALUES: list[str] = ["extreme", "severe", "moderate", "minor", "unknown"]

SERVICE_GET_DETAILS: str = "get_details"

SERVICE_DATA_HEADLINE: str = "headline"
SERVICE_DATA_DESCRIPTION: str = "description"
SERVICE_DATA_SENDER: str = "sender"
SERVICE_DATA_SEVERITY: str = "severity"
SERVICE_DATA_RECOMMENDED_ACTIONS: str = "recommended_actions"
SERVICE_DATA_AFFECTED_AREAS: str = "affected_areas"
SERVICE_DATA_WEB: str = "web"
SERVICE_DATA_ID: str = "id"
SERVICE_DATA_SENT: str = "sent"
SERVICE_DATA_START: str = "start"
SERVICE_DATA_EXPIRES: str = "expires"

CONF_REGIONS: str = "regions"
CONF_MESSAGE_SLOTS: str = "slots"
CONF_FILTERS: str = "filters"
Expand Down
24 changes: 24 additions & 0 deletions homeassistant/components/nina/icons.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"entity": {
"sensor": {
"affected_areas": {
"default": "mdi:map-marker-radius"
},
"headline": {
"default": "mdi:text-short"
},
"more_info_url": {
"default": "mdi:web"
},
"sender": {
"default": "mdi:account-tie-voice"
},
"severity": {
"default": "mdi:alert"
}
}
},
"services": {
"get_details": { "service": "mdi:download" }
}
}
17 changes: 4 additions & 13 deletions homeassistant/components/nina/quality_scale.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
rules:
# Bronze
action-setup:
status: exempt
comment: |
This integration does not provide additional actions.
action-setup: done
appropriate-polling: done
brands: done
common-modules: done
config-flow-test-coverage: done
config-flow: done
dependency-transparency: done
docs-actions:
status: exempt
comment: |
This integration does not provide additional actions.
docs-actions: done
docs-conditions:
status: exempt
comment: This integration does not have any conditions.
Expand All @@ -35,10 +29,7 @@ rules:
unique-config-entry: done

# Silver
action-exceptions:
status: exempt
comment: |
This integration does not provide additional actions.
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters: done
docs-installation-parameters: done
Expand Down Expand Up @@ -78,7 +69,7 @@ rules:
entity-disabled-by-default: done
entity-translations: done
exception-translations: todo
icon-translations: todo
icon-translations: done
reconfiguration-flow: todo
repair-issues:
status: exempt
Expand Down
Loading
Loading