forked from home-assistant/core
Compare commits
171 Commits
2024.10.0b
...
2024.10.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a301d51fb2 | ||
|
|
515771553f | ||
|
|
e204812d2b | ||
|
|
ca703cb858 | ||
|
|
b018d4a97d | ||
|
|
146768ff8a | ||
|
|
ea7473ed67 | ||
|
|
0e8393766f | ||
|
|
7d2536c503 | ||
|
|
f9cbf1b30c | ||
|
|
d66d87d271 | ||
|
|
5a8fa6cf38 | ||
|
|
76340035db | ||
|
|
0a26e68d0c | ||
|
|
14127b910f | ||
|
|
ba4d081021 | ||
|
|
18d65d513e | ||
|
|
6952d2420f | ||
|
|
9176994947 | ||
|
|
d389b55f40 | ||
|
|
0ccff9fc54 | ||
|
|
a8836ca7b6 | ||
|
|
f5d04a970f | ||
|
|
7aec98dafd | ||
|
|
773564d4f5 | ||
|
|
3e2edc1a2d | ||
|
|
9cfc9b9baf | ||
|
|
92b67ead83 | ||
|
|
ee9525cc00 | ||
|
|
571bfaf5d7 | ||
|
|
a3475607b2 | ||
|
|
f0a653d010 | ||
|
|
eecdf66013 | ||
|
|
f99db05a4a | ||
|
|
635731421f | ||
|
|
44743df7d6 | ||
|
|
33617694cc | ||
|
|
ed445d20b9 | ||
|
|
66c2fe091b | ||
|
|
8c80f47a35 | ||
|
|
e37025c1c7 | ||
|
|
0aabde081b | ||
|
|
a1c9d53474 | ||
|
|
094996ad0c | ||
|
|
ce359a7689 | ||
|
|
ee599160b3 | ||
|
|
dd076f7a13 | ||
|
|
3021d38b6f | ||
|
|
bfcabeaf26 | ||
|
|
c31e0336dc | ||
|
|
a1e42cac7a | ||
|
|
14a3e5b771 | ||
|
|
5901c543da | ||
|
|
456b80e6ae | ||
|
|
e5644ae011 | ||
|
|
41c794c733 | ||
|
|
a481448d46 | ||
|
|
2bd7ce618a | ||
|
|
da1ac4f1e9 | ||
|
|
f0cb638106 | ||
|
|
dad2396d01 | ||
|
|
91e4d8b663 | ||
|
|
e35496133e | ||
|
|
3be808ae1e | ||
|
|
c5772916a1 | ||
|
|
8cd63b80b1 | ||
|
|
c087654386 | ||
|
|
60b9e65c78 | ||
|
|
79b304a5d2 | ||
|
|
bb9fd126e5 | ||
|
|
bff2d5c26c | ||
|
|
46d9ac8380 | ||
|
|
5da3ca4bb1 | ||
|
|
2c99fdc092 | ||
|
|
31a075fb13 | ||
|
|
1d132d7a1e | ||
|
|
3b6f88cfa7 | ||
|
|
b927763d8d | ||
|
|
d00e1cb6a5 | ||
|
|
adf7474edb | ||
|
|
041d663cb8 | ||
|
|
37f611a8d3 | ||
|
|
be99329efa | ||
|
|
327cb70bb8 | ||
|
|
be2b5a4c3a | ||
|
|
d1eda9dd73 | ||
|
|
b902cb5a13 | ||
|
|
1184ee4a59 | ||
|
|
2cf898afcc | ||
|
|
df53e19eda | ||
|
|
7f79b26341 | ||
|
|
2182bc3af2 | ||
|
|
2cbf53ad7b | ||
|
|
c52607b465 | ||
|
|
087566072d | ||
|
|
6b814afd39 | ||
|
|
ea8aa6b07d | ||
|
|
1b0f731e30 | ||
|
|
1ebde4a880 | ||
|
|
e53bd477b4 | ||
|
|
3f9287c36b | ||
|
|
b2b940fc32 | ||
|
|
7d9e170512 | ||
|
|
6ab92abe80 | ||
|
|
5db4a73d8e | ||
|
|
acb0aeaa9a | ||
|
|
dc7c909316 | ||
|
|
a052e15319 | ||
|
|
a50b299a82 | ||
|
|
a6808a8fda | ||
|
|
7ac944c537 | ||
|
|
7d3dd2dd6b | ||
|
|
48538ef5d5 | ||
|
|
5365439fd4 | ||
|
|
9c28a4e8a0 | ||
|
|
565203047c | ||
|
|
b9795a2ae7 | ||
|
|
4e4f8ee3a4 | ||
|
|
b8fd921c81 | ||
|
|
fcf91954ff | ||
|
|
49708196ac | ||
|
|
8c8a2eef21 | ||
|
|
749a5b37c9 | ||
|
|
60079a14e7 | ||
|
|
df6edd09c0 | ||
|
|
88ff94dd69 | ||
|
|
067b81a60b | ||
|
|
03553b8bb9 | ||
|
|
bce7552d4d | ||
|
|
53a2777831 | ||
|
|
507492947a | ||
|
|
41b3eb9f79 | ||
|
|
f2c746122e | ||
|
|
e25a54aef4 | ||
|
|
5c42e45048 | ||
|
|
c8b92bc858 | ||
|
|
9d059fcfaa | ||
|
|
ce5f193219 | ||
|
|
92023ecbe6 | ||
|
|
1e0164a96a | ||
|
|
6f5eac3143 | ||
|
|
60dfccb747 | ||
|
|
e9dc09755e | ||
|
|
1ce2b18aaf | ||
|
|
abd351e326 | ||
|
|
d3e6069095 | ||
|
|
f0c3900842 | ||
|
|
25247de6a6 | ||
|
|
f3a72dda7b | ||
|
|
b6af6ddea2 | ||
|
|
a2cd17ef0a | ||
|
|
b8ed449944 | ||
|
|
dc79299301 | ||
|
|
fa295b93a7 | ||
|
|
725c361e9c | ||
|
|
a8f25b1b93 | ||
|
|
3ee85b3356 | ||
|
|
22c85bf5f7 | ||
|
|
0a18838fb0 | ||
|
|
62629a0b34 | ||
|
|
b42848fd7a | ||
|
|
9070806172 | ||
|
|
4e11797d72 | ||
|
|
8f47b63762 | ||
|
|
daa13235e6 | ||
|
|
084c2d976e | ||
|
|
75363b609b | ||
|
|
8d09982f3b | ||
|
|
aa5e8eaf19 | ||
|
|
fc97eb8151 | ||
|
|
a68d7c9b9d |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -37,7 +37,7 @@ on:
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
CACHE_VERSION: 10
|
||||
CACHE_VERSION: 11
|
||||
UV_CACHE_VERSION: 1
|
||||
MYPY_CACHE_VERSION: 9
|
||||
HA_SHORT_VERSION: "2024.10"
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/airgradient",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["airgradient==0.9.0"],
|
||||
"requirements": ["airgradient==0.9.1"],
|
||||
"zeroconf": ["_airgradient._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ HVAC_MODE_LIB_TO_HASS: Final[dict[OperationMode, HVACMode]] = {
|
||||
OperationMode.HEATING: HVACMode.HEAT,
|
||||
OperationMode.FAN: HVACMode.FAN_ONLY,
|
||||
OperationMode.DRY: HVACMode.DRY,
|
||||
OperationMode.AUX_HEATING: HVACMode.HEAT,
|
||||
OperationMode.AUTO: HVACMode.HEAT_COOL,
|
||||
}
|
||||
HVAC_MODE_HASS_TO_LIB: Final[dict[HVACMode, OperationMode]] = {
|
||||
@@ -157,9 +158,10 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity):
|
||||
self._attr_temperature_unit = TEMP_UNIT_LIB_TO_HASS[
|
||||
self.get_airzone_value(AZD_TEMP_UNIT)
|
||||
]
|
||||
self._attr_hvac_modes = [
|
||||
_attr_hvac_modes = [
|
||||
HVAC_MODE_LIB_TO_HASS[mode] for mode in self.get_airzone_value(AZD_MODES)
|
||||
]
|
||||
self._attr_hvac_modes = list(dict.fromkeys(_attr_hvac_modes))
|
||||
if (
|
||||
self.get_airzone_value(AZD_SPEED) is not None
|
||||
and self.get_airzone_value(AZD_SPEEDS) is not None
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/airzone",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairzone"],
|
||||
"requirements": ["aioairzone==0.9.3"]
|
||||
"requirements": ["aioairzone==0.9.5"]
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/airzone_cloud",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["aioairzone_cloud"],
|
||||
"requirements": ["aioairzone-cloud==0.6.5"]
|
||||
"requirements": ["aioairzone-cloud==0.6.6"]
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "Successfully connected to AlarmDecoder."
|
||||
@@ -37,7 +38,7 @@
|
||||
"title": "Configure AlarmDecoder",
|
||||
"description": "What would you like to edit?",
|
||||
"data": {
|
||||
"edit_select": "Edit"
|
||||
"edit_selection": "Edit"
|
||||
}
|
||||
},
|
||||
"arm_settings": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"site": {
|
||||
"data": {
|
||||
"site_nmi": "Site NMI",
|
||||
"site_id": "Site NMI",
|
||||
"site_name": "Site Name"
|
||||
},
|
||||
"description": "Select the NMI of the site you would like to add"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"error": {
|
||||
"no_integration_selected": "You must select at least one integration to track"
|
||||
"no_integrations_selected": "You must select at least one integration to track"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
@@ -37,7 +37,7 @@
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
},
|
||||
"error": {
|
||||
"no_integration_selected": "[%key:component::analytics_insights::config::error::no_integration_selected%]"
|
||||
"no_integrations_selected": "[%key:component::analytics_insights::config::error::no_integrations_selected%]"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
|
||||
BIN
homeassistant/components/assist_satellite/connection_test.mp3
Executable file → Normal file
BIN
homeassistant/components/assist_satellite/connection_test.mp3
Executable file → Normal file
Binary file not shown.
@@ -16,6 +16,10 @@
|
||||
"hostname": "connect",
|
||||
"macaddress": "2C9FFB*"
|
||||
},
|
||||
{
|
||||
"hostname": "connect",
|
||||
"macaddress": "789C85*"
|
||||
},
|
||||
{
|
||||
"hostname": "august*",
|
||||
"macaddress": "E076D0*"
|
||||
|
||||
@@ -4,6 +4,7 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import CONF_THRESHOLD, DEFAULT_THRESHOLD
|
||||
from .coordinator import AuroraDataUpdateCoordinator
|
||||
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||
@@ -21,9 +22,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: AuroraConfigEntry) -> bo
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
entry.async_on_unload(entry.add_update_listener(update_listener))
|
||||
return True
|
||||
|
||||
|
||||
async def update_listener(hass: HomeAssistant, entry: AuroraConfigEntry) -> None:
|
||||
"""Handle options update."""
|
||||
entry.runtime_data.threshold = int(
|
||||
entry.options.get(CONF_THRESHOLD, DEFAULT_THRESHOLD)
|
||||
)
|
||||
# refresh the state of the visibility alert binary sensor
|
||||
await entry.runtime_data.async_request_refresh()
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: AuroraConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
@@ -38,8 +38,8 @@ class AuroraDataUpdateCoordinator(DataUpdateCoordinator[int]):
|
||||
)
|
||||
|
||||
self.api = AuroraForecast(async_get_clientsession(hass))
|
||||
self.latitude = int(self.config_entry.data[CONF_LATITUDE])
|
||||
self.longitude = int(self.config_entry.data[CONF_LONGITUDE])
|
||||
self.latitude = round(self.config_entry.data[CONF_LATITUDE])
|
||||
self.longitude = round(self.config_entry.data[CONF_LONGITUDE])
|
||||
self.threshold = int(
|
||||
self.config_entry.options.get(CONF_THRESHOLD, DEFAULT_THRESHOLD)
|
||||
)
|
||||
|
||||
@@ -14,14 +14,15 @@
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"threshold": "Threshold (%)"
|
||||
"forecast_threshold": "Threshold (%)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"options": {
|
||||
"init": {
|
||||
"title": "Options for the Azure Event Hub.",
|
||||
"data": {
|
||||
"send_interval": "Interval between sending batches to the hub."
|
||||
|
||||
@@ -13,4 +13,5 @@ EXCLUDE_FROM_BACKUP = [
|
||||
"*.log",
|
||||
"backups/*.tar",
|
||||
"OZW_Log.txt",
|
||||
"tts/*",
|
||||
]
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
"description": "Set up your BleBox to integrate with Home Assistant.",
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::ip%]",
|
||||
"port": "[%key:common::config_flow::data::port%]"
|
||||
"password": "[%key:common::config_flow::data::password%]",
|
||||
"port": "[%key:common::config_flow::data::port%]",
|
||||
"username": "[%key:common::config_flow::data::username%]"
|
||||
},
|
||||
"title": "Set up your BleBox device"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/bluesound",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["pyblu==1.0.2"],
|
||||
"requirements": ["pyblu==1.0.4"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"type": "_musc._tcp.local."
|
||||
|
||||
@@ -493,6 +493,8 @@ class BluesoundPlayer(MediaPlayerEntity):
|
||||
return None
|
||||
|
||||
position = self._status.seconds
|
||||
if position is None:
|
||||
return None
|
||||
|
||||
if mediastate == MediaPlayerState.PLAYING:
|
||||
position += (dt_util.utcnow() - self._last_status_update).total_seconds()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@@ -61,6 +62,12 @@ class BryantConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, entry_data: Mapping[str, Any]
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle integration reconfiguration."""
|
||||
return await self.async_step_reconfigure_confirm()
|
||||
|
||||
async def async_step_reconfigure_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle integration reconfiguration."""
|
||||
@@ -83,5 +90,7 @@ class BryantConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
errors["base"] = "cannot_connect"
|
||||
return self.async_show_form(
|
||||
step_id="reconfigure", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
||||
step_id="reconfigure_confirm",
|
||||
data_schema=STEP_USER_DATA_SCHEMA,
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"reconfigure_confirm": {
|
||||
"data": {
|
||||
"filename": "[%key:component::bryant_evolution::config::step::user::data::filename%]"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"filename": "Serial port filename"
|
||||
|
||||
@@ -34,7 +34,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
username=entry.data[CONF_USERNAME],
|
||||
password=entry.data[CONF_PASSWORD],
|
||||
ssl_verify_cert=entry.data[CONF_VERIFY_SSL],
|
||||
timeout=10,
|
||||
timeout=30,
|
||||
)
|
||||
try:
|
||||
await hass.async_add_executor_job(client.principal)
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_service_calendar_list_events": {
|
||||
"title": "Detected use of deprecated action `calendar.list_events`",
|
||||
"title": "Detected use of deprecated action calendar.list_events",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["aiostreammagic"],
|
||||
"requirements": ["aiostreammagic==2.3.1"],
|
||||
"requirements": ["aiostreammagic==2.5.0"],
|
||||
"zeroconf": ["_stream-magic._tcp.local.", "_smoip._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/cast",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["casttube", "pychromecast"],
|
||||
"requirements": ["PyChromecast==14.0.1"],
|
||||
"requirements": ["PyChromecast==14.0.3"],
|
||||
"zeroconf": ["_googlecast._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_gender": {
|
||||
"title": "The `{deprecated_option}` text-to-speech option is deprecated",
|
||||
"title": "The {deprecated_option} text-to-speech option is deprecated",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/conversation",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["hassil==1.7.4", "home-assistant-intents==2024.9.23"]
|
||||
"requirements": ["hassil==1.7.4", "home-assistant-intents==2024.10.2"]
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ class DaikinClimate(DaikinEntity, ClimateEntity):
|
||||
|
||||
if values:
|
||||
await self.device.set(values)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
@@ -261,6 +262,7 @@ class DaikinClimate(DaikinEntity, ClimateEntity):
|
||||
await self.device.set_advanced_mode(
|
||||
HA_PRESET_TO_DAIKIN[PRESET_ECO], ATTR_STATE_OFF
|
||||
)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
@property
|
||||
def preset_modes(self) -> list[str]:
|
||||
@@ -275,9 +277,11 @@ class DaikinClimate(DaikinEntity, ClimateEntity):
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn device on."""
|
||||
await self.device.set({})
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn device off."""
|
||||
await self.device.set(
|
||||
{HA_ATTR_TO_DAIKIN[ATTR_HVAC_MODE]: HA_STATE_TO_DAIKIN[HVACMode.OFF]}
|
||||
)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
@@ -63,10 +63,12 @@ class DaikinZoneSwitch(DaikinEntity, SwitchEntity):
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the zone on."""
|
||||
await self.device.set_zone(self._zone_id, "zone_onoff", "1")
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the zone off."""
|
||||
await self.device.set_zone(self._zone_id, "zone_onoff", "0")
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
|
||||
class DaikinStreamerSwitch(DaikinEntity, SwitchEntity):
|
||||
@@ -88,10 +90,12 @@ class DaikinStreamerSwitch(DaikinEntity, SwitchEntity):
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the zone on."""
|
||||
await self.device.set_streamer("on")
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the zone off."""
|
||||
await self.device.set_streamer("off")
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
|
||||
class DaikinToggleSwitch(DaikinEntity, SwitchEntity):
|
||||
@@ -112,7 +116,9 @@ class DaikinToggleSwitch(DaikinEntity, SwitchEntity):
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the zone on."""
|
||||
await self.device.set({})
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the zone off."""
|
||||
await self.device.set({DAIKIN_ATTR_MODE: "off"})
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/doorbird",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["doorbirdpy"],
|
||||
"requirements": ["DoorBirdPy==3.0.2"],
|
||||
"requirements": ["DoorBirdPy==3.0.4"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"type": "_axis-video._tcp.local.",
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pyduotecno", "pyduotecno-node", "pyduotecno-unit"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["pyDuotecno==2024.9.0"]
|
||||
"requirements": ["pyDuotecno==2024.10.0"]
|
||||
}
|
||||
|
||||
@@ -5,18 +5,21 @@
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]",
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
"password": "[%key:common::config_flow::data::password%]",
|
||||
"port": "[%key:common::config_flow::data::port%]"
|
||||
},
|
||||
"data_description": {
|
||||
"host": "The hostname or IP address of your Duotecno device."
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/econet",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["paho_mqtt", "pyeconet"],
|
||||
"requirements": ["pyeconet==0.1.22"]
|
||||
"requirements": ["pyeconet==0.1.23"]
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ class EnphaseConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
VERSION = 1
|
||||
|
||||
_reconnect_entry: ConfigEntry
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize an envoy flow."""
|
||||
self.ip_address: str | None = None
|
||||
@@ -233,17 +235,22 @@ class EnphaseConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, entry_data: Mapping[str, Any]
|
||||
) -> ConfigFlowResult:
|
||||
"""Add reconfigure step to allow to manually reconfigure a config entry."""
|
||||
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
|
||||
assert entry
|
||||
self._reconnect_entry = entry
|
||||
return await self.async_step_reconfigure_confirm()
|
||||
|
||||
async def async_step_reconfigure_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Add reconfigure step to allow to manually reconfigure a config entry."""
|
||||
errors: dict[str, str] = {}
|
||||
description_placeholders: dict[str, str] = {}
|
||||
|
||||
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
|
||||
assert entry
|
||||
|
||||
suggested_values: dict[str, Any] | MappingProxyType[str, Any] = (
|
||||
user_input or entry.data
|
||||
user_input or self._reconnect_entry.data
|
||||
)
|
||||
|
||||
host: Any = suggested_values.get(CONF_HOST)
|
||||
@@ -284,7 +291,7 @@ class EnphaseConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
error="reconfigure_successful",
|
||||
)
|
||||
if not self.unique_id:
|
||||
await self.async_set_unique_id(entry.unique_id)
|
||||
await self.async_set_unique_id(self._reconnect_entry.unique_id)
|
||||
|
||||
self.context["title_placeholders"] = {
|
||||
CONF_SERIAL: self.unique_id,
|
||||
@@ -292,7 +299,7 @@ class EnphaseConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
}
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="reconfigure",
|
||||
step_id="reconfigure_confirm",
|
||||
data_schema=self.add_suggested_values_to_schema(
|
||||
self._async_generate_schema(), suggested_values
|
||||
),
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"host": "The hostname or IP address of your Enphase Envoy gateway."
|
||||
}
|
||||
},
|
||||
"reconfigure": {
|
||||
"reconfigure_confirm": {
|
||||
"description": "[%key:component::enphase_envoy::config::step::user::description%]",
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]",
|
||||
|
||||
@@ -133,7 +133,7 @@ class EsphomeAssistSatellite(
|
||||
|
||||
# Empty config. Updated when added to HA.
|
||||
self._satellite_config = assist_satellite.AssistSatelliteConfiguration(
|
||||
available_wake_words=[], active_wake_words=[], max_active_wake_words=0
|
||||
available_wake_words=[], active_wake_words=[], max_active_wake_words=1
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -179,7 +179,13 @@ class EsphomeAssistSatellite(
|
||||
|
||||
async def _update_satellite_config(self) -> None:
|
||||
"""Get the latest satellite configuration from the device."""
|
||||
config = await self.cli.get_voice_assistant_configuration(_CONFIG_TIMEOUT_SEC)
|
||||
try:
|
||||
config = await self.cli.get_voice_assistant_configuration(
|
||||
_CONFIG_TIMEOUT_SEC
|
||||
)
|
||||
except TimeoutError:
|
||||
# Placeholder config will be used
|
||||
return
|
||||
|
||||
# Update available/active wake words
|
||||
self._satellite_config.available_wake_words = [
|
||||
@@ -206,7 +212,7 @@ class EsphomeAssistSatellite(
|
||||
)
|
||||
if feature_flags & VoiceAssistantFeature.API_AUDIO:
|
||||
# TCP audio
|
||||
self.entry_data.disconnect_callbacks.add(
|
||||
self.async_on_remove(
|
||||
self.cli.subscribe_voice_assistant(
|
||||
handle_start=self.handle_pipeline_start,
|
||||
handle_stop=self.handle_pipeline_stop,
|
||||
@@ -216,7 +222,7 @@ class EsphomeAssistSatellite(
|
||||
)
|
||||
else:
|
||||
# UDP audio
|
||||
self.entry_data.disconnect_callbacks.add(
|
||||
self.async_on_remove(
|
||||
self.cli.subscribe_voice_assistant(
|
||||
handle_start=self.handle_pipeline_start,
|
||||
handle_stop=self.handle_pipeline_stop,
|
||||
@@ -229,7 +235,7 @@ class EsphomeAssistSatellite(
|
||||
assert (self.registry_entry is not None) and (
|
||||
self.registry_entry.device_id is not None
|
||||
)
|
||||
self.entry_data.disconnect_callbacks.add(
|
||||
self.async_on_remove(
|
||||
async_register_timer_handler(
|
||||
self.hass, self.registry_entry.device_id, self.handle_timer_event
|
||||
)
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]"
|
||||
},
|
||||
"error": {
|
||||
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20240927.0"]
|
||||
"requirements": ["home-assistant-frontend==20241002.3"]
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ DOMAIN = "fujitsu_fglair"
|
||||
|
||||
CONF_REGION = "region"
|
||||
CONF_EUROPE = "is_europe"
|
||||
REGION_EU = "EU"
|
||||
REGION_EU = "eu"
|
||||
REGION_DEFAULT = "default"
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/fujitsu_fglair",
|
||||
"iot_class": "cloud_polling",
|
||||
"requirements": ["ayla-iot-unofficial==1.4.1"]
|
||||
"requirements": ["ayla-iot-unofficial==1.4.2"]
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["fyta_cli==0.6.6"]
|
||||
"requirements": ["fyta_cli==0.6.7"]
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/calendar.google",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["googleapiclient"],
|
||||
"requirements": ["gcal-sync==6.1.4", "oauth2client==4.1.3", "ical==8.1.1"]
|
||||
"requirements": ["gcal-sync==6.1.6", "oauth2client==4.1.3", "ical==8.2.0"]
|
||||
}
|
||||
|
||||
@@ -172,10 +172,12 @@ class BaseGoogleCloudProvider:
|
||||
_LOGGER.error("Error: %s when validating options: %s", err, options)
|
||||
return None, None
|
||||
|
||||
encoding = texttospeech.AudioEncoding(options[CONF_ENCODING])
|
||||
gender: texttospeech.SsmlVoiceGender | None = texttospeech.SsmlVoiceGender(
|
||||
encoding: texttospeech.AudioEncoding = texttospeech.AudioEncoding[
|
||||
options[CONF_ENCODING]
|
||||
] # type: ignore[misc]
|
||||
gender: texttospeech.SsmlVoiceGender | None = texttospeech.SsmlVoiceGender[
|
||||
options[CONF_GENDER]
|
||||
)
|
||||
] # type: ignore[misc]
|
||||
voice = options[CONF_VOICE]
|
||||
if voice:
|
||||
gender = None
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"wrong_account": "Wrong account: Please authenticate with the right account.",
|
||||
"oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]",
|
||||
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
|
||||
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]"
|
||||
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "[%key:common::config_flow::create_entry::authenticated%]"
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"wrong_account": "Wrong account: Please authenticate with the right account.",
|
||||
"oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]",
|
||||
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
|
||||
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]"
|
||||
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "[%key:common::config_flow::create_entry::authenticated%]"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import voluptuous as vol
|
||||
@@ -207,6 +208,8 @@ class GoogleTravelTimeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
VERSION = 1
|
||||
|
||||
_context_entry: ConfigEntry
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(
|
||||
@@ -235,28 +238,33 @@ class GoogleTravelTimeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
self, entry_data: Mapping[str, Any]
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle reconfiguration."""
|
||||
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
|
||||
if TYPE_CHECKING:
|
||||
assert entry
|
||||
self._context_entry = entry
|
||||
return await self.async_step_reconfigure_confirm()
|
||||
|
||||
async def async_step_reconfigure_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle reconfiguration."""
|
||||
errors: dict[str, str] | None = None
|
||||
user_input = user_input or {}
|
||||
if user_input:
|
||||
if user_input is not None:
|
||||
errors = await validate_input(self.hass, user_input)
|
||||
if not errors:
|
||||
return self.async_update_reload_and_abort(
|
||||
entry,
|
||||
self._context_entry,
|
||||
data=user_input,
|
||||
reason="reconfigure_successful",
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="reconfigure",
|
||||
step_id="reconfigure_confirm",
|
||||
data_schema=self.add_suggested_values_to_schema(
|
||||
RECONFIGURE_SCHEMA, entry.data.copy()
|
||||
RECONFIGURE_SCHEMA, self._context_entry.data.copy()
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"destination": "Destination"
|
||||
}
|
||||
},
|
||||
"reconfigure": {
|
||||
"reconfigure_confirm": {
|
||||
"description": "[%key:component::google_travel_time::config::step::user::description%]",
|
||||
"data": {
|
||||
"api_key": "[%key:common::config_flow::data::api_key%]",
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_task_entity": {
|
||||
"title": "The Habitica `{task_name}` sensor is deprecated",
|
||||
"title": "The Habitica {task_name} sensor is deprecated",
|
||||
"description": "The Habitica entity `{entity}` is deprecated and will be removed in a future release.\nPlease update your automations and scripts to replace the sensor entity with the newly added todo entity.\nWhen you are done migrating you can disable `{entity}`."
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,6 +14,9 @@ from homeassistant.util import dt as dt_util
|
||||
def next_due_date(task: dict[str, Any], last_cron: str) -> datetime.date | None:
|
||||
"""Calculate due date for dailies and yesterdailies."""
|
||||
|
||||
if task["everyX"] == 0 or not task.get("nextDue"): # grey dailies never become due
|
||||
return None
|
||||
|
||||
today = to_date(last_cron)
|
||||
startdate = to_date(task["startDate"])
|
||||
if TYPE_CHECKING:
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
},
|
||||
"cmd": {
|
||||
"name": "Command",
|
||||
"description": "Command itself. Could be decimal number or string with hexadeximal notation: \"0x10\"."
|
||||
"description": "Command itself. Could be decimal number or string with hexadecimal notation: \"0x10\"."
|
||||
},
|
||||
"dst": {
|
||||
"name": "Destination",
|
||||
"description": "Destination for command. Could be decimal number or string with hexadeximal notation: \"0x10\"."
|
||||
"description": "Destination for command. Could be decimal number or string with hexadecimal notation: \"0x10\"."
|
||||
},
|
||||
"raw": {
|
||||
"name": "Raw",
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"src": {
|
||||
"name": "Source",
|
||||
"description": "Source of command. Could be decimal number or string with hexadeximal notation: \"0x10\"."
|
||||
"description": "Source of command. Could be decimal number or string with hexadecimal notation: \"0x10\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -127,5 +127,5 @@ class HiveSensorEntity(HiveEntity, SensorEntity):
|
||||
await self.hive.session.updateData(self.device)
|
||||
self.device = await self.hive.sensor.getSensor(self.device)
|
||||
self._attr_native_value = self.entity_description.fn(
|
||||
self.device["status"]["state"]
|
||||
self.device.get("status", {}).get("state")
|
||||
)
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/holiday",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["holidays==0.57", "babel==2.15.0"]
|
||||
"requirements": ["holidays==0.58", "babel==2.15.0"]
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"description": "The currency {currency} is no longer in use, please reconfigure the currency configuration."
|
||||
},
|
||||
"legacy_templates_false": {
|
||||
"title": "`legacy_templates` config key is being removed",
|
||||
"title": "legacy_templates config key is being removed",
|
||||
"description": "Nothing will change with your templates.\n\nRemove the `legacy_templates` key from the `homeassistant` configuration in your configuration.yaml file and restart Home Assistant to fix this issue."
|
||||
},
|
||||
"legacy_templates_true": {
|
||||
@@ -43,7 +43,7 @@
|
||||
"description": "It's not possible to configure {platform} {domain} by adding `{platform_key}` to the {domain} configuration. Please check the documentation for more information on how to set up this integration.\n\nTo resolve this:\n1. Remove `{platform_key}` occurences from the `{domain}:` configuration in your YAML configuration file.\n2. Restart Home Assistant.\n\nExample that should be removed:\n{yaml_example}"
|
||||
},
|
||||
"storage_corruption": {
|
||||
"title": "Storage corruption detected for `{storage_key}`",
|
||||
"title": "Storage corruption detected for {storage_key}",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Any
|
||||
@@ -557,6 +558,8 @@ OPTIONS_FLOW = {
|
||||
class HomeworksConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Config flow for Lutron Homeworks."""
|
||||
|
||||
_context_entry: ConfigEntry
|
||||
|
||||
async def _validate_edit_controller(
|
||||
self, user_input: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
@@ -580,18 +583,24 @@ class HomeworksConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
return user_input
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
self, entry_data: Mapping[str, Any]
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle a reconfigure flow."""
|
||||
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
|
||||
assert entry
|
||||
self._context_entry = entry
|
||||
return await self.async_step_reconfigure_confirm()
|
||||
|
||||
async def async_step_reconfigure_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle a reconfigure flow."""
|
||||
errors = {}
|
||||
suggested_values = {
|
||||
CONF_HOST: entry.options[CONF_HOST],
|
||||
CONF_PORT: entry.options[CONF_PORT],
|
||||
CONF_USERNAME: entry.data.get(CONF_USERNAME),
|
||||
CONF_PASSWORD: entry.data.get(CONF_PASSWORD),
|
||||
CONF_HOST: self._context_entry.options[CONF_HOST],
|
||||
CONF_PORT: self._context_entry.options[CONF_PORT],
|
||||
CONF_USERNAME: self._context_entry.data.get(CONF_USERNAME),
|
||||
CONF_PASSWORD: self._context_entry.data.get(CONF_PASSWORD),
|
||||
}
|
||||
|
||||
if user_input:
|
||||
@@ -608,16 +617,16 @@ class HomeworksConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
else:
|
||||
password = user_input.pop(CONF_PASSWORD, None)
|
||||
username = user_input.pop(CONF_USERNAME, None)
|
||||
new_data = entry.data | {
|
||||
new_data = self._context_entry.data | {
|
||||
CONF_PASSWORD: password,
|
||||
CONF_USERNAME: username,
|
||||
}
|
||||
new_options = entry.options | {
|
||||
new_options = self._context_entry.options | {
|
||||
CONF_HOST: user_input[CONF_HOST],
|
||||
CONF_PORT: user_input[CONF_PORT],
|
||||
}
|
||||
return self.async_update_reload_and_abort(
|
||||
entry,
|
||||
self._context_entry,
|
||||
data=new_data,
|
||||
options=new_options,
|
||||
reason="reconfigure_successful",
|
||||
@@ -625,7 +634,7 @@ class HomeworksConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="reconfigure",
|
||||
step_id="reconfigure_confirm",
|
||||
data_schema=self.add_suggested_values_to_schema(
|
||||
DATA_SCHEMA_EDIT_CONTROLLER, suggested_values
|
||||
),
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"name": "[%key:component::homeworks::config::step::user::data_description::name%]"
|
||||
}
|
||||
},
|
||||
"reconfigure": {
|
||||
"reconfigure_confirm": {
|
||||
"data": {
|
||||
"host": "[%key:common::config_flow::data::host%]",
|
||||
"port": "[%key:common::config_flow::data::port%]",
|
||||
@@ -45,8 +45,8 @@
|
||||
},
|
||||
"data_description": {
|
||||
"name": "A unique name identifying the Lutron Homeworks controller",
|
||||
"password": "[%key:component::homeworks::config::step::reconfigure::data_description::password%]",
|
||||
"username": "[%key:component::homeworks::config::step::reconfigure::data_description::username%]"
|
||||
"password": "[%key:component::homeworks::config::step::reconfigure_confirm::data_description::password%]",
|
||||
"username": "[%key:component::homeworks::config::step::reconfigure_confirm::data_description::username%]"
|
||||
},
|
||||
"description": "Add a Lutron Homeworks controller"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
HAP_SUFFIX = "._hap._tcp.local."
|
||||
POWERVIEW_G2_SUFFIX = "._powerview._tcp.local."
|
||||
POWERVIEW_G3_SUFFIX = "._powerview-g3._tcp.local."
|
||||
POWERVIEW_G3_SUFFIX = "._PowerView-G3._tcp.local."
|
||||
|
||||
|
||||
async def validate_input(hass: HomeAssistant, hub_address: str) -> dict[str, str]:
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aiopvapi"],
|
||||
"requirements": ["aiopvapi==3.1.1"],
|
||||
"zeroconf": ["_powerview._tcp.local.", "_powerview-g3._tcp.local."]
|
||||
"zeroconf": ["_powerview._tcp.local.", "_PowerView-G3._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -125,7 +125,9 @@ class AutomowerBaseEntity(CoordinatorEntity[AutomowerDataUpdateCoordinator]):
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, mower_id)},
|
||||
manufacturer="Husqvarna",
|
||||
model=self.mower_attributes.system.model,
|
||||
model=self.mower_attributes.system.model.removeprefix(
|
||||
"HUSQVARNA "
|
||||
).removeprefix("Husqvarna "),
|
||||
name=self.mower_attributes.system.name,
|
||||
serial_number=self.mower_attributes.system.serial_number,
|
||||
suggested_area="Garden",
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/husqvarna_automower",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["aioautomower"],
|
||||
"requirements": ["aioautomower==2024.9.3"]
|
||||
"requirements": ["aioautomower==2024.10.0"]
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ DEFAULT_WATERING_TIME = timedelta(minutes=15)
|
||||
|
||||
MANUFACTURER = "Hydrawise"
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
SCAN_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
SIGNAL_UPDATE_HYDRAWISE = "hydrawise_update"
|
||||
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/imgw_pib",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["imgw_pib==1.0.5"]
|
||||
"requirements": ["imgw_pib==1.0.6"]
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["deepmerge", "pyipp"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["pyipp==0.16.0"],
|
||||
"requirements": ["pyipp==0.17.0"],
|
||||
"zeroconf": ["_ipps._tcp.local.", "_ipp._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pyipp import Marker, Printer
|
||||
@@ -19,7 +19,6 @@ from homeassistant.const import ATTR_LOCATION, PERCENTAGE, EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from . import IPPConfigEntry
|
||||
from .const import (
|
||||
@@ -80,7 +79,7 @@ PRINTER_SENSORS: tuple[IPPSensorEntityDescription, ...] = (
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda printer: (utcnow() - timedelta(seconds=printer.info.uptime)),
|
||||
value_fn=lambda printer: printer.booted_at,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
"invalid_host": "The host entry was not in full URL format, e.g., http://192.168.10.100:80"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"error": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"quality_scale": "platinum",
|
||||
"requirements": [
|
||||
"xknx==3.2.0",
|
||||
"xknxproject==3.7.1",
|
||||
"xknxproject==3.8.1",
|
||||
"knx-frontend==2024.9.10.221729"
|
||||
],
|
||||
"single_config_entry": true
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from laundrify_aio import LaundrifyAPI
|
||||
from laundrify_aio.exceptions import ApiConnectionException, UnauthorizedException
|
||||
|
||||
@@ -14,6 +16,8 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from .const import DEFAULT_POLL_INTERVAL, DOMAIN
|
||||
from .coordinator import LaundrifyUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||
|
||||
|
||||
@@ -51,3 +55,21 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Migrate entry."""
|
||||
|
||||
_LOGGER.debug("Migrating from version %s", entry.version)
|
||||
|
||||
if entry.version == 1:
|
||||
# 1 -> 2: Unique ID from integer to string
|
||||
if entry.minor_version == 1:
|
||||
minor_version = 2
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, unique_id=str(entry.unique_id), minor_version=minor_version
|
||||
)
|
||||
|
||||
_LOGGER.debug("Migration successful")
|
||||
|
||||
return True
|
||||
|
||||
@@ -29,6 +29,7 @@ class LaundrifyConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for laundrify."""
|
||||
|
||||
VERSION = 1
|
||||
MINOR_VERSION = 2
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
@@ -64,7 +65,7 @@ class LaundrifyConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
else:
|
||||
entry_data = {CONF_ACCESS_TOKEN: access_token}
|
||||
|
||||
await self.async_set_unique_id(account_id)
|
||||
await self.async_set_unique_id(str(account_id))
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
# Create a new entry if it doesn't exist
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@@ -9,7 +10,7 @@ import pypck
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.config_entries import ConfigFlowResult
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlowResult
|
||||
from homeassistant.const import (
|
||||
CONF_BASE,
|
||||
CONF_DEVICES,
|
||||
@@ -113,6 +114,8 @@ class LcnFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
VERSION = 1
|
||||
MINOR_VERSION = 2
|
||||
|
||||
_context_entry: ConfigEntry
|
||||
|
||||
async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
|
||||
"""Import existing configuration from LCN."""
|
||||
# validate the imported connection parameters
|
||||
@@ -193,31 +196,41 @@ class LcnFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
return self.async_create_entry(title=data[CONF_HOST], data=data)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, entry_data: Mapping[str, Any]
|
||||
) -> config_entries.ConfigFlowResult:
|
||||
"""Reconfigure LCN configuration."""
|
||||
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
|
||||
assert entry
|
||||
self._context_entry = entry
|
||||
return await self.async_step_reconfigure_confirm()
|
||||
|
||||
async def async_step_reconfigure_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> config_entries.ConfigFlowResult:
|
||||
"""Reconfigure LCN configuration."""
|
||||
errors = None
|
||||
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
|
||||
assert entry
|
||||
|
||||
if user_input is not None:
|
||||
user_input[CONF_HOST] = entry.data[CONF_HOST]
|
||||
user_input[CONF_HOST] = self._context_entry.data[CONF_HOST]
|
||||
|
||||
await self.hass.config_entries.async_unload(entry.entry_id)
|
||||
await self.hass.config_entries.async_unload(self._context_entry.entry_id)
|
||||
if (error := await validate_connection(user_input)) is not None:
|
||||
errors = {CONF_BASE: error}
|
||||
|
||||
if errors is None:
|
||||
data = entry.data.copy()
|
||||
data = self._context_entry.data.copy()
|
||||
data.update(user_input)
|
||||
self.hass.config_entries.async_update_entry(entry, data=data)
|
||||
await self.hass.config_entries.async_setup(entry.entry_id)
|
||||
self.hass.config_entries.async_update_entry(
|
||||
self._context_entry, data=data
|
||||
)
|
||||
await self.hass.config_entries.async_setup(self._context_entry.entry_id)
|
||||
return self.async_abort(reason="reconfigure_successful")
|
||||
|
||||
await self.hass.config_entries.async_setup(entry.entry_id)
|
||||
await self.hass.config_entries.async_setup(self._context_entry.entry_id)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="reconfigure",
|
||||
data_schema=self.add_suggested_values_to_schema(CONFIG_SCHEMA, entry.data),
|
||||
step_id="reconfigure_confirm",
|
||||
data_schema=self.add_suggested_values_to_schema(
|
||||
CONFIG_SCHEMA, self._context_entry.data
|
||||
),
|
||||
errors=errors or {},
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"acknowledge": "Retry sendig commands if no response is received (increases bus traffic)."
|
||||
}
|
||||
},
|
||||
"reconfigure": {
|
||||
"reconfigure_confirm": {
|
||||
"title": "Reconfigure LCN host",
|
||||
"description": "Reconfigure connection to LCN host.",
|
||||
"data": {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/linkplay",
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["python-linkplay==0.0.12"],
|
||||
"loggers": ["linkplay"],
|
||||
"requirements": ["python-linkplay==0.0.15"],
|
||||
"zeroconf": ["_linkplay._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pylitejet"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["pylitejet==0.6.2"]
|
||||
"requirements": ["pylitejet==0.6.3"]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from datetime import date, datetime, timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
@@ -74,6 +75,7 @@ class LocalCalendarEntity(CalendarEntity):
|
||||
"""Initialize LocalCalendarEntity."""
|
||||
self._store = store
|
||||
self._calendar = calendar
|
||||
self._calendar_lock = asyncio.Lock()
|
||||
self._event: CalendarEvent | None = None
|
||||
self._attr_name = name
|
||||
self._attr_unique_id = unique_id
|
||||
@@ -110,8 +112,10 @@ class LocalCalendarEntity(CalendarEntity):
|
||||
async def async_create_event(self, **kwargs: Any) -> None:
|
||||
"""Add a new event to calendar."""
|
||||
event = _parse_event(kwargs)
|
||||
EventStore(self._calendar).add(event)
|
||||
await self._async_store()
|
||||
async with self._calendar_lock:
|
||||
event_store = EventStore(self._calendar)
|
||||
await self.hass.async_add_executor_job(event_store.add, event)
|
||||
await self._async_store()
|
||||
await self.async_update_ha_state(force_refresh=True)
|
||||
|
||||
async def async_delete_event(
|
||||
@@ -124,15 +128,16 @@ class LocalCalendarEntity(CalendarEntity):
|
||||
range_value: Range = Range.NONE
|
||||
if recurrence_range == Range.THIS_AND_FUTURE:
|
||||
range_value = Range.THIS_AND_FUTURE
|
||||
try:
|
||||
EventStore(self._calendar).delete(
|
||||
uid,
|
||||
recurrence_id=recurrence_id,
|
||||
recurrence_range=range_value,
|
||||
)
|
||||
except EventStoreError as err:
|
||||
raise HomeAssistantError(f"Error while deleting event: {err}") from err
|
||||
await self._async_store()
|
||||
async with self._calendar_lock:
|
||||
try:
|
||||
EventStore(self._calendar).delete(
|
||||
uid,
|
||||
recurrence_id=recurrence_id,
|
||||
recurrence_range=range_value,
|
||||
)
|
||||
except EventStoreError as err:
|
||||
raise HomeAssistantError(f"Error while deleting event: {err}") from err
|
||||
await self._async_store()
|
||||
await self.async_update_ha_state(force_refresh=True)
|
||||
|
||||
async def async_update_event(
|
||||
@@ -147,16 +152,23 @@ class LocalCalendarEntity(CalendarEntity):
|
||||
range_value: Range = Range.NONE
|
||||
if recurrence_range == Range.THIS_AND_FUTURE:
|
||||
range_value = Range.THIS_AND_FUTURE
|
||||
try:
|
||||
EventStore(self._calendar).edit(
|
||||
uid,
|
||||
new_event,
|
||||
recurrence_id=recurrence_id,
|
||||
recurrence_range=range_value,
|
||||
)
|
||||
except EventStoreError as err:
|
||||
raise HomeAssistantError(f"Error while updating event: {err}") from err
|
||||
await self._async_store()
|
||||
|
||||
async with self._calendar_lock:
|
||||
event_store = EventStore(self._calendar)
|
||||
|
||||
def apply_edit() -> None:
|
||||
event_store.edit(
|
||||
uid,
|
||||
new_event,
|
||||
recurrence_id=recurrence_id,
|
||||
recurrence_range=range_value,
|
||||
)
|
||||
|
||||
try:
|
||||
await self.hass.async_add_executor_job(apply_edit)
|
||||
except EventStoreError as err:
|
||||
raise HomeAssistantError(f"Error while updating event: {err}") from err
|
||||
await self._async_store()
|
||||
await self.async_update_ha_state(force_refresh=True)
|
||||
|
||||
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/local_calendar",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["ical"],
|
||||
"requirements": ["ical==8.1.1"]
|
||||
"requirements": ["ical==8.2.0"]
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/local_todo",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["ical==8.1.1"]
|
||||
"requirements": ["ical==8.2.0"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""A Local To-do todo platform."""
|
||||
|
||||
import asyncio
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
@@ -130,6 +131,7 @@ class LocalTodoListEntity(TodoListEntity):
|
||||
"""Initialize LocalTodoListEntity."""
|
||||
self._store = store
|
||||
self._calendar = calendar
|
||||
self._calendar_lock = asyncio.Lock()
|
||||
self._attr_name = name.capitalize()
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
@@ -159,23 +161,28 @@ class LocalTodoListEntity(TodoListEntity):
|
||||
async def async_create_todo_item(self, item: TodoItem) -> None:
|
||||
"""Add an item to the To-do list."""
|
||||
todo = _convert_item(item)
|
||||
self._new_todo_store().add(todo)
|
||||
await self.async_save()
|
||||
async with self._calendar_lock:
|
||||
todo_store = self._new_todo_store()
|
||||
await self.hass.async_add_executor_job(todo_store.add, todo)
|
||||
await self.async_save()
|
||||
await self.async_update_ha_state(force_refresh=True)
|
||||
|
||||
async def async_update_todo_item(self, item: TodoItem) -> None:
|
||||
"""Update an item to the To-do list."""
|
||||
todo = _convert_item(item)
|
||||
self._new_todo_store().edit(todo.uid, todo)
|
||||
await self.async_save()
|
||||
async with self._calendar_lock:
|
||||
todo_store = self._new_todo_store()
|
||||
await self.hass.async_add_executor_job(todo_store.edit, todo.uid, todo)
|
||||
await self.async_save()
|
||||
await self.async_update_ha_state(force_refresh=True)
|
||||
|
||||
async def async_delete_todo_items(self, uids: list[str]) -> None:
|
||||
"""Delete an item from the To-do list."""
|
||||
store = self._new_todo_store()
|
||||
for uid in uids:
|
||||
store.delete(uid)
|
||||
await self.async_save()
|
||||
async with self._calendar_lock:
|
||||
for uid in uids:
|
||||
store.delete(uid)
|
||||
await self.async_save()
|
||||
await self.async_update_ha_state(force_refresh=True)
|
||||
|
||||
async def async_move_todo_item(
|
||||
@@ -184,23 +191,24 @@ class LocalTodoListEntity(TodoListEntity):
|
||||
"""Re-order an item to the To-do list."""
|
||||
if uid == previous_uid:
|
||||
return
|
||||
todos = self._calendar.todos
|
||||
item_idx: dict[str, int] = {itm.uid: idx for idx, itm in enumerate(todos)}
|
||||
if uid not in item_idx:
|
||||
raise HomeAssistantError(
|
||||
"Item '{uid}' not found in todo list {self.entity_id}"
|
||||
)
|
||||
if previous_uid and previous_uid not in item_idx:
|
||||
raise HomeAssistantError(
|
||||
"Item '{previous_uid}' not found in todo list {self.entity_id}"
|
||||
)
|
||||
dst_idx = item_idx[previous_uid] + 1 if previous_uid else 0
|
||||
src_idx = item_idx[uid]
|
||||
src_item = todos.pop(src_idx)
|
||||
if dst_idx > src_idx:
|
||||
dst_idx -= 1
|
||||
todos.insert(dst_idx, src_item)
|
||||
await self.async_save()
|
||||
async with self._calendar_lock:
|
||||
todos = self._calendar.todos
|
||||
item_idx: dict[str, int] = {itm.uid: idx for idx, itm in enumerate(todos)}
|
||||
if uid not in item_idx:
|
||||
raise HomeAssistantError(
|
||||
"Item '{uid}' not found in todo list {self.entity_id}"
|
||||
)
|
||||
if previous_uid and previous_uid not in item_idx:
|
||||
raise HomeAssistantError(
|
||||
"Item '{previous_uid}' not found in todo list {self.entity_id}"
|
||||
)
|
||||
dst_idx = item_idx[previous_uid] + 1 if previous_uid else 0
|
||||
src_idx = item_idx[uid]
|
||||
src_item = todos.pop(src_idx)
|
||||
if dst_idx > src_idx:
|
||||
dst_idx -= 1
|
||||
todos.insert(dst_idx, src_item)
|
||||
await self.async_save()
|
||||
await self.async_update_ha_state(force_refresh=True)
|
||||
|
||||
async def async_save(self) -> None:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Config flow for the integration."""
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@@ -41,17 +42,17 @@ class MadVRConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
return await self._handle_config_step(user_input)
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
self, entry_data: Mapping[str, Any]
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle reconfiguration of the device."""
|
||||
self.entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
|
||||
return await self.async_step_reconfigure_confirm(user_input)
|
||||
return await self.async_step_reconfigure_confirm()
|
||||
|
||||
async def async_step_reconfigure_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle a reconfiguration flow initialized by the user."""
|
||||
return await self._handle_config_step(user_input, step_id="reconfigure")
|
||||
return await self._handle_config_step(user_input, step_id="reconfigure_confirm")
|
||||
|
||||
async def _handle_config_step(
|
||||
self, user_input: dict[str, Any] | None = None, step_id: str = "user"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"port": "The port your madVR Envy is listening on. In 99% of cases, leave this as the default."
|
||||
}
|
||||
},
|
||||
"reconfigure": {
|
||||
"reconfigure_confirm": {
|
||||
"title": "Reconfigure madVR Envy",
|
||||
"description": "Your device needs to be on in order to reconfigure the integation.",
|
||||
"data": {
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/matrix",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["matrix_client"],
|
||||
"requirements": ["matrix-nio==0.25.1", "Pillow==10.4.0"]
|
||||
"requirements": ["matrix-nio==0.25.2", "Pillow==10.4.0"]
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/mealie",
|
||||
"integration_type": "service",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["aiomealie==0.9.2"]
|
||||
"requirements": ["aiomealie==0.9.3"]
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
},
|
||||
"error": {
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
"iot_class": "calculated",
|
||||
"loggers": ["yt_dlp"],
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["yt-dlp==2024.08.06"],
|
||||
"requirements": ["yt-dlp==2024.10.07"],
|
||||
"single_config_entry": true
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]",
|
||||
"user_rejected_authorize": "[%key:common::config_flow::abort::oauth2_user_rejected_authorize%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]",
|
||||
"wrong_account": "You can only reauthenticate this entry with the same microBees account."
|
||||
},
|
||||
|
||||
@@ -71,15 +71,15 @@
|
||||
},
|
||||
"issues": {
|
||||
"removed_lazy_error_count": {
|
||||
"title": "`{config_key}` configuration key is being removed",
|
||||
"title": "{config_key} configuration key is being removed",
|
||||
"description": "Please remove the `{config_key}` key from the {integration} entry in your configuration.yaml file and restart Home Assistant to fix this issue. All errors will be reported, as lazy_error_count is accepted but ignored"
|
||||
},
|
||||
"deprecated_retries": {
|
||||
"title": "`{config_key}` configuration key is being removed",
|
||||
"title": "{config_key} configuration key is being removed",
|
||||
"description": "Please remove the `{config_key}` key from the {integration} entry in your configuration.yaml file and restart Home Assistant to fix this issue.\n\nThe maximum number of retries is now fixed to 3."
|
||||
},
|
||||
"missing_modbus_name": {
|
||||
"title": "Modbus entry with host `{sub_2}` missing name",
|
||||
"title": "Modbus entry with host {sub_2} missing name",
|
||||
"description": "Please add `{sub_1}` key to the {integration} entry with host `{sub_2}` in your configuration.yaml file and restart Home Assistant to fix this issue\n\n. `{sub_1}: {sub_3}` have been added."
|
||||
},
|
||||
"duplicate_modbus_entry": {
|
||||
@@ -99,7 +99,7 @@
|
||||
"description": "Please add at least one entity to Modbus {sub_1} in your configuration.yaml file and restart Home Assistant to fix this issue."
|
||||
},
|
||||
"deprecated_restart": {
|
||||
"title": "`modbus.restart` is being removed",
|
||||
"title": "modbus.restart is being removed",
|
||||
"description": "Please use reload yaml via the developer tools in the UI instead of via the `modbus.restart` action."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ from homeassistant.const import CONF_NAME, Platform
|
||||
from homeassistant.helpers.schema_config_entry_flow import (
|
||||
SchemaCommonFlowHandler,
|
||||
SchemaConfigFlowHandler,
|
||||
SchemaFlowError,
|
||||
SchemaFlowFormStep,
|
||||
)
|
||||
from homeassistant.helpers.selector import (
|
||||
@@ -33,18 +34,20 @@ from .const import (
|
||||
)
|
||||
|
||||
|
||||
async def validate_duplicate(
|
||||
async def validate_input(
|
||||
handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
"""Validate already existing entry."""
|
||||
handler.parent_handler._async_abort_entries_match({**handler.options, **user_input}) # noqa: SLF001
|
||||
if user_input[CONF_CALIBRATION_FACTOR] == 0.0:
|
||||
raise SchemaFlowError("calibration_is_zero")
|
||||
return user_input
|
||||
|
||||
|
||||
DATA_SCHEMA_OPTIONS = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_CALIBRATION_FACTOR): NumberSelector(
|
||||
NumberSelectorConfig(min=0, step="any", mode=NumberSelectorMode.BOX)
|
||||
NumberSelectorConfig(step=0.1, mode=NumberSelectorMode.BOX)
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -74,13 +77,13 @@ DATA_SCHEMA_CONFIG = vol.Schema(
|
||||
CONFIG_FLOW = {
|
||||
"user": SchemaFlowFormStep(
|
||||
schema=DATA_SCHEMA_CONFIG,
|
||||
validate_user_input=validate_duplicate,
|
||||
validate_user_input=validate_input,
|
||||
),
|
||||
}
|
||||
OPTIONS_FLOW = {
|
||||
"init": SchemaFlowFormStep(
|
||||
DATA_SCHEMA_OPTIONS,
|
||||
validate_user_input=validate_duplicate,
|
||||
validate_user_input=validate_input,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ async def async_setup_platform(
|
||||
outdoor_temp_sensor,
|
||||
indoor_humidity_sensor,
|
||||
calib_factor,
|
||||
None,
|
||||
)
|
||||
],
|
||||
False,
|
||||
@@ -118,6 +119,7 @@ async def async_setup_entry(
|
||||
outdoor_temp_sensor,
|
||||
indoor_humidity_sensor,
|
||||
calib_factor,
|
||||
entry.entry_id,
|
||||
)
|
||||
],
|
||||
False,
|
||||
@@ -141,10 +143,12 @@ class MoldIndicator(SensorEntity):
|
||||
outdoor_temp_sensor: str,
|
||||
indoor_humidity_sensor: str,
|
||||
calib_factor: float,
|
||||
unique_id: str | None,
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
self._state: str | None = None
|
||||
self._attr_name = name
|
||||
self._attr_unique_id = unique_id
|
||||
self._indoor_temp_sensor = indoor_temp_sensor
|
||||
self._indoor_humidity_sensor = indoor_humidity_sensor
|
||||
self._outdoor_temp_sensor = outdoor_temp_sensor
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
},
|
||||
"error": {
|
||||
"calibration_is_zero": "Calibration factor can't be zero."
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"description": "Add Mold indicator helper",
|
||||
@@ -27,6 +30,9 @@
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
},
|
||||
"error": {
|
||||
"calibration_is_zero": "Calibration factor can't be zero."
|
||||
},
|
||||
"step": {
|
||||
"init": {
|
||||
"description": "Adjust the calibration factor as required",
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "assumed_state",
|
||||
"loggers": ["motionblindsble"],
|
||||
"requirements": ["motionblindsble==0.1.1"]
|
||||
"requirements": ["motionblindsble==0.1.2"]
|
||||
}
|
||||
|
||||
@@ -260,14 +260,18 @@ class MqttSensor(MqttEntity, RestoreSensor):
|
||||
msg.topic,
|
||||
)
|
||||
return
|
||||
|
||||
if payload == PAYLOAD_NONE:
|
||||
self._attr_native_value = None
|
||||
return
|
||||
|
||||
if self._numeric_state_expected:
|
||||
if payload == "":
|
||||
_LOGGER.debug("Ignore empty state from '%s'", msg.topic)
|
||||
elif payload == PAYLOAD_NONE:
|
||||
self._attr_native_value = None
|
||||
else:
|
||||
self._attr_native_value = payload
|
||||
return
|
||||
|
||||
if self.options and payload not in self.options:
|
||||
_LOGGER.warning(
|
||||
"Ignoring invalid option received on topic '%s', got '%s', allowed: %s",
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
}
|
||||
},
|
||||
"migrate_notify_service": {
|
||||
"title": "Legacy action `notify.{service_name}` stll being used",
|
||||
"title": "Legacy action notify.{service_name} stll being used",
|
||||
"fix_flow": {
|
||||
"step": {
|
||||
"confirm": {
|
||||
|
||||
@@ -7,7 +7,7 @@ from nyt_games import NYTGamesClient
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_TOKEN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
||||
|
||||
from .coordinator import NYTGamesCoordinator
|
||||
|
||||
@@ -23,7 +23,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: NYTGamesConfigEntry) ->
|
||||
"""Set up NYTGames from a config entry."""
|
||||
|
||||
client = NYTGamesClient(
|
||||
entry.data[CONF_TOKEN], session=async_get_clientsession(hass)
|
||||
entry.data[CONF_TOKEN], session=async_create_clientsession(hass)
|
||||
)
|
||||
|
||||
coordinator = NYTGamesCoordinator(hass, client)
|
||||
|
||||
@@ -7,7 +7,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_TOKEN
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
||||
|
||||
from .const import DOMAIN, LOGGER
|
||||
|
||||
@@ -21,8 +21,9 @@ class NYTGamesConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a flow initialized by the user."""
|
||||
errors: dict[str, str] = {}
|
||||
if user_input:
|
||||
session = async_get_clientsession(self.hass)
|
||||
client = NYTGamesClient(user_input[CONF_TOKEN], session=session)
|
||||
session = async_create_clientsession(self.hass)
|
||||
token = user_input[CONF_TOKEN].strip()
|
||||
client = NYTGamesClient(token, session=session)
|
||||
try:
|
||||
user_id = await client.get_user_id()
|
||||
except NYTGamesAuthenticationError:
|
||||
@@ -35,7 +36,9 @@ class NYTGamesConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
else:
|
||||
await self.async_set_unique_id(str(user_id))
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(title="NYT Games", data=user_input)
|
||||
return self.async_create_entry(
|
||||
title="NYT Games", data={CONF_TOKEN: token}
|
||||
)
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema({vol.Required(CONF_TOKEN): str}),
|
||||
|
||||
@@ -23,7 +23,7 @@ class NYTGamesData:
|
||||
|
||||
wordle: Wordle
|
||||
spelling_bee: SpellingBee | None
|
||||
connections: Connections
|
||||
connections: Connections | None
|
||||
|
||||
|
||||
class NYTGamesCoordinator(DataUpdateCoordinator[NYTGamesData]):
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/nyt_games",
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"requirements": ["nyt_games==0.4.2"]
|
||||
"requirements": ["nyt_games==0.4.3"]
|
||||
}
|
||||
|
||||
@@ -161,10 +161,11 @@ async def async_setup_entry(
|
||||
NYTGamesSpellingBeeSensor(coordinator, description)
|
||||
for description in SPELLING_BEE_SENSORS
|
||||
)
|
||||
entities.extend(
|
||||
NYTGamesConnectionsSensor(coordinator, description)
|
||||
for description in CONNECTIONS_SENSORS
|
||||
)
|
||||
if coordinator.data.connections is not None:
|
||||
entities.extend(
|
||||
NYTGamesConnectionsSensor(coordinator, description)
|
||||
for description in CONNECTIONS_SENSORS
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
@@ -236,4 +237,5 @@ class NYTGamesConnectionsSensor(ConnectionsEntity, SensorEntity):
|
||||
@property
|
||||
def native_value(self) -> StateType | date:
|
||||
"""Return the state of the sensor."""
|
||||
assert self.coordinator.data.connections is not None
|
||||
return self.entity_description.value_fn(self.coordinator.data.connections)
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/opentherm_gw",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pyotgw"],
|
||||
"requirements": ["pyotgw==2.2.1"]
|
||||
"requirements": ["pyotgw==2.2.2"]
|
||||
}
|
||||
|
||||
@@ -130,20 +130,32 @@ class OpowerCoordinator(DataUpdateCoordinator[dict[str, Forecast]]):
|
||||
continue
|
||||
start = cost_reads[0].start_time
|
||||
_LOGGER.debug("Getting statistics at: %s", start)
|
||||
stats = await get_instance(self.hass).async_add_executor_job(
|
||||
statistics_during_period,
|
||||
self.hass,
|
||||
start,
|
||||
start + timedelta(seconds=1),
|
||||
{cost_statistic_id, consumption_statistic_id},
|
||||
"hour",
|
||||
None,
|
||||
{"sum"},
|
||||
)
|
||||
# In the common case there should be a previous statistic at start time
|
||||
# so we only need to fetch one statistic. If there isn't any, fetch all.
|
||||
for end in (start + timedelta(seconds=1), None):
|
||||
stats = await get_instance(self.hass).async_add_executor_job(
|
||||
statistics_during_period,
|
||||
self.hass,
|
||||
start,
|
||||
end,
|
||||
{cost_statistic_id, consumption_statistic_id},
|
||||
"hour",
|
||||
None,
|
||||
{"sum"},
|
||||
)
|
||||
if stats:
|
||||
break
|
||||
if end:
|
||||
_LOGGER.debug(
|
||||
"Not found. Trying to find the oldest statistic after %s",
|
||||
start,
|
||||
)
|
||||
# We are in this code path only if get_last_statistics found a stat
|
||||
# so statistics_during_period should also have found at least one.
|
||||
assert stats
|
||||
cost_sum = cast(float, stats[cost_statistic_id][0]["sum"])
|
||||
consumption_sum = cast(float, stats[consumption_statistic_id][0]["sum"])
|
||||
last_stats_time = stats[consumption_statistic_id][0]["start"]
|
||||
assert last_stats_time == start.timestamp()
|
||||
|
||||
cost_statistics = []
|
||||
consumption_statistics = []
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/opower",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["opower"],
|
||||
"requirements": ["opower==0.8.0"]
|
||||
"requirements": ["opower==0.8.3"]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
},
|
||||
"abort": {
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
|
||||
"already_configured": "The Thread border router is already configured",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
|
||||
@@ -32,7 +32,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
client_session=async_get_clientsession(hass),
|
||||
)
|
||||
|
||||
if custom_account := entry.data.get(CONF_ACCOUNT) is not None:
|
||||
if (custom_account := entry.data.get(CONF_ACCOUNT)) is not None:
|
||||
client.custom_account_id = custom_account
|
||||
|
||||
try:
|
||||
@@ -49,7 +49,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
async def async_update_data() -> OVODailyUsage:
|
||||
"""Fetch data from OVO Energy."""
|
||||
if custom_account := entry.data.get(CONF_ACCOUNT) is not None:
|
||||
if (custom_account := entry.data.get(CONF_ACCOUNT)) is not None:
|
||||
client.custom_account_id = custom_account
|
||||
|
||||
async with asyncio.timeout(10):
|
||||
|
||||
@@ -46,7 +46,7 @@ class OVOEnergyFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
client_session=async_get_clientsession(self.hass),
|
||||
)
|
||||
|
||||
if custom_account := user_input.get(CONF_ACCOUNT) is not None:
|
||||
if (custom_account := user_input.get(CONF_ACCOUNT)) is not None:
|
||||
client.custom_account_id = custom_account
|
||||
|
||||
try:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user