Skip to content

Commit

Permalink
2023.12.2 (#105655)
Browse files Browse the repository at this point in the history
  • Loading branch information
frenck authored Dec 13, 2023
2 parents 9b10af6 + ebb54d7 commit 711d9e2
Show file tree
Hide file tree
Showing 75 changed files with 1,201 additions and 523 deletions.
23 changes: 3 additions & 20 deletions homeassistant/components/aftership/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from homeassistant.config_entries import ConfigFlow
from homeassistant.const import CONF_API_KEY, CONF_NAME
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN
from homeassistant.data_entry_flow import AbortFlow, FlowResult
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue

Expand Down Expand Up @@ -51,25 +51,6 @@ async def async_step_user(

async def async_step_import(self, config: dict[str, Any]) -> FlowResult:
"""Import configuration from yaml."""
try:
self._async_abort_entries_match({CONF_API_KEY: config[CONF_API_KEY]})
except AbortFlow as err:
async_create_issue(
self.hass,
DOMAIN,
"deprecated_yaml_import_issue_already_configured",
breaks_in_ha_version="2024.4.0",
is_fixable=False,
issue_domain=DOMAIN,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml_import_issue_already_configured",
translation_placeholders={
"domain": DOMAIN,
"integration_title": "AfterShip",
},
)
raise err

async_create_issue(
self.hass,
HOMEASSISTANT_DOMAIN,
Expand All @@ -84,6 +65,8 @@ async def async_step_import(self, config: dict[str, Any]) -> FlowResult:
"integration_title": "AfterShip",
},
)

self._async_abort_entries_match({CONF_API_KEY: config[CONF_API_KEY]})
return self.async_create_entry(
title=config.get(CONF_NAME, "AfterShip"),
data={CONF_API_KEY: config[CONF_API_KEY]},
Expand Down
4 changes: 0 additions & 4 deletions homeassistant/components/aftership/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@
}
},
"issues": {
"deprecated_yaml_import_issue_already_configured": {
"title": "The {integration_title} YAML configuration import failed",
"description": "Configuring {integration_title} using YAML is being removed but the YAML configuration was already imported.\n\nRemove the YAML configuration and restart Home Assistant."
},
"deprecated_yaml_import_issue_cannot_connect": {
"title": "The {integration_title} YAML configuration import failed",
"description": "Configuring {integration_title} using YAML is being removed but there was an connection error importing your YAML configuration.\n\nEnsure connection to {integration_title} works and restart Home Assistant to try again or remove the {integration_title} YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
Expand Down
19 changes: 9 additions & 10 deletions homeassistant/components/alexa/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1304,13 +1304,14 @@ async def async_api_set_range(
service = None
data: dict[str, Any] = {ATTR_ENTITY_ID: entity.entity_id}
range_value = directive.payload["rangeValue"]
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)

# Cover Position
if instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
range_value = int(range_value)
if range_value == 0:
if supported & cover.CoverEntityFeature.CLOSE and range_value == 0:
service = cover.SERVICE_CLOSE_COVER
elif range_value == 100:
elif supported & cover.CoverEntityFeature.OPEN and range_value == 100:
service = cover.SERVICE_OPEN_COVER
else:
service = cover.SERVICE_SET_COVER_POSITION
Expand All @@ -1319,9 +1320,9 @@ async def async_api_set_range(
# Cover Tilt
elif instance == f"{cover.DOMAIN}.tilt":
range_value = int(range_value)
if range_value == 0:
if supported & cover.CoverEntityFeature.CLOSE_TILT and range_value == 0:
service = cover.SERVICE_CLOSE_COVER_TILT
elif range_value == 100:
elif supported & cover.CoverEntityFeature.OPEN_TILT and range_value == 100:
service = cover.SERVICE_OPEN_COVER_TILT
else:
service = cover.SERVICE_SET_COVER_TILT_POSITION
Expand All @@ -1332,13 +1333,11 @@ async def async_api_set_range(
range_value = int(range_value)
if range_value == 0:
service = fan.SERVICE_TURN_OFF
elif supported & fan.FanEntityFeature.SET_SPEED:
service = fan.SERVICE_SET_PERCENTAGE
data[fan.ATTR_PERCENTAGE] = range_value
else:
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported and fan.FanEntityFeature.SET_SPEED:
service = fan.SERVICE_SET_PERCENTAGE
data[fan.ATTR_PERCENTAGE] = range_value
else:
service = fan.SERVICE_TURN_ON
service = fan.SERVICE_TURN_ON

# Humidifier target humidity
elif instance == f"{humidifier.DOMAIN}.{humidifier.ATTR_HUMIDITY}":
Expand Down
62 changes: 32 additions & 30 deletions homeassistant/components/assist_pipeline/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ class PipelineStage(StrEnum):
STT = "stt"
INTENT = "intent"
TTS = "tts"
END = "end"


PIPELINE_STAGE_ORDER = [
Expand Down Expand Up @@ -1024,35 +1025,32 @@ async def text_to_speech(self, tts_input: str) -> None:
)
)

if tts_input := tts_input.strip():
try:
# Synthesize audio and get URL
tts_media_id = tts_generate_media_source_id(
self.hass,
tts_input,
engine=self.tts_engine,
language=self.pipeline.tts_language,
options=self.tts_options,
)
tts_media = await media_source.async_resolve_media(
self.hass,
tts_media_id,
None,
)
except Exception as src_error:
_LOGGER.exception("Unexpected error during text-to-speech")
raise TextToSpeechError(
code="tts-failed",
message="Unexpected error during text-to-speech",
) from src_error

_LOGGER.debug("TTS result %s", tts_media)
tts_output = {
"media_id": tts_media_id,
**asdict(tts_media),
}
else:
tts_output = {}
try:
# Synthesize audio and get URL
tts_media_id = tts_generate_media_source_id(
self.hass,
tts_input,
engine=self.tts_engine,
language=self.pipeline.tts_language,
options=self.tts_options,
)
tts_media = await media_source.async_resolve_media(
self.hass,
tts_media_id,
None,
)
except Exception as src_error:
_LOGGER.exception("Unexpected error during text-to-speech")
raise TextToSpeechError(
code="tts-failed",
message="Unexpected error during text-to-speech",
) from src_error

_LOGGER.debug("TTS result %s", tts_media)
tts_output = {
"media_id": tts_media_id,
**asdict(tts_media),
}

self.process_event(
PipelineEvent(PipelineEventType.TTS_END, {"tts_output": tts_output})
Expand Down Expand Up @@ -1345,7 +1343,11 @@ async def buffer_then_audio_stream() -> (
self.conversation_id,
self.device_id,
)
current_stage = PipelineStage.TTS
if tts_input.strip():
current_stage = PipelineStage.TTS
else:
# Skip TTS
current_stage = PipelineStage.END

if self.run.end_stage != PipelineStage.INTENT:
# text-to-speech
Expand Down
7 changes: 6 additions & 1 deletion homeassistant/components/blink/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
)
from .coordinator import BlinkUpdateCoordinator

SERVICE_UPDATE_SCHEMA = vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): vol.All(cv.ensure_list, [cv.string]),
}
)
SERVICE_SAVE_VIDEO_SCHEMA = vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): vol.All(cv.ensure_list, [cv.string]),
Expand Down Expand Up @@ -152,7 +157,7 @@ async def blink_refresh(call: ServiceCall):

