Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b13dd4e
Migrate lg_netcast to use runtime_data (#147338)
epenet Jun 23, 2025
f64533e
Migrate led_ble to use runtime_data (#147337)
epenet Jun 23, 2025
741e893
Migrate leaone to use runtime_data (#147336)
epenet Jun 23, 2025
a2785a8
Migrate ld2410_ble to use runtime_data (#147335)
epenet Jun 23, 2025
82c1751
Matter dishwasher alarm (#146842)
lboue Jun 23, 2025
4d2f0f2
Migrate laundrify to use runtime_data (#147331)
epenet Jun 23, 2025
436fcb7
Fixed YoLink incorrect valve status (#147021)
matrixd2 Jun 23, 2025
0ab23cc
Migrate landisgyr_heat_meter to use runtime_data (#147329)
epenet Jun 23, 2025
1119716
Clean superfluous cloud deps from pyproject (#147223)
arturpragacz Jun 23, 2025
3b4eb7c
Migrate lametric to use runtime_data (#147328)
epenet Jun 23, 2025
bf733fd
Remove config flow unique_id migration from devolo Home Control (#147…
Shutgun Jun 23, 2025
2bfb09c
Improve test of WS command get_services cache handling (#147134)
emontnemery Jun 23, 2025
d06da8c
Migrate lcn to use runtime_data (#147333)
epenet Jun 23, 2025
2a97b12
Bump IMGW-PIB backend library to version 1.1.0 (#147341)
bieniu Jun 23, 2025
b252039
Lametric add configuration url (#147118)
rrooggiieerr Jun 23, 2025
756b858
Wallbox fix too many requests by API (#147197)
hesselonline Jun 23, 2025
2e15583
Fix reload for Shelly devices with no script support (#147344)
chemelli74 Jun 23, 2025
87ecf55
Add unique ID support to Trend integration YAML configuration (#147346)
frenck Jun 23, 2025
7ec2e0c
Move lyric coordinator to separate module (#147357)
epenet Jun 23, 2025
d38c880
Bump demetriek to 1.3.0 (#147350)
joostlek Jun 23, 2025
9ae3129
Matter battery storage (#147235)
lboue Jun 23, 2025
0c08b4f
Add Matter protocol to Switchbot (#147356)
joostlek Jun 23, 2025
b48ebea
Tilt Pi integration (#139726)
michaelheyman Jun 23, 2025
c1e32aa
Add trigger template alarm control panels (#145461)
Petro31 Jun 23, 2025
8e6edf5
Add trigger based locks to template integration (#145528)
Petro31 Jun 23, 2025
fa71c40
Bump thinqconnect to 1.0.7 (#147073)
LG-ThinQ-Integration Jun 23, 2025
3798e99
Update bosch_alarm to platinum quality scale (#145027)
sanjay900 Jun 23, 2025
f8267b1
Add Altruist integration to Core (#146158)
LoSk-p Jun 23, 2025
a11e274
Address AI Task late comments (#147313)
balloob Jun 23, 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
1 change: 1 addition & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ homeassistant.components.alert.*
homeassistant.components.alexa.*
homeassistant.components.alexa_devices.*
homeassistant.components.alpha_vantage.*
homeassistant.components.altruist.*
homeassistant.components.amazon_polly.*
homeassistant.components.amberelectric.*
homeassistant.components.ambient_network.*
Expand Down
4 changes: 4 additions & 0 deletions CODEOWNERS

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

3 changes: 2 additions & 1 deletion homeassistant/brands/switchbot.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"domain": "switchbot",
"name": "SwitchBot",
"integrations": ["switchbot", "switchbot_cloud"]
"integrations": ["switchbot", "switchbot_cloud"],
"iot_standards": ["matter"]
}
5 changes: 5 additions & 0 deletions homeassistant/brands/tilt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"domain": "tilt",
"name": "Tilt",
"integrations": ["tilt_ble", "tilt_pi"]
}
23 changes: 16 additions & 7 deletions homeassistant/components/ai_task/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import voluptuous as vol

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import (
HassJobType,
HomeAssistant,
Expand All @@ -17,9 +18,17 @@
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.typing import UNDEFINED, ConfigType, UndefinedType

from .const import DATA_COMPONENT, DATA_PREFERENCES, DOMAIN, AITaskEntityFeature
from .const import (
ATTR_INSTRUCTIONS,
ATTR_TASK_NAME,
DATA_COMPONENT,
DATA_PREFERENCES,
DOMAIN,
SERVICE_GENERATE_TEXT,
AITaskEntityFeature,
)
from .entity import AITaskEntity
from .http import async_setup as async_setup_conversation_http
from .http import async_setup as async_setup_http
from .task import GenTextTask, GenTextTaskResult, async_generate_text

__all__ = [
Expand All @@ -45,16 +54,16 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
hass.data[DATA_COMPONENT] = entity_component
hass.data[DATA_PREFERENCES] = AITaskPreferences(hass)
await hass.data[DATA_PREFERENCES].async_load()
async_setup_conversation_http(hass)
async_setup_http(hass)
hass.services.async_register(
DOMAIN,
"generate_text",
SERVICE_GENERATE_TEXT,
async_service_generate_text,
schema=vol.Schema(
{
vol.Required("task_name"): cv.string,
vol.Optional("entity_id"): cv.entity_id,
vol.Required("instructions"): cv.string,
vol.Required(ATTR_TASK_NAME): cv.string,
vol.Optional(ATTR_ENTITY_ID): cv.entity_id,
vol.Required(ATTR_INSTRUCTIONS): cv.string,
}
),
supports_response=SupportsResponse.ONLY,
Expand Down
7 changes: 6 additions & 1 deletion homeassistant/components/ai_task/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from enum import IntFlag
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Final

from homeassistant.util.hass_dict import HassKey

Expand All @@ -17,6 +17,11 @@
DATA_COMPONENT: HassKey[EntityComponent[AITaskEntity]] = HassKey(DOMAIN)
DATA_PREFERENCES: HassKey[AITaskPreferences] = HassKey(f"{DOMAIN}_preferences")

SERVICE_GENERATE_TEXT = "generate_text"

ATTR_INSTRUCTIONS: Final = "instructions"
ATTR_TASK_NAME: Final = "task_name"

DEFAULT_SYSTEM_PROMPT = (
"You are a Home Assistant expert and help users with their tasks."
)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/ai_task/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ generate_text:
selector:
text:
instructions:
example: "Generate a funny notification that garage door was left open"
example: "Generate a funny notification that the garage door was left open"
required: true
selector:
text:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/ai_task/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Use AI to run a task that generates text.",
"fields": {
"task_name": {
"name": "Task Name",
"name": "Task name",
"description": "Name of the task."
},
"instructions": {
Expand Down
9 changes: 6 additions & 3 deletions homeassistant/components/ai_task/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dataclasses import dataclass

from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError

from .const import DATA_COMPONENT, DATA_PREFERENCES, AITaskEntityFeature

Expand All @@ -21,14 +22,16 @@ async def async_generate_text(
entity_id = hass.data[DATA_PREFERENCES].gen_text_entity_id

if entity_id is None:
raise ValueError("No entity_id provided and no preferred entity set")
raise HomeAssistantError("No entity_id provided and no preferred entity set")

entity = hass.data[DATA_COMPONENT].get_entity(entity_id)
if entity is None:
raise ValueError(f"AI Task entity {entity_id} not found")
raise HomeAssistantError(f"AI Task entity {entity_id} not found")

if AITaskEntityFeature.GENERATE_TEXT not in entity.supported_features:
raise ValueError(f"AI Task entity {entity_id} does not support generating text")
raise HomeAssistantError(
f"AI Task entity {entity_id} does not support generating text"
)

return await entity.internal_async_generate_text(
GenTextTask(
Expand Down
27 changes: 27 additions & 0 deletions homeassistant/components/altruist/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""The Altruist integration."""

from __future__ import annotations

from homeassistant.const import Platform
from homeassistant.core import HomeAssistant

from .coordinator import AltruistConfigEntry, AltruistDataUpdateCoordinator

PLATFORMS = [Platform.SENSOR]


async def async_setup_entry(hass: HomeAssistant, entry: AltruistConfigEntry) -> bool:
"""Set up Altruist from a config entry."""

coordinator = AltruistDataUpdateCoordinator(hass, entry)

await coordinator.async_config_entry_first_refresh()

entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True


async def async_unload_entry(hass: HomeAssistant, entry: AltruistConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
107 changes: 107 additions & 0 deletions homeassistant/components/altruist/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""Config flow for the Altruist integration."""

import logging
from typing import Any

from altruistclient import AltruistClient, AltruistDeviceModel, AltruistError
import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_HOST, DOMAIN

_LOGGER = logging.getLogger(__name__)


class AltruistConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Altruist."""

device: AltruistDeviceModel

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""
errors: dict[str, str] = {}
ip_address = ""
if user_input is not None:
ip_address = user_input[CONF_HOST]
try:
client = await AltruistClient.from_ip_address(
async_get_clientsession(self.hass), ip_address
)
except AltruistError:
errors["base"] = "no_device_found"
else:
self.device = client.device
await self.async_set_unique_id(
client.device_id, raise_on_progress=False
)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=self.device.id,
data={
CONF_HOST: ip_address,
},
)

data_schema = self.add_suggested_values_to_schema(
vol.Schema({vol.Required(CONF_HOST): str}),
{CONF_HOST: ip_address},
)

return self.async_show_form(
step_id="user",
data_schema=data_schema,
errors=errors,
description_placeholders={
"ip_address": ip_address,
},
)

async def async_step_zeroconf(
self, discovery_info: ZeroconfServiceInfo
) -> ConfigFlowResult:
"""Handle zeroconf discovery."""
_LOGGER.debug("Zeroconf discovery: %s", discovery_info)
try:
client = await AltruistClient.from_ip_address(
async_get_clientsession(self.hass), str(discovery_info.ip_address)
)
except AltruistError:
return self.async_abort(reason="no_device_found")

self.device = client.device
_LOGGER.debug("Zeroconf device: %s", client.device)
await self.async_set_unique_id(client.device_id)
self._abort_if_unique_id_configured()
self.context.update(
{
"title_placeholders": {
"name": self.device.id,
}
}
)
return await self.async_step_discovery_confirm()

async def async_step_discovery_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Confirm discovery."""
if user_input is not None:
return self.async_create_entry(
title=self.device.id,
data={
CONF_HOST: self.device.ip_address,
},
)

self._set_confirm_only()
return self.async_show_form(
step_id="discovery_confirm",
description_placeholders={
"model": self.device.id,
},
)
5 changes: 5 additions & 0 deletions homeassistant/components/altruist/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Constants for the Altruist integration."""

DOMAIN = "altruist"

CONF_HOST = "host"
64 changes: 64 additions & 0 deletions homeassistant/components/altruist/coordinator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Coordinator module for Altruist integration in Home Assistant.

This module defines the AltruistDataUpdateCoordinator class, which manages
data updates for Altruist sensors using the AltruistClient.
"""

from datetime import timedelta
import logging

from altruistclient import AltruistClient, AltruistError

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_HOST

_LOGGER = logging.getLogger(__name__)

UPDATE_INTERVAL = timedelta(seconds=15)

type AltruistConfigEntry = ConfigEntry[AltruistDataUpdateCoordinator]


class AltruistDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str]]):
"""Coordinates data updates for Altruist sensors."""

client: AltruistClient

def __init__(
self,
hass: HomeAssistant,
config_entry: AltruistConfigEntry,
) -> None:
"""Initialize the data update coordinator for Altruist sensors."""
device_id = config_entry.unique_id
super().__init__(
hass,
logger=_LOGGER,
config_entry=config_entry,
name=f"Altruist {device_id}",
update_interval=UPDATE_INTERVAL,
)
self._ip_address = config_entry.data[CONF_HOST]

async def _async_setup(self) -> None:
try:
self.client = await AltruistClient.from_ip_address(
async_get_clientsession(self.hass), self._ip_address
)
await self.client.fetch_data()
except AltruistError as e:
raise ConfigEntryNotReady("Error in Altruist setup") from e

async def _async_update_data(self) -> dict[str, str]:
try:
fetched_data = await self.client.fetch_data()
except AltruistError as ex:
raise UpdateFailed(
f"The Altruist {self.client.device_id} is unavailable: {ex}"
) from ex
return {item["value_type"]: item["value"] for item in fetched_data}
15 changes: 15 additions & 0 deletions homeassistant/components/altruist/icons.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"entity": {
"sensor": {
"pm_10": {
"default": "mdi:thought-bubble"
},
"pm_25": {
"default": "mdi:thought-bubble-outline"
},
"radiation": {
"default": "mdi:radioactive"
}
}
}
}
12 changes: 12 additions & 0 deletions homeassistant/components/altruist/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"domain": "altruist",
"name": "Altruist",
"codeowners": ["@airalab", "@LoSk-p"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/altruist",
"integration_type": "device",
"iot_class": "local_polling",
"quality_scale": "bronze",
"requirements": ["altruistclient==0.1.1"],
"zeroconf": ["_altruist._tcp.local."]
}
Loading
Loading