Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7aa4810
Clean up internal_get_tts_audio in TTS entity (#148946)
arturpragacz Jul 23, 2025
52abab8
Use translation_key for entities in Huum (#149256)
vincentwolsink Jul 23, 2025
aeeabfc
Fix typo "hazlenut" in `miele` (#149299)
NoRi2909 Jul 23, 2025
232b346
Avoid hardcoded max core climate timeout in SleepIQ (#149283)
dferg Jul 23, 2025
b37273e
Makes entites available in Husqvarna Automower when mower is in error…
Thomas55555 Jul 23, 2025
3dffd74
Migrate OpenAI to has entity name (#149301)
joostlek Jul 23, 2025
eb8ca53
Migrate Anthropic to has entity name (#149302)
joostlek Jul 23, 2025
edf6166
Fix spelling of "Domino's Pizza" in `dominos` (#149308)
NoRi2909 Jul 23, 2025
dcf29d1
Migrate Ollama to has entity name (#149303)
joostlek Jul 23, 2025
2a0a31b
Capitalize "HEPA" as an abbreviation in `matter` (#149306)
NoRi2909 Jul 23, 2025
4761161
Update Tesla OAuth Server in Tesla Fleet (#149280)
Bre77 Jul 23, 2025
6dc5c9b
Add fan off mode to the supported fan modes to fujitsu_fglair (#149277)
crevetor Jul 23, 2025
4d5c1b1
Consolidate REST sensor encoding tests using pytest parametrize (#149…
bdraco Jul 23, 2025
70e03cd
Implements coordinator pattern for Growatt component data fetching (#…
johanzander Jul 23, 2025
7c83fd0
Add twice_daily forecast to SMHI (#148882)
gjohansson-ST Jul 23, 2025
9a9f65d
Improve config flow tests in Onkyo (#149199)
arturpragacz Jul 23, 2025
4730c5b
Add logging to Tuya for devices that cannot be supported (#149192)
epenet Jul 23, 2025
6d38722
Fix one inconsistent spelling of "AppArmor" in `hassio` (#149310)
NoRi2909 Jul 23, 2025
1c8ae8a
Add switches for blue current integration. (#146210)
NickKoepr Jul 23, 2025
d9b2577
Remove sensors from Imeon Inverter (#148542)
Imeon-Energy Jul 23, 2025
22fa863
Discover ZWA-2 LED as a configuration entity in Z-Wave (#149298)
AlCalzone Jul 23, 2025
58ddf4e
Add note about re-interviewing Z-Wave battery powered devices (#149300)
Mariusthvdb Jul 23, 2025
fad5f7a
Move optimistic platform logic to AbstractTemplateEntity base class (…
Petro31 Jul 23, 2025
23b2936
Replace RuntimeError with custom ServiceValidationError in Tuya (#149…
epenet Jul 23, 2025
b6db103
Update supported languages for Google Generative AI TTS and STT (#149…
tronikos Jul 23, 2025
391b144
Update Z-Wave LED entity name for ZWA-2 (#149323)
AlCalzone Jul 23, 2025
ccd22ce
Fix brightness_step and brightness_step_pct via lifx.set_state (#149217)
Djelibeybi Jul 23, 2025
2abd203
Bump eheimdigital quality scale to platinum (#148263)
autinerd Jul 23, 2025
f679f33
Fix description of `current` field of `keba.set_current` action (#149…
NoRi2909 Jul 23, 2025
6180741
Fix typo "optimisic" in `mqtt` (#149291)
NoRi2909 Jul 23, 2025
15f7dad
Fix warning about failure to get action during setup phase (#148923)
mback2k Jul 23, 2025
8b7295c
Fix three spelling issues in `lg_thinq` (#149322)
NoRi2909 Jul 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
4 changes: 3 additions & 1 deletion homeassistant/components/anthropic/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,13 @@ def _create_token_stats(
class AnthropicBaseLLMEntity(Entity):
"""Anthropic base LLM entity."""

_attr_has_entity_name = True
_attr_name = None

def __init__(self, entry: AnthropicConfigEntry, subentry: ConfigSubentry) -> None:
"""Initialize the entity."""
self.entry = entry
self.subentry = subentry
self._attr_name = subentry.title
self._attr_unique_id = subentry.subentry_id
self._attr_device_info = dr.DeviceInfo(
identifiers={(DOMAIN, subentry.subentry_id)},
Expand Down
47 changes: 33 additions & 14 deletions homeassistant/components/blue_current/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,31 @@
)

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_NAME, CONF_API_TOKEN, Platform
from homeassistant.const import CONF_API_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.dispatcher import async_dispatcher_send

from .const import DOMAIN, EVSE_ID, LOGGER, MODEL_TYPE
from .const import (
CHARGEPOINT_SETTINGS,
CHARGEPOINT_STATUS,
DOMAIN,
EVSE_ID,
LOGGER,
PLUG_AND_CHARGE,
VALUE,
)

type BlueCurrentConfigEntry = ConfigEntry[Connector]

PLATFORMS = [Platform.BUTTON, Platform.SENSOR]
PLATFORMS = [Platform.BUTTON, Platform.SENSOR, Platform.SWITCH]
CHARGE_POINTS = "CHARGE_POINTS"
DATA = "data"
DELAY = 5

GRID = "GRID"
OBJECT = "object"
VALUE_TYPES = ["CH_STATUS"]
VALUE_TYPES = [CHARGEPOINT_STATUS, CHARGEPOINT_SETTINGS]


async def async_setup_entry(
Expand Down Expand Up @@ -94,7 +102,7 @@ async def on_data(self, message: dict) -> None:
elif object_name in VALUE_TYPES:
value_data: dict = message[DATA]
evse_id = value_data.pop(EVSE_ID)
self.update_charge_point(evse_id, value_data)
self.update_charge_point(evse_id, object_name, value_data)

# gets grid key / values
elif GRID in object_name:
Expand All @@ -106,26 +114,37 @@ async def handle_charge_point_data(self, charge_points_data: list) -> None:
"""Handle incoming chargepoint data."""
await asyncio.gather(
*(
self.handle_charge_point(
entry[EVSE_ID], entry[MODEL_TYPE], entry[ATTR_NAME]
)
self.handle_charge_point(entry[EVSE_ID], entry)
for entry in charge_points_data
),
self.client.get_grid_status(charge_points_data[0][EVSE_ID]),
)

async def handle_charge_point(self, evse_id: str, model: str, name: str) -> None:
async def handle_charge_point(
self, evse_id: str, charge_point: dict[str, Any]
) -> None:
"""Add the chargepoint and request their data."""
self.add_charge_point(evse_id, model, name)
self.add_charge_point(evse_id, charge_point)
await self.client.get_status(evse_id)

def add_charge_point(self, evse_id: str, model: str, name: str) -> None:
def add_charge_point(self, evse_id: str, charge_point: dict[str, Any]) -> None:
"""Add a charge point to charge_points."""
self.charge_points[evse_id] = {MODEL_TYPE: model, ATTR_NAME: name}
self.charge_points[evse_id] = charge_point

def update_charge_point(self, evse_id: str, data: dict) -> None:
def update_charge_point(self, evse_id: str, update_type: str, data: dict) -> None:
"""Update the charge point data."""
self.charge_points[evse_id].update(data)
charge_point = self.charge_points[evse_id]
if update_type == CHARGEPOINT_SETTINGS:
# Update the plug and charge object. The library parses this object to a bool instead of an object.
plug_and_charge = charge_point.get(PLUG_AND_CHARGE)
if plug_and_charge is not None:
plug_and_charge[VALUE] = data[PLUG_AND_CHARGE]

# Remove the plug and charge object from the data list before updating.
del data[PLUG_AND_CHARGE]

charge_point.update(data)

self.dispatch_charge_point_update_signal(evse_id)

def dispatch_charge_point_update_signal(self, evse_id: str) -> None:
Expand Down
11 changes: 11 additions & 0 deletions homeassistant/components/blue_current/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,14 @@

EVSE_ID = "evse_id"
MODEL_TYPE = "model_type"
PLUG_AND_CHARGE = "plug_and_charge"
VALUE = "value"
PERMISSION = "permission"
CHARGEPOINT_STATUS = "CH_STATUS"
CHARGEPOINT_SETTINGS = "CH_SETTINGS"
BLOCK = "block"
UNAVAILABLE = "unavailable"
AVAILABLE = "available"
LINKED_CHARGE_CARDS = "linked_charge_cards_only"
PUBLIC_CHARGING = "public_charging"
ACTIVITY = "activity"
11 changes: 11 additions & 0 deletions homeassistant/components/blue_current/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@
"stop_charge_session": {
"default": "mdi:stop"
}
},
"switch": {
"plug_and_charge": {
"default": "mdi:ev-plug-type2"
},
"linked_charge_cards": {
"default": "mdi:account-group"
},
"block": {
"default": "mdi:lock"
}
}
}
}
11 changes: 11 additions & 0 deletions homeassistant/components/blue_current/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@
"reset": {
"name": "Reset"
}
},
"switch": {
"plug_and_charge": {
"name": "Plug & Charge"
},
"linked_charge_cards_only": {
"name": "Linked charging cards only"
},
"block": {
"name": "Block charge point"
}
}
}
}
169 changes: 169 additions & 0 deletions homeassistant/components/blue_current/switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"""Support for Blue Current switches."""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from typing import Any

from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import PLUG_AND_CHARGE, BlueCurrentConfigEntry, Connector
from .const import (
AVAILABLE,
BLOCK,
LINKED_CHARGE_CARDS,
PUBLIC_CHARGING,
UNAVAILABLE,
VALUE,
)
from .entity import ChargepointEntity


@dataclass(kw_only=True, frozen=True)
class BlueCurrentSwitchEntityDescription(SwitchEntityDescription):
"""Describes a Blue Current switch entity."""

function: Callable[[Connector, str, bool], Any]

turn_on_off_fn: Callable[[str, Connector], tuple[bool, bool]]
"""Update the switch based on the latest data received from the websocket. The first returned boolean is _attr_is_on, the second one has_value."""


def update_on_value_and_activity(
key: str, evse_id: str, connector: Connector, reverse_is_on: bool = False
) -> tuple[bool, bool]:
"""Return the updated state of the switch based on received chargepoint data and activity."""

data_object = connector.charge_points[evse_id].get(key)
is_on = data_object[VALUE] if data_object is not None else None
activity = connector.charge_points[evse_id].get("activity")

if is_on is not None and activity == AVAILABLE:
return is_on if not reverse_is_on else not is_on, True
return False, False


def update_block_switch(evse_id: str, connector: Connector) -> tuple[bool, bool]:
"""Return the updated data for a block switch."""
activity = connector.charge_points[evse_id].get("activity")
return activity == UNAVAILABLE, activity in [AVAILABLE, UNAVAILABLE]


def update_charge_point(
key: str, evse_id: str, connector: Connector, new_switch_value: bool
) -> None:
"""Change charge point data when the state of the switch changes."""
data_objects = connector.charge_points[evse_id].get(key)
if data_objects is not None:
data_objects[VALUE] = new_switch_value


async def set_plug_and_charge(connector: Connector, evse_id: str, value: bool) -> None:
"""Toggle the plug and charge setting for a specific charging point."""
await connector.client.set_plug_and_charge(evse_id, value)
update_charge_point(PLUG_AND_CHARGE, evse_id, connector, value)


async def set_linked_charge_cards(
connector: Connector, evse_id: str, value: bool
) -> None:
"""Toggle the plug and charge setting for a specific charging point."""
await connector.client.set_linked_charge_cards_only(evse_id, value)
update_charge_point(PUBLIC_CHARGING, evse_id, connector, not value)


SWITCHES = (
BlueCurrentSwitchEntityDescription(
key=PLUG_AND_CHARGE,
translation_key=PLUG_AND_CHARGE,
function=set_plug_and_charge,
turn_on_off_fn=lambda evse_id, connector: (
update_on_value_and_activity(PLUG_AND_CHARGE, evse_id, connector)
),
),
BlueCurrentSwitchEntityDescription(
key=LINKED_CHARGE_CARDS,
translation_key=LINKED_CHARGE_CARDS,
function=set_linked_charge_cards,
turn_on_off_fn=lambda evse_id, connector: (
update_on_value_and_activity(
PUBLIC_CHARGING, evse_id, connector, reverse_is_on=True
)
),
),
BlueCurrentSwitchEntityDescription(
key=BLOCK,
translation_key=BLOCK,
function=lambda connector, evse_id, value: connector.client.block(
evse_id, value
),
turn_on_off_fn=update_block_switch,
),
)


async def async_setup_entry(
hass: HomeAssistant,
entry: BlueCurrentConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Blue Current switches."""
connector = entry.runtime_data

async_add_entities(
ChargePointSwitch(
connector,
evse_id,
switch,
)
for evse_id in connector.charge_points
for switch in SWITCHES
)


class ChargePointSwitch(ChargepointEntity, SwitchEntity):
"""Base charge point switch."""

has_value = True
entity_description: BlueCurrentSwitchEntityDescription

def __init__(
self,
connector: Connector,
evse_id: str,
switch: BlueCurrentSwitchEntityDescription,
) -> None:
"""Initialize the switch."""
super().__init__(connector, evse_id)

self.key = switch.key
self.entity_description = switch
self.evse_id = evse_id
self._attr_available = True
self._attr_unique_id = f"{switch.key}_{evse_id}"

async def call_function(self, value: bool) -> None:
"""Call the function to set setting."""
await self.entity_description.function(self.connector, self.evse_id, value)

async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
await self.call_function(True)
self._attr_is_on = True
self.async_write_ha_state()

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity on."""
await self.call_function(False)
self._attr_is_on = False
self.async_write_ha_state()

@callback
def update_from_latest_data(self) -> None:
"""Fetch new state data for the switch."""
new_state = self.entity_description.turn_on_off_fn(self.evse_id, self.connector)
self._attr_is_on = new_state[0]
self.has_value = new_state[1]
4 changes: 2 additions & 2 deletions homeassistant/components/dominos/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"services": {
"order": {
"name": "Order",
"description": "Places a set of orders with Dominos Pizza.",
"description": "Places a set of orders with Domino's Pizza.",
"fields": {
"order_entity_id": {
"name": "Order entity",
"description": "The ID (as specified in the configuration) of an order to place. If provided as an array, all of the identified orders will be placed."
"description": "The ID (as specified in the configuration) of an order to place. If provided as an array, all the identified orders will be placed."
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/eheimdigital/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["eheimdigital"],
"quality_scale": "bronze",
"quality_scale": "platinum",
"requirements": ["eheimdigital==1.3.0"],
"zeroconf": [
{ "type": "_http._tcp.local.", "name": "eheimdigital._http._tcp.local." }
Expand Down
16 changes: 9 additions & 7 deletions homeassistant/components/eheimdigital/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,24 @@ rules:
diagnostics: done
discovery-update-info: done
discovery: done
docs-data-update: todo
docs-examples: todo
docs-known-limitations: todo
docs-data-update: done
docs-examples: done
docs-known-limitations: done
docs-supported-devices: done
docs-supported-functions: done
docs-troubleshooting: todo
docs-use-cases: todo
docs-troubleshooting: done
docs-use-cases: done
dynamic-devices: done
entity-category: done
entity-device-class: done
entity-disabled-by-default: done
entity-translations: done
exception-translations: done
icon-translations: todo
icon-translations: done
reconfiguration-flow: done
repair-issues: todo
repair-issues:
status: exempt
comment: No repairs.
stale-devices: done

# Platinum
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/fujitsu_fglair/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
FAN_HIGH,
FAN_LOW,
FAN_MEDIUM,
FAN_OFF,
SWING_BOTH,
SWING_HORIZONTAL,
SWING_OFF,
Expand All @@ -31,6 +32,7 @@
from .entity import FGLairEntity

HA_TO_FUJI_FAN = {
FAN_OFF: FanSpeed.QUIET,
FAN_LOW: FanSpeed.LOW,
FAN_MEDIUM: FanSpeed.MEDIUM,
FAN_HIGH: FanSpeed.HIGH,
Expand Down
Loading
Loading