# Register all the above services
service_mapping = [
(blink_refresh, SERVICE_REFRESH, None),
(blink_refresh, SERVICE_REFRESH, SERVICE_UPDATE_SCHEMA),
(
async_handle_save_video_service,
SERVICE_SAVE_VIDEO,
Expand Down
32 changes: 28 additions & 4 deletions homeassistant/components/blink/services.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
# Describes the format for available Blink services

blink_update:
fields:
device_id:
required: true
selector:
device:
integration: blink

trigger_camera:
target:
entity:
integration: blink
domain: camera
fields:
device_id:
required: true
selector:
device:
integration: blink

save_video:
fields:
device_id:
required: true
selector:
device:
integration: blink
name:
required: true
example: "Living Room"
Expand All @@ -22,6 +36,11 @@ save_video:

save_recent_clips:
fields:
device_id:
required: true
selector:
device:
integration: blink
name:
required: true
example: "Living Room"
Expand All @@ -35,6 +54,11 @@ save_recent_clips:

send_pin:
fields:
device_id:
required: true
selector:
device:
integration: blink
pin:
example: "abc123"
selector:
Expand Down
28 changes: 26 additions & 2 deletions homeassistant/components/blink/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,23 @@
"services": {
"blink_update": {
"name": "Update",
"description": "Forces a refresh."
"description": "Forces a refresh.",
"fields": {
"device_id": {
"name": "Device ID",
"description": "The Blink device id."
}
}
},
"trigger_camera": {
"name": "Trigger camera",
"description": "Requests camera to take new image."
"description": "Requests camera to take new image.",
"fields": {
"device_id": {
"name": "Device ID",
"description": "The Blink device id."
}
}
},
"save_video": {
"name": "Save video",
Expand All @@ -74,6 +86,10 @@
"filename": {
"name": "File name",
"description": "Filename to writable path (directory may need to be included in allowlist_external_dirs in config)."
},
"device_id": {
"name": "Device ID",
"description": "The Blink device id."
}
}
},
Expand All @@ -88,6 +104,10 @@
"file_path": {
"name": "Output directory",
"description": "Directory name of writable path (directory may need to be included in allowlist_external_dirs in config)."
},
"device_id": {
"name": "Device ID",
"description": "The Blink device id."
}
}
},
Expand All @@ -98,6 +118,10 @@
"pin": {
"name": "Pin",
"description": "PIN received from blink. Leave empty if you only received a verification email."
},
"device_id": {
"name": "Device ID",
"description": "The Blink device id."
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/caldav/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/caldav",
"iot_class": "cloud_polling",
"loggers": ["caldav", "vobject"],
"requirements": ["caldav==1.3.6"]
"requirements": ["caldav==1.3.8"]
}
10 changes: 5 additions & 5 deletions homeassistant/components/caldav/todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,7 @@ def _to_ics_fields(item: TodoItem) -> dict[str, Any]:
if status := item.status:
item_data["status"] = TODO_STATUS_MAP_INV.get(status, "NEEDS-ACTION")
if due := item.due:
if isinstance(due, datetime):
item_data["due"] = dt_util.as_utc(due).strftime("%Y%m%dT%H%M%SZ")
else:
item_data["due"] = due.strftime("%Y%m%d")
item_data["due"] = due
if description := item.description:
item_data["description"] = description
return item_data
Expand Down Expand Up @@ -162,7 +159,10 @@ async def async_update_todo_item(self, item: TodoItem) -> None:
except (requests.ConnectionError, DAVError) as err:
raise HomeAssistantError(f"CalDAV lookup error: {err}") from err
vtodo = todo.icalendar_component # type: ignore[attr-defined]
vtodo.update(**_to_ics_fields(item))
updated_fields = _to_ics_fields(item)
if "due" in updated_fields:
todo.set_due(updated_fields.pop("due")) # type: ignore[attr-defined]
vtodo.update(**updated_fields)
try:
await self.hass.async_add_executor_job(
partial(
Expand Down
16 changes: 15 additions & 1 deletion homeassistant/components/climate/intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class GetTemperatureIntent(intent.IntentHandler):
"""Handle GetTemperature intents."""

intent_type = INTENT_GET_TEMPERATURE
slot_schema = {vol.Optional("area"): str}
slot_schema = {vol.Optional("area"): str, vol.Optional("name"): str}

async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
"""Handle the intent."""
Expand Down Expand Up @@ -49,6 +49,20 @@ async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse
if climate_state is None:
raise intent.IntentHandleError(f"No climate entity in area {area_name}")

climate_entity = component.get_entity(climate_state.entity_id)
elif "name" in slots:
# Filter by name
entity_name = slots["name"]["value"]

for maybe_climate in intent.async_match_states(
hass, name=entity_name, domains=[DOMAIN]
):
climate_state = maybe_climate
break

if climate_state is None:
raise intent.IntentHandleError(f"No climate entity named {entity_name}")

climate_entity = component.get_entity(climate_state.entity_id)
else:
# First entity
Expand Down
5 changes: 4 additions & 1 deletion homeassistant/components/enphase_envoy/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ async def _async_update_data(self) -> dict[str, Any]:
if not self._setup_complete:
await self._async_setup_and_authenticate()
self._async_mark_setup_complete()
return (await envoy.update()).raw
# dump all received data in debug mode to assist troubleshooting
envoy_data = await envoy.update()
_LOGGER.debug("Envoy data: %s", envoy_data)
return envoy_data.raw
except INVALID_AUTH_ERRORS as err:
if self._setup_complete and tries == 0:
# token likely expired or firmware changed, try to re-authenticate
Expand Down
Loading

0 comments on commit 711d9e2

Please sign in to comment.