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
8 changes: 2 additions & 6 deletions homeassistant/components/airly/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ rules:
appropriate-polling: done
brands: done
common-modules: done
config-flow-test-coverage:
status: todo
comment: The config flow test should either result in an entry being created or an abort.
config-flow:
status: todo
comment: Add data_description.
config-flow-test-coverage: done
config-flow: done
dependency-transparency: done
docs-actions:
status: exempt
Expand Down
6 changes: 5 additions & 1 deletion homeassistant/components/airly/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
"latitude": "[%key:common::config_flow::data::latitude%]",
"longitude": "[%key:common::config_flow::data::longitude%]"
},
"description": "To generate API key go to {developer_registration_url}"
"data_description": {
"api_key": "To generate API key go to {developer_registration_url}.",
"latitude": "The latitude of your location.",
"longitude": "The longitude of your location."
}
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/brother/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"iot_class": "local_polling",
"loggers": ["brother", "pyasn1", "pysmi", "pysnmp"],
"quality_scale": "platinum",
"requirements": ["brother==6.1.1"],
"requirements": ["brother==6.1.2"],
"zeroconf": [
{
"name": "brother*",
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/deako/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/escea/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/fjaraskupan/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
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 @@ -22,5 +22,5 @@
"integration_type": "system",
"preview_features": { "winter_mode": {} },
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20260826.1"]
"requirements": ["home-assistant-frontend==20260826.2"]
}
1 change: 0 additions & 1 deletion homeassistant/components/govee_light_local/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/gree/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/hisense_aehw4a1/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/homeassistant/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"authorize_url_timeout": "[%key:common::config_flow::abort::oauth2_authorize_url_timeout%]",
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]",
"missing_credentials": "[%key:common::config_flow::abort::oauth2_missing_credentials%]",
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]",
"oauth_error": "[%key:common::config_flow::abort::oauth2_error%]",
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/lg_infrared/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Platform.CLIMATE,
Platform.EVENT,
Platform.MEDIA_PLAYER,
Platform.SELECT,
Platform.SWITCH,
]

