Skip to content

Commit 79ff85f

Browse files
frenckemontnemerymikey0000joostlekcdce8p
authored
2025.2.1 (#137688)
* Fix hassio test using wrong fixture (#137516) * Change Electric Kiwi authentication (#135231) Co-authored-by: Joostlek <[email protected]> * Update govee-ble to 0.42.1 (#137371) * Bump holidays to 0.66 (#137449) * Bump aiohttp-asyncmdnsresolver to 0.1.0 (#137492) changelog: aio-libs/aiohttp-asyncmdnsresolver@v0.0.3...v0.1.0 Switches to the new AsyncDualMDNSResolver class to which tries via mDNS and DNS for .local domains since we have so many different user DNS configurations to support fixes #137479 fixes #136922 * Bump aiohttp to 3.11.12 (#137494) changelog: aio-libs/aiohttp@v3.11.11...v3.11.12 * Bump govee-ble to 0.43.0 to fix compat with new H5179 firmware (#137508) changelog: Bluetooth-Devices/govee-ble@v0.42.1...v0.43.0 fixes #136969 * Bump habiticalib to v0.3.5 (#137510) * Fix Mill issue, where no sensors were shown (#137521) Fix mill issue #137477 Signed-off-by: Daniel Hjelseth Høyer <[email protected]> * Don't overwrite setup state in async_set_domains_to_be_loaded (#137547) * Use separate metadata files for onedrive (#137549) * Fix sending polls to Telegram threads (#137553) Fix sending poll to Telegram thread * Skip building wheels for electrickiwi-api (#137556) * Add excluded domains to broadcast intent (#137566) * Revert "Add `PaddleSwitchPico` (Pico Paddle Remote) device trigger to Lutron Caseta" (#137571) * Fix Overseerr webhook configuration JSON (#137572) Co-authored-by: Lars Jouon <[email protected]> * Do not rely on pyserial for port scanning with the CM5 + ZHA (#137585) Do not rely on pyserial for port scanning with the CM5 * Bump eheimdigital to 1.0.6 (#137587) * Bump pyfireservicerota to 0.0.46 (#137589) * Bump reolink-aio to 0.11.10 (#137591) * Allow to omit the payload attribute to MQTT publish action to allow an empty payload to be sent by default (#137595) Allow to omit the payload attribute to MQTT publish actionto allow an empty payload to be sent by default * Handle previously migrated HEOS device identifier (#137596) * Bump `aioshelly` to version `12.4.1` (#137598) * Bump aioshelly to 12.4.0 * Bump to 12.4.1 * Bump electrickiwi-api to 0.9.13 (#137601) * bump ek api version to fix deps * Revert "Skip building wheels for electrickiwi-api (#137556)" This reverts commit 5f6068e. --------- Co-authored-by: Marc Mueller <[email protected]> * Bump ZHA to 0.0.48 (#137610) * Bump Electrickiwi-api to 0.9.14 (#137614) * bump library to fix bug with post * rebuild * Update google-nest-sdm to 7.1.3 (#137625) * Update google-nest-sdm to 7.1.2 * Bump nest to 7.1.3 * Don't use the current temperature from Shelly BLU TRV as a state for External Temperature number entity (#137658) Introduce RpcBluTrvExtTempNumber for External Temperature entity * Fix LG webOS TV turn off when device is already off (#137675) * Bump version to 2025.2.1 --------- Signed-off-by: Daniel Hjelseth Høyer <[email protected]> Co-authored-by: Erik Montnemery <[email protected]> Co-authored-by: Michael Arthur <[email protected]> Co-authored-by: Joostlek <[email protected]> Co-authored-by: Marc Mueller <[email protected]> Co-authored-by: G Johansson <[email protected]> Co-authored-by: J. Nick Koston <[email protected]> Co-authored-by: Manu <[email protected]> Co-authored-by: Daniel Hjelseth Høyer <[email protected]> Co-authored-by: Josef Zweck <[email protected]> Co-authored-by: Jasper Wiegratz <[email protected]> Co-authored-by: Michael Hansen <[email protected]> Co-authored-by: Dennis Effing <[email protected]> Co-authored-by: Lars Jouon <[email protected]> Co-authored-by: puddly <[email protected]> Co-authored-by: Sid <[email protected]> Co-authored-by: Ron <[email protected]> Co-authored-by: starkillerOG <[email protected]> Co-authored-by: Jan Bouwhuis <[email protected]> Co-authored-by: Andrew Sayre <[email protected]> Co-authored-by: Maciej Bieniek <[email protected]> Co-authored-by: TheJulianJES <[email protected]> Co-authored-by: Allen Porter <[email protected]> Co-authored-by: Shay Levy <[email protected]>
2 parents 5c383f3 + 73ad4ca commit 79ff85f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+2209
-1374
lines changed

homeassistant/components/assist_satellite/intent.py

+34-14
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
"""Assist Satellite intents."""
22

3+
from typing import Final
4+
35
import voluptuous as vol
46

57
from homeassistant.core import HomeAssistant
68
from homeassistant.helpers import entity_registry as er, intent
79

810
from .const import DOMAIN, AssistSatelliteEntityFeature
911

12+
EXCLUDED_DOMAINS: Final[set[str]] = {"voip"}
13+
1014

1115
async def async_setup_intents(hass: HomeAssistant) -> None:
1216
"""Set up the intents."""
@@ -30,19 +34,36 @@ async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse
3034
ent_reg = er.async_get(hass)
3135

3236
# Find all assist satellite entities that are not the one invoking the intent
33-
entities = {
34-
entity: entry
35-
for entity in hass.states.async_entity_ids(DOMAIN)
36-
if (entry := ent_reg.async_get(entity))
37-
and entry.supported_features & AssistSatelliteEntityFeature.ANNOUNCE
38-
}
39-
40-
if intent_obj.device_id:
41-
entities = {
42-
entity: entry
43-
for entity, entry in entities.items()
44-
if entry.device_id != intent_obj.device_id
45-
}
37+
entities: dict[str, er.RegistryEntry] = {}
38+
for entity in hass.states.async_entity_ids(DOMAIN):
39+
entry = ent_reg.async_get(entity)
40+
if (
41+
(entry is None)
42+
or (
43+
# Supports announce
44+
not (
45+
entry.supported_features & AssistSatelliteEntityFeature.ANNOUNCE
46+
)
47+
)
48+
# Not the invoking device
49+
or (intent_obj.device_id and (entry.device_id == intent_obj.device_id))
50+
):
51+
# Skip satellite
52+
continue
53+
54+
# Check domain of config entry against excluded domains
55+
if (
56+
entry.config_entry_id
57+
and (
58+
config_entry := hass.config_entries.async_get_entry(
59+
entry.config_entry_id
60+
)
61+
)
62+
and (config_entry.domain in EXCLUDED_DOMAINS)
63+
):
64+
continue
65+
66+
entities[entity] = entry
4667

4768
await hass.services.async_call(
4869
DOMAIN,
@@ -54,7 +75,6 @@ async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse
5475
)
5576

5677
response = intent_obj.create_response()
57-
response.async_set_speech("Done")
5878
response.response_type = intent.IntentResponseType.ACTION_DONE
5979
response.async_set_results(
6080
success_results=[

homeassistant/components/eheimdigital/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"iot_class": "local_polling",
99
"loggers": ["eheimdigital"],
1010
"quality_scale": "bronze",
11-
"requirements": ["eheimdigital==1.0.5"],
11+
"requirements": ["eheimdigital==1.0.6"],
1212
"zeroconf": [
1313
{ "type": "_http._tcp.local.", "name": "eheimdigital._http._tcp.local." }
1414
]

homeassistant/components/electric_kiwi/__init__.py

+61-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44

55
import aiohttp
66
from electrickiwi_api import ElectricKiwiApi
7-
from electrickiwi_api.exceptions import ApiException
7+
from electrickiwi_api.exceptions import ApiException, AuthException
88

99
from homeassistant.const import Platform
1010
from homeassistant.core import HomeAssistant
1111
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
12-
from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow
12+
from homeassistant.helpers import (
13+
aiohttp_client,
14+
config_entry_oauth2_flow,
15+
entity_registry as er,
16+
)
1317

1418
from . import api
1519
from .coordinator import (
@@ -44,7 +48,9 @@ async def async_setup_entry(
4448
raise ConfigEntryNotReady from err
4549

4650
ek_api = ElectricKiwiApi(
47-
api.AsyncConfigEntryAuth(aiohttp_client.async_get_clientsession(hass), session)
51+
api.ConfigEntryElectricKiwiAuth(
52+
aiohttp_client.async_get_clientsession(hass), session
53+
)
4854
)
4955
hop_coordinator = ElectricKiwiHOPDataCoordinator(hass, entry, ek_api)
5056
account_coordinator = ElectricKiwiAccountDataCoordinator(hass, entry, ek_api)
@@ -53,6 +59,8 @@ async def async_setup_entry(
5359
await ek_api.set_active_session()
5460
await hop_coordinator.async_config_entry_first_refresh()
5561
await account_coordinator.async_config_entry_first_refresh()
62+
except AuthException as err:
63+
raise ConfigEntryAuthFailed from err
5664
except ApiException as err:
5765
raise ConfigEntryNotReady from err
5866

@@ -70,3 +78,53 @@ async def async_unload_entry(
7078
) -> bool:
7179
"""Unload a config entry."""
7280
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
81+
82+
83+
async def async_migrate_entry(
84+
hass: HomeAssistant, config_entry: ElectricKiwiConfigEntry
85+
) -> bool:
86+
"""Migrate old entry."""
87+
if config_entry.version == 1 and config_entry.minor_version == 1:
88+
implementation = (
89+
await config_entry_oauth2_flow.async_get_config_entry_implementation(
90+
hass, config_entry
91+
)
92+
)
93+
94+
session = config_entry_oauth2_flow.OAuth2Session(
95+
hass, config_entry, implementation
96+
)
97+
98+
ek_api = ElectricKiwiApi(
99+
api.ConfigEntryElectricKiwiAuth(
100+
aiohttp_client.async_get_clientsession(hass), session
101+
)
102+
)
103+
try:
104+
await ek_api.set_active_session()
105+
connection_details = await ek_api.get_connection_details()
106+
except AuthException:
107+
config_entry.async_start_reauth(hass)
108+
return False
109+
except ApiException:
110+
return False
111+
unique_id = str(ek_api.customer_number)
112+
identifier = ek_api.electricity.identifier
113+
hass.config_entries.async_update_entry(
114+
config_entry, unique_id=unique_id, minor_version=2
115+
)
116+
entity_registry = er.async_get(hass)
117+
entity_entries = er.async_entries_for_config_entry(
118+
entity_registry, config_entry_id=config_entry.entry_id
119+
)
120+
121+
for entity in entity_entries:
122+
assert entity.config_entry_id
123+
entity_registry.async_update_entity(
124+
entity.entity_id,
125+
new_unique_id=entity.unique_id.replace(
126+
f"{unique_id}_{connection_details.id}", f"{unique_id}_{identifier}"
127+
),
128+
)
129+
130+
return True

homeassistant/components/electric_kiwi/api.py

+21-5
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22

33
from __future__ import annotations
44

5-
from typing import cast
6-
75
from aiohttp import ClientSession
86
from electrickiwi_api import AbstractAuth
97

10-
from homeassistant.helpers import config_entry_oauth2_flow
8+
from homeassistant.core import HomeAssistant
9+
from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow
1110

1211
from .const import API_BASE_URL
1312

1413

15-
class AsyncConfigEntryAuth(AbstractAuth):
14+
class ConfigEntryElectricKiwiAuth(AbstractAuth):
1615
"""Provide Electric Kiwi authentication tied to an OAuth2 based config entry."""
1716

1817
def __init__(
@@ -29,4 +28,21 @@ async def async_get_access_token(self) -> str:
2928
"""Return a valid access token."""
3029
await self._oauth_session.async_ensure_token_valid()
3130

32-
return cast(str, self._oauth_session.token["access_token"])
31+
return str(self._oauth_session.token["access_token"])
32+
33+
34+
class ConfigFlowElectricKiwiAuth(AbstractAuth):
35+
"""Provide Electric Kiwi authentication tied to an OAuth2 based config flow."""
36+
37+
def __init__(
38+
self,
39+
hass: HomeAssistant,
40+
token: str,
41+
) -> None:
42+
"""Initialize ConfigFlowFitbitApi."""
43+
super().__init__(aiohttp_client.async_get_clientsession(hass), API_BASE_URL)
44+
self._token = token
45+
46+
async def async_get_access_token(self) -> str:
47+
"""Return the token for the Electric Kiwi API."""
48+
return self._token

homeassistant/components/electric_kiwi/config_flow.py

+31-6
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
import logging
77
from typing import Any
88

9-
from homeassistant.config_entries import ConfigFlowResult
9+
from electrickiwi_api import ElectricKiwiApi
10+
from electrickiwi_api.exceptions import ApiException
11+
12+
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult
13+
from homeassistant.const import CONF_NAME
1014
from homeassistant.helpers import config_entry_oauth2_flow
1115

16+
from . import api
1217
from .const import DOMAIN, SCOPE_VALUES
1318

1419

@@ -17,6 +22,8 @@ class ElectricKiwiOauth2FlowHandler(
1722
):
1823
"""Config flow to handle Electric Kiwi OAuth2 authentication."""
1924

25+
VERSION = 1
26+
MINOR_VERSION = 2
2027
DOMAIN = DOMAIN
2128

2229
@property
@@ -40,12 +47,30 @@ async def async_step_reauth_confirm(
4047
) -> ConfigFlowResult:
4148
"""Dialog that informs the user that reauth is required."""
4249
if user_input is None:
43-
return self.async_show_form(step_id="reauth_confirm")
50+
return self.async_show_form(
51+
step_id="reauth_confirm",
52+
description_placeholders={CONF_NAME: self._get_reauth_entry().title},
53+
)
4454
return await self.async_step_user()
4555

4656
async def async_oauth_create_entry(self, data: dict) -> ConfigFlowResult:
4757
"""Create an entry for Electric Kiwi."""
48-
existing_entry = await self.async_set_unique_id(DOMAIN)
49-
if existing_entry:
50-
return self.async_update_reload_and_abort(existing_entry, data=data)
51-
return await super().async_oauth_create_entry(data)
58+
ek_api = ElectricKiwiApi(
59+
api.ConfigFlowElectricKiwiAuth(self.hass, data["token"]["access_token"])
60+
)
61+
62+
try:
63+
session = await ek_api.get_active_session()
64+
except ApiException:
65+
return self.async_abort(reason="connection_error")
66+
67+
unique_id = str(session.data.customer_number)
68+
await self.async_set_unique_id(unique_id)
69+
if self.source == SOURCE_REAUTH:
70+
self._abort_if_unique_id_mismatch(reason="wrong_account")
71+
return self.async_update_reload_and_abort(
72+
self._get_reauth_entry(), data=data
73+
)
74+
75+
self._abort_if_unique_id_configured()
76+
return self.async_create_entry(title=unique_id, data=data)

homeassistant/components/electric_kiwi/const.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
OAUTH2_TOKEN = "https://welcome.electrickiwi.co.nz/oauth/token"
99
API_BASE_URL = "https://api.electrickiwi.co.nz"
1010

11-
SCOPE_VALUES = "read_connection_detail read_billing_frequency read_account_running_balance read_consumption_summary read_consumption_averages read_hop_intervals_config read_hop_connection save_hop_connection read_session"
11+
SCOPE_VALUES = "read_customer_details read_connection_detail read_connection read_billing_address get_bill_address read_billing_frequency read_billing_details read_billing_bills read_billing_bill read_billing_bill_id read_billing_bill_file read_account_running_balance read_customer_account_summary read_consumption_summary download_consumption_file read_consumption_averages get_consumption_averages read_hop_intervals_config read_hop_intervals read_hop_connection read_hop_specific_connection save_hop_connection save_hop_specific_connection read_outage_contact get_outage_contact_info_for_icp read_session read_session_data_login"

homeassistant/components/electric_kiwi/coordinator.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from electrickiwi_api import ElectricKiwiApi
1212
from electrickiwi_api.exceptions import ApiException, AuthException
13-
from electrickiwi_api.model import AccountBalance, Hop, HopIntervals
13+
from electrickiwi_api.model import AccountSummary, Hop, HopIntervals
1414

1515
from homeassistant.config_entries import ConfigEntry
1616
from homeassistant.core import HomeAssistant
@@ -34,7 +34,7 @@ class ElectricKiwiRuntimeData:
3434
type ElectricKiwiConfigEntry = ConfigEntry[ElectricKiwiRuntimeData]
3535

3636

37-
class ElectricKiwiAccountDataCoordinator(DataUpdateCoordinator[AccountBalance]):
37+
class ElectricKiwiAccountDataCoordinator(DataUpdateCoordinator[AccountSummary]):
3838
"""ElectricKiwi Account Data object."""
3939

4040
def __init__(
@@ -51,13 +51,13 @@ def __init__(
5151
name="Electric Kiwi Account Data",
5252
update_interval=ACCOUNT_SCAN_INTERVAL,
5353
)
54-
self._ek_api = ek_api
54+
self.ek_api = ek_api
5555

56-
async def _async_update_data(self) -> AccountBalance:
56+
async def _async_update_data(self) -> AccountSummary:
5757
"""Fetch data from Account balance API endpoint."""
5858
try:
5959
async with asyncio.timeout(60):
60-
return await self._ek_api.get_account_balance()
60+
return await self.ek_api.get_account_summary()
6161
except AuthException as auth_err:
6262
raise ConfigEntryAuthFailed from auth_err
6363
except ApiException as api_err:
@@ -85,7 +85,7 @@ def __init__(
8585
# Polling interval. Will only be polled if there are subscribers.
8686
update_interval=HOP_SCAN_INTERVAL,
8787
)
88-
self._ek_api = ek_api
88+
self.ek_api = ek_api
8989
self.hop_intervals: HopIntervals | None = None
9090

9191
def get_hop_options(self) -> dict[str, int]:
@@ -100,7 +100,7 @@ def get_hop_options(self) -> dict[str, int]:
100100
async def async_update_hop(self, hop_interval: int) -> Hop:
101101
"""Update selected hop and data."""
102102
try:
103-
self.async_set_updated_data(await self._ek_api.post_hop(hop_interval))
103+
self.async_set_updated_data(await self.ek_api.post_hop(hop_interval))
104104
except AuthException as auth_err:
105105
raise ConfigEntryAuthFailed from auth_err
106106
except ApiException as api_err:
@@ -118,7 +118,7 @@ async def _async_update_data(self) -> Hop:
118118
try:
119119
async with asyncio.timeout(60):
120120
if self.hop_intervals is None:
121-
hop_intervals: HopIntervals = await self._ek_api.get_hop_intervals()
121+
hop_intervals: HopIntervals = await self.ek_api.get_hop_intervals()
122122
hop_intervals.intervals = OrderedDict(
123123
filter(
124124
lambda pair: pair[1].active == 1,
@@ -127,7 +127,7 @@ async def _async_update_data(self) -> Hop:
127127
)
128128

129129
self.hop_intervals = hop_intervals
130-
return await self._ek_api.get_hop()
130+
return await self.ek_api.get_hop()
131131
except AuthException as auth_err:
132132
raise ConfigEntryAuthFailed from auth_err
133133
except ApiException as api_err:

homeassistant/components/electric_kiwi/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
"documentation": "https://www.home-assistant.io/integrations/electric_kiwi",
88
"integration_type": "hub",
99
"iot_class": "cloud_polling",
10-
"requirements": ["electrickiwi-api==0.8.5"]
10+
"requirements": ["electrickiwi-api==0.9.14"]
1111
}

homeassistant/components/electric_kiwi/select.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ def __init__(
5353
"""Initialise the HOP selection entity."""
5454
super().__init__(coordinator)
5555
self._attr_unique_id = (
56-
f"{coordinator._ek_api.customer_number}" # noqa: SLF001
57-
f"_{coordinator._ek_api.connection_id}_{description.key}" # noqa: SLF001
56+
f"{coordinator.ek_api.customer_number}"
57+
f"_{coordinator.ek_api.electricity.identifier}_{description.key}"
5858
)
5959
self.entity_description = description
6060
self.values_dict = coordinator.get_hop_options()

0 commit comments

Comments
 (0)