Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e786939
Improve search test coverage of synthetic device handling (#182166)
emontnemery Sep 14, 2026
4c8c05b
Improve logbook test coverage of synthetic device handling (#182165)
emontnemery Sep 14, 2026
432e9d4
Improve hue test coverage of synthetic device handling (#182164)
emontnemery Sep 14, 2026
b94ec35
LibreNMS reached silver on the IQS (#182098)
mib1185 Sep 14, 2026
c8035dc
Move service registration to async_setup in lifx (#181196)
epenet Sep 14, 2026
152ca3f
Move service registration to async_setup in zha (#181186)
epenet Sep 14, 2026
401bcae
Add SwitchBot Universal Remote Control battery sensor (#174101)
Onero-testdev Sep 14, 2026
17fe096
Add AirGradient measurement interval number (#180319)
samuelbles07 Sep 14, 2026
b3a105c
Add energy site reconfigure flow to Teslemetry (#181335)
Bre77 Sep 14, 2026
59272ae
Add explicit device creation for DALI lines of lunatone (#180895)
MoonDevLT Sep 14, 2026
1d38f36
Add Besen charger display temperature unit select (#180888)
moryoav Sep 14, 2026
42ed09d
Add Tuya sfkzq water valve test fixture (#182169)
syl-craft Sep 14, 2026
0349bfc
Move remaining lifx actions to services module (#182172)
epenet Sep 14, 2026
25fc54e
Handle gone next flow in improv_ble provisioning (#182147)
balloob Sep 14, 2026
ae3fae9
Add TP-Link Omada controller device and update support (#181993)
rubempoli Sep 14, 2026
74639e3
Include disabled entities in search/related when requested (#178024)
shbatm Sep 14, 2026
2b993ee
Bump aiocomelit to 3.0.0 (#182193)
chemelli74 Sep 14, 2026
9fedf1e
Drop "unsupported" suffix in Tuya device info (#182171)
epenet Sep 14, 2026
3e18e6c
Name the two ZhongHong fan speeds the climate component does not (#18…
crhan Sep 14, 2026
2109e42
Fix Google Tasks error handling on DNS failure (#182195)
joostlek Sep 14, 2026
2193749
Add glass break device class for binary_sensor (#181332)
catellie Sep 14, 2026
5ba6d59
Re-read a ZhongHong unit shortly after commanding it (#182074)
crhan Sep 14, 2026
b0e7823
Add date to response for IMAP fetch service call (#181604)
noantiq Sep 14, 2026
90da985
Fix race in conversation test_todo_add_item_fr (#182205)
epenet Sep 14, 2026
0475dc7
Move imap service registration to services module (#182207)
epenet Sep 14, 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: 2 additions & 0 deletions homeassistant/components/airgradient/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
LED_BAR_MODE = "led_bar_mode"
LED_BAR_BRIGHTNESS = "led_bar_brightness"
DISPLAY_BRIGHTNESS = "display_brightness"
MEASUREMENT_INTERVAL = "measurement_interval"
GPS_MODE = "gps_mode"
FRONT_LED_BRIGHTNESS = "front_led_brightness"
BACK_LED_BRIGHTNESS = "back_led_brightness"
Expand Down Expand Up @@ -62,6 +63,7 @@ class ModelCapabilities:
TVOC_LEARNING_OFFSET,
PM_STANDARD_CONFIG,
TEMPERATURE_UNIT,
MEASUREMENT_INTERVAL,
GPS_MODE,
FRONT_LED_BRIGHTNESS,
BACK_LED_BRIGHTNESS,
Expand Down
22 changes: 20 additions & 2 deletions homeassistant/components/airgradient/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

from homeassistant.components.number import (
DOMAIN as NUMBER_DOMAIN,
NumberDeviceClass,
NumberEntity,
NumberEntityDescription,
NumberMode,
)
from homeassistant.const import EntityCategory, UnitOfRatio
from homeassistant.const import EntityCategory, UnitOfRatio, UnitOfTime
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
Expand All @@ -21,6 +23,7 @@
from .const import (
DISPLAY_BRIGHTNESS as DISPLAY_BRIGHTNESS_CONFIG,
DOMAIN,
MEASUREMENT_INTERVAL as MEASUREMENT_INTERVAL_CONFIG,
supports_config,
)
from .coordinator import AirGradientCoordinator
Expand Down Expand Up @@ -64,6 +67,21 @@ class AirGradientNumberEntityDescription(NumberEntityDescription):
set_value_fn=lambda client, value: client.set_led_bar_brightness(value),
)

MEASUREMENT_INTERVAL = AirGradientNumberEntityDescription(
key="measurement_interval",
translation_key="measurement_interval",
entity_category=EntityCategory.CONFIG,
device_class=NumberDeviceClass.DURATION,
mode=NumberMode.BOX,
native_min_value=1,
native_max_value=3600,
native_step=1,
native_unit_of_measurement=UnitOfTime.SECONDS,
config_key=MEASUREMENT_INTERVAL_CONFIG,
value_fn=lambda config: config.measurement_interval,
set_value_fn=lambda client, value: client.set_measurement_interval(value),
)


async def async_setup_entry(
hass: HomeAssistant,
Expand All @@ -74,7 +92,7 @@ async def async_setup_entry(

coordinator = entry.runtime_data
model = coordinator.data.measures.model
descriptions = (DISPLAY_BRIGHTNESS, LED_BAR_BRIGHTNESS)
descriptions = (DISPLAY_BRIGHTNESS, LED_BAR_BRIGHTNESS, MEASUREMENT_INTERVAL)
descriptions_by_key = {description.key: description for description in descriptions}
added_entities: set[str] = set()

Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/airgradient/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
},
"led_bar_brightness": {
"name": "LED bar brightness"
},
"measurement_interval": {
"name": "Measurement interval"
}
},
"select": {
Expand Down
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.NUMBER, Platform.SENSOR, Platform.SWITCH]
PLATFORMS: Final = [Platform.NUMBER, Platform.SELECT, 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 @@ -95,6 +95,11 @@ async def async_set_charge_amps(self, amps: int) -> None:

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

async def async_set_temperature_unit(self, unit: str) -> None:
"""Set the charger display temperature unit."""

await self._async_run_command(self.client.async_set_temperature_unit(unit))

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

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

from collections.abc import Awaitable, Callable, Mapping
from dataclasses import dataclass
from typing import Final, override

from besen.models import BesenData

from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.const import EntityCategory
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

TEMPERATURE_UNIT_OPTIONS: Final = {
"celsius": "Celsius",
"fahrenheit": "Fahrenheit",
}
TEMPERATURE_UNIT_VALUES: Final = {
value: key for key, value in TEMPERATURE_UNIT_OPTIONS.items()
}


def _option_value(value: str | None, options: Mapping[str, str]) -> str | None:
"""Return a Home Assistant option for a charger value."""

return options.get(value) if value is not None else None


@dataclass(frozen=True, kw_only=True)
class BesenSelectEntityDescription(SelectEntityDescription):
"""Describe a Besen select entity."""

current_option_fn: Callable[[BesenData], str | None]
option_values: dict[str, str]
select_option_fn: Callable[[BesenCoordinator, str], Awaitable[None]]


SELECT_DESCRIPTIONS: tuple[BesenSelectEntityDescription, ...] = (
BesenSelectEntityDescription(
key="temperature_unit",
translation_key="temperature_unit",
entity_category=EntityCategory.CONFIG,
options=list(TEMPERATURE_UNIT_OPTIONS),
current_option_fn=lambda data: _option_value(
data.config.temperature_unit, TEMPERATURE_UNIT_VALUES
),
option_values=TEMPERATURE_UNIT_OPTIONS,
select_option_fn=lambda coordinator, option: (
coordinator.async_set_temperature_unit(option)
),
),
)


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

async_add_entities(
BesenSelect(entry.runtime_data, description)
for description in SELECT_DESCRIPTIONS
)


class BesenSelect(BesenEntity, SelectEntity):
"""Representation of a Besen select."""

entity_description: BesenSelectEntityDescription

def __init__(
self,
coordinator: BesenCoordinator,
description: BesenSelectEntityDescription,
) -> None:
"""Initialize a Besen select."""

super().__init__(coordinator, description.key)
self.entity_description = description

@property
@override
def current_option(self) -> str | None:
"""Return the current option."""

return self.entity_description.current_option_fn(self.coordinator.data)

@override
async def async_select_option(self, option: str) -> None:
"""Set the selected option."""

await self.entity_description.select_option_fn(
self.coordinator,
self.entity_description.option_values[option],
)
9 changes: 9 additions & 0 deletions homeassistant/components/besen/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@
"number": {
"charging_current": { "name": "Charging current" }
},
"select": {
"temperature_unit": {
"name": "Temperature unit",
"state": {
"celsius": "Celsius",
"fahrenheit": "Fahrenheit"
}
}
},
"sensor": {
"charging_message": {
"name": "Charging message",
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/binary_sensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class BinarySensorDeviceClass(StrEnum):
# On means gas detected, Off means no gas (clear)
GAS = "gas"

# On means glass break detected, Off means no glass break (clear)
GLASS_BREAK = "glass_break"

# On means hot, Off means normal
HEAT = "heat"

Expand Down
8 changes: 8 additions & 0 deletions homeassistant/components/binary_sensor/device_condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
CONF_IS_NOT_CONNECTED = "is_not_connected"
CONF_IS_GAS = "is_gas"
CONF_IS_NO_GAS = "is_no_gas"
CONF_IS_GLASS_BREAK = "is_glass_break"
CONF_IS_NO_GLASS_BREAK = "is_no_glass_break"
CONF_IS_HOT = "is_hot"
CONF_IS_NOT_HOT = "is_not_hot"
CONF_IS_LIGHT = "is_light"
Expand Down Expand Up @@ -83,6 +85,7 @@
CONF_IS_COLD,
CONF_IS_CONNECTED,
CONF_IS_GAS,
CONF_IS_GLASS_BREAK,
CONF_IS_HOT,
CONF_IS_LIGHT,
CONF_IS_NOT_LOCKED,
Expand Down Expand Up @@ -123,6 +126,7 @@
CONF_IS_NOT_UNSAFE,
CONF_IS_NO_CO,
CONF_IS_NO_GAS,
CONF_IS_NO_GLASS_BREAK,
CONF_IS_NO_LIGHT,
CONF_IS_NO_MOTION,
CONF_IS_NO_PROBLEM,
Expand Down Expand Up @@ -167,6 +171,10 @@
{CONF_TYPE: CONF_IS_GAS},
{CONF_TYPE: CONF_IS_NO_GAS},
],
BinarySensorDeviceClass.GLASS_BREAK: [
{CONF_TYPE: CONF_IS_GLASS_BREAK},
{CONF_TYPE: CONF_IS_NO_GLASS_BREAK},
],
BinarySensorDeviceClass.HEAT: [
{CONF_TYPE: CONF_IS_HOT},
{CONF_TYPE: CONF_IS_NOT_HOT},
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/binary_sensor/device_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
CONF_NOT_CONNECTED = "not_connected"
CONF_GAS = "gas"
CONF_NO_GAS = "no_gas"
CONF_GLASS_BREAK = "glass_break"
CONF_NO_GLASS_BREAK = "no_glass_break"
CONF_HOT = "hot"
CONF_NOT_HOT = "not_hot"
CONF_LIGHT = "light"
Expand Down Expand Up @@ -104,6 +106,10 @@
{CONF_TYPE: CONF_GAS},
{CONF_TYPE: CONF_NO_GAS},
],
BinarySensorDeviceClass.GLASS_BREAK: [
{CONF_TYPE: CONF_GLASS_BREAK},
{CONF_TYPE: CONF_NO_GLASS_BREAK},
],
BinarySensorDeviceClass.HEAT: [
{CONF_TYPE: CONF_HOT},
{CONF_TYPE: CONF_NOT_HOT},
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/binary_sensor/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
"on": "mdi:alert-circle"
}
},
"glass_break": {
"default": "mdi:glass-fragile"
},
"heat": {
"default": "mdi:thermometer",
"state": {
Expand Down
11 changes: 11 additions & 0 deletions homeassistant/components/binary_sensor/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"is_cold": "{entity_name} is cold",
"is_connected": "{entity_name} is connected",
"is_gas": "{entity_name} is detecting gas",
"is_glass_break": "{entity_name} is detecting glass break",
"is_hot": "{entity_name} is hot",
"is_light": "{entity_name} is detecting light",
"is_locked": "{entity_name} is locked",
Expand All @@ -15,6 +16,7 @@
"is_moving": "{entity_name} is moving",
"is_no_co": "{entity_name} is not detecting carbon monoxide",
"is_no_gas": "{entity_name} is not detecting gas",
"is_no_glass_break": "{entity_name} is not detecting glass break",
"is_no_light": "{entity_name} is not detecting light",
"is_no_motion": "{entity_name} is not detecting motion",
"is_no_problem": "{entity_name} is not detecting problem",
Expand Down Expand Up @@ -64,6 +66,7 @@
"cold": "{entity_name} became cold",
"connected": "{entity_name} connected",
"gas": "{entity_name} started detecting gas",
"glass_break": "{entity_name} detected glass break",
"hot": "{entity_name} became hot",
"light": "{entity_name} started detecting light",
"locked": "{entity_name} locked",
Expand All @@ -72,6 +75,7 @@
"moving": "{entity_name} started moving",
"no_co": "{entity_name} stopped detecting carbon monoxide",
"no_gas": "{entity_name} stopped detecting gas",
"no_glass_break": "{entity_name} stopped detecting glass break",
"no_light": "{entity_name} stopped detecting light",
"no_motion": "{entity_name} stopped detecting motion",
"no_problem": "{entity_name} stopped detecting problem",
Expand Down Expand Up @@ -176,6 +180,13 @@
"on": "Detected"
}
},
"glass_break": {
"name": "Glass break",
"state": {
"off": "Clear",
"on": "Glass break detected"
}
},
"heat": {
"name": "Heat",
"state": {
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/comelit/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from enum import StrEnum
from typing import Any, TypedDict, cast, override

from aiocomelit import ComelitSerialBridgeObject
from aiocomelit import ComelitDeviceObject
from aiocomelit.const import CLIMATE

from homeassistant.components.climate import (
Expand Down Expand Up @@ -128,7 +128,7 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
def __init__(
self,
coordinator: ComelitSerialBridge,
device: ComelitSerialBridgeObject,
device: ComelitDeviceObject,
config_entry_entry_id: str,
) -> None:
"""Init light entity."""
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/comelit/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging

from aiocomelit.api import (
ComelitSerialBridgeObject,
ComelitDeviceObject,
ComelitVedoAreaObject,
ComelitVedoZoneObject,
)
Expand All @@ -12,7 +12,7 @@
LOGGER = logging.getLogger(__package__)

type ObjectClassType = (
ComelitSerialBridgeObject | ComelitVedoAreaObject | ComelitVedoZoneObject
ComelitDeviceObject | ComelitVedoAreaObject | ComelitVedoZoneObject
)


Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/comelit/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from datetime import timedelta
from typing import TypeVar, cast, override

from aiocomelit.api import ComelitCommonApi, ComeliteSerialBridgeApi, ComelitVedoApi
from aiocomelit import ComeliteSerialBridgeApi, ComelitVedoApi
from aiocomelit.api import ComelitHttpApi
from aiocomelit.const import (
ALARM_AREA,
ALARM_ZONE,
Expand Down Expand Up @@ -51,7 +52,7 @@ class ComelitBaseCoordinator(DataUpdateCoordinator[T]):

_hw_version: str
config_entry: ComelitConfigEntry
api: ComelitCommonApi
api: ComelitHttpApi

def __init__(
self, hass: HomeAssistant, entry: ComelitConfigEntry, device: str, host: str
Expand Down
Loading
Loading