Expand Down
5 changes: 5 additions & 0 deletions homeassistant/components/lg_infrared/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@
}
}
},
"select": {
"energy_limit": {
"default": "mdi:lightning-bolt-outline"
}
},
"switch": {
"auto_clean": {
"default": "mdi:broom"
Expand Down
78 changes: 78 additions & 0 deletions homeassistant/components/lg_infrared/select.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""Select platform for LG IR integration."""

from typing import override

from infrared_protocols.codes.lg.ac import LGACCode

from homeassistant.components.infrared import InfraredEmitterConsumerEntity
from homeassistant.components.select import SelectEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity

from .const import CONF_DEVICE_TYPE, CONF_INFRARED_ENTITY_ID, LGDeviceType
from .entity import LgIrEntity

PARALLEL_UPDATES = 1

ENERGY_LIMIT_OFF = "off"

# The unit caps its power draw at the selected percentage; "off" removes the cap.
_ENERGY_LIMIT_TO_CODE: dict[str, LGACCode] = {
ENERGY_LIMIT_OFF: LGACCode.ENERGY_LIMIT_OFF,
"40": LGACCode.ENERGY_LIMIT_40,
"60": LGACCode.ENERGY_LIMIT_60,
"80": LGACCode.ENERGY_LIMIT_80,
}


async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the LG AC energy-limit select from a config entry."""
if entry.data[CONF_DEVICE_TYPE] != LGDeviceType.AC:
return

async_add_entities(
[LgAcEnergyLimitSelect(entry, entry.data[CONF_INFRARED_ENTITY_ID])]
)


class LgAcEnergyLimitSelect(
LgIrEntity, InfraredEmitterConsumerEntity, SelectEntity, RestoreEntity
):
"""Selects the LG AC energy-consumption cap."""

_attr_assumed_state = True
_attr_entity_category = EntityCategory.CONFIG
_attr_translation_key = "energy_limit"
_attr_options = list(_ENERGY_LIMIT_TO_CODE)

def __init__(self, entry: ConfigEntry, emitter_entity_id: str) -> None:
"""Initialize the energy-limit select."""
super().__init__(entry, unique_id_suffix="energy_limit", device_name="LG AC")
self._infrared_emitter_entity_id = emitter_entity_id
self._attr_current_option = ENERGY_LIMIT_OFF

@override
async def async_added_to_hass(self) -> None:
"""Restore the assumed state, as infrared cannot read it back from the AC."""
await super().async_added_to_hass()
last_state = await self.async_get_last_state()
if (
last_state is not None
and last_state.state not in (STATE_UNAVAILABLE, STATE_UNKNOWN)
and last_state.state in _ENERGY_LIMIT_TO_CODE
):
self._attr_current_option = last_state.state

@override
async def async_select_option(self, option: str) -> None:
"""Send the code for the chosen energy cap."""
await self._send_command(_ENERGY_LIMIT_TO_CODE[option].to_command())
self._attr_current_option = option
self.async_write_ha_state()
11 changes: 11 additions & 0 deletions homeassistant/components/lg_infrared/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,17 @@
}
}
},
"select": {
"energy_limit": {
"name": "Energy limit",
"state": {
"40": "40%",
"60": "60%",
"80": "80%",
"off": "[%key:common::state::off%]"
}
}
},
"switch": {
"auto_clean": {
"name": "Auto clean"
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/openhome/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ async def async_update(self) -> None:
self._attr_media_title = track_information.get("title")
if artists := track_information.get("artist"):
self._attr_media_artist = artists[0]
self._attr_media_content_id = track_information.get("uri")
self._attr_media_content_type = MediaType.MUSIC

if self._device.volume_enabled:
self._attr_supported_features |= (
Expand Down
30 changes: 20 additions & 10 deletions homeassistant/components/recorder/purge.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,25 @@ def purge_old_data(
instance, session, events_batch_size, purge_before
)

statistics_runs = _select_statistics_runs_to_purge(
statistics_runs, statistics_runs_has_more = _select_statistics_runs_to_purge(
session, purge_before, instance.max_bind_vars
)
short_term_statistics = _select_short_term_statistics_to_purge(
session, purge_before, instance.max_bind_vars
short_term_statistics, short_term_statistics_has_more = (
_select_short_term_statistics_to_purge(
session, purge_before, instance.max_bind_vars
)
)
if statistics_runs:
_purge_statistics_runs(session, statistics_runs)

if short_term_statistics:
_purge_short_term_statistics(session, short_term_statistics)

if has_more_to_purge or statistics_runs or short_term_statistics:
if (
has_more_to_purge
or statistics_runs_has_more
or short_term_statistics_has_more
):
# Return false, as we might not be done yet.
_LOGGER.debug("Purging hasn't fully completed yet")
return False
Expand Down Expand Up @@ -365,14 +371,16 @@ def _purge_unused_data_ids(

def _select_statistics_runs_to_purge(
session: Session, purge_before: datetime, max_bind_vars: int
) -> list[int]:
"""Return a list of statistic runs to purge.
) -> tuple[list[int], bool]:
"""Return a list of statistic runs to purge and if there may be more.

Takes care to keep the newest run.
"""
statistic_runs = session.execute(
find_statistics_runs_to_purge(purge_before, max_bind_vars)
).all()
# Only a full batch can have more rows to purge
has_more = len(statistic_runs) == max_bind_vars
statistic_runs_list = [run_id for (run_id,) in statistic_runs]
# Exclude the newest statistics run
if (
Expand All @@ -381,18 +389,20 @@ def _select_statistics_runs_to_purge(
statistic_runs_list.remove(last_run)

_LOGGER.debug("Selected %s statistic runs to remove", len(statistic_runs))
return statistic_runs_list
return statistic_runs_list, has_more


def _select_short_term_statistics_to_purge(
session: Session, purge_before: datetime, max_bind_vars: int
) -> list[int]:
"""Return a list of short term statistics to purge."""
) -> tuple[list[int], bool]:
"""Return a list of short term statistics to purge and if there may be more."""
statistics = session.execute(
find_short_term_statistics_to_purge(purge_before, max_bind_vars)
).all()
_LOGGER.debug("Selected %s short term statistics to remove", len(statistics))
return [statistic_id for (statistic_id,) in statistics]
# Only a full batch can have more rows to purge
has_more = len(statistics) == max_bind_vars
return [statistic_id for (statistic_id,) in statistics], has_more


def _select_legacy_detached_state_and_attributes_and_data_ids_to_purge(
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/refoss/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/sonos/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"not_ipv4_address": "No IPv4 address in SSDP discovery information",
"not_sonos_device": "Discovered device is not a Sonos device",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/wemo/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/zerproc/strings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"config": {
"abort": {
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"step": {
Expand Down
Loading
Loading