Bump esphome dependencies (#110892)
This commit is contained in:
parent
136a31e4bc
commit
fd1f712d67
23 changed files with 91 additions and 121 deletions
|
@ -115,42 +115,42 @@ class EsphomeAlarmControlPanel(
|
||||||
|
|
||||||
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
async def async_alarm_disarm(self, code: str | None = None) -> None:
|
||||||
"""Send disarm command."""
|
"""Send disarm command."""
|
||||||
await self._client.alarm_control_panel_command(
|
self._client.alarm_control_panel_command(
|
||||||
self._key, AlarmControlPanelCommand.DISARM, code
|
self._key, AlarmControlPanelCommand.DISARM, code
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
async def async_alarm_arm_home(self, code: str | None = None) -> None:
|
||||||
"""Send arm home command."""
|
"""Send arm home command."""
|
||||||
await self._client.alarm_control_panel_command(
|
self._client.alarm_control_panel_command(
|
||||||
self._key, AlarmControlPanelCommand.ARM_HOME, code
|
self._key, AlarmControlPanelCommand.ARM_HOME, code
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
async def async_alarm_arm_away(self, code: str | None = None) -> None:
|
||||||
"""Send arm away command."""
|
"""Send arm away command."""
|
||||||
await self._client.alarm_control_panel_command(
|
self._client.alarm_control_panel_command(
|
||||||
self._key, AlarmControlPanelCommand.ARM_AWAY, code
|
self._key, AlarmControlPanelCommand.ARM_AWAY, code
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_alarm_arm_night(self, code: str | None = None) -> None:
|
async def async_alarm_arm_night(self, code: str | None = None) -> None:
|
||||||
"""Send arm away command."""
|
"""Send arm away command."""
|
||||||
await self._client.alarm_control_panel_command(
|
self._client.alarm_control_panel_command(
|
||||||
self._key, AlarmControlPanelCommand.ARM_NIGHT, code
|
self._key, AlarmControlPanelCommand.ARM_NIGHT, code
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
|
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
|
||||||
"""Send arm away command."""
|
"""Send arm away command."""
|
||||||
await self._client.alarm_control_panel_command(
|
self._client.alarm_control_panel_command(
|
||||||
self._key, AlarmControlPanelCommand.ARM_CUSTOM_BYPASS, code
|
self._key, AlarmControlPanelCommand.ARM_CUSTOM_BYPASS, code
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
|
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
|
||||||
"""Send arm away command."""
|
"""Send arm away command."""
|
||||||
await self._client.alarm_control_panel_command(
|
self._client.alarm_control_panel_command(
|
||||||
self._key, AlarmControlPanelCommand.ARM_VACATION, code
|
self._key, AlarmControlPanelCommand.ARM_VACATION, code
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_alarm_trigger(self, code: str | None = None) -> None:
|
async def async_alarm_trigger(self, code: str | None = None) -> None:
|
||||||
"""Send alarm trigger command."""
|
"""Send alarm trigger command."""
|
||||||
await self._client.alarm_control_panel_command(
|
self._client.alarm_control_panel_command(
|
||||||
self._key, AlarmControlPanelCommand.TRIGGER, code
|
self._key, AlarmControlPanelCommand.TRIGGER, code
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,7 +21,8 @@ def _async_unload(unload_callbacks: list[CALLBACK_TYPE]) -> None:
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
||||||
async def async_connect_scanner(
|
@hass_callback
|
||||||
|
def async_connect_scanner(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry_data: RuntimeEntryData,
|
entry_data: RuntimeEntryData,
|
||||||
cli: APIClient,
|
cli: APIClient,
|
||||||
|
@ -29,7 +30,7 @@ async def async_connect_scanner(
|
||||||
cache: ESPHomeBluetoothCache,
|
cache: ESPHomeBluetoothCache,
|
||||||
) -> CALLBACK_TYPE:
|
) -> CALLBACK_TYPE:
|
||||||
"""Connect scanner."""
|
"""Connect scanner."""
|
||||||
client_data = await connect_scanner(cli, device_info, cache, entry_data.available)
|
client_data = connect_scanner(cli, device_info, cache, entry_data.available)
|
||||||
entry_data.bluetooth_device = client_data.bluetooth_device
|
entry_data.bluetooth_device = client_data.bluetooth_device
|
||||||
client_data.disconnect_callbacks = entry_data.disconnect_callbacks
|
client_data.disconnect_callbacks = entry_data.disconnect_callbacks
|
||||||
scanner = client_data.scanner
|
scanner = client_data.scanner
|
||||||
|
|
|
@ -54,4 +54,4 @@ class EsphomeButton(EsphomeEntity[ButtonInfo, EntityState], ButtonEntity):
|
||||||
|
|
||||||
async def async_press(self) -> None:
|
async def async_press(self) -> None:
|
||||||
"""Press the button."""
|
"""Press the button."""
|
||||||
await self._client.button_command(self._key)
|
self._client.button_command(self._key)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Callable, Coroutine
|
from collections.abc import Callable
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
@ -70,14 +70,14 @@ class EsphomeCamera(Camera, EsphomeEntity[CameraInfo, CameraState]):
|
||||||
return await self._async_request_image(self._client.request_single_image)
|
return await self._async_request_image(self._client.request_single_image)
|
||||||
|
|
||||||
async def _async_request_image(
|
async def _async_request_image(
|
||||||
self, request_method: Callable[[], Coroutine[Any, Any, None]]
|
self, request_method: Callable[[], None]
|
||||||
) -> bytes | None:
|
) -> bytes | None:
|
||||||
"""Wait for an image to be available and return it."""
|
"""Wait for an image to be available and return it."""
|
||||||
if not self.available:
|
if not self.available:
|
||||||
return None
|
return None
|
||||||
image_future = self._loop.create_future()
|
image_future = self._loop.create_future()
|
||||||
self._image_futures.append(image_future)
|
self._image_futures.append(image_future)
|
||||||
await request_method()
|
request_method()
|
||||||
if not await image_future:
|
if not await image_future:
|
||||||
return None
|
return None
|
||||||
return self._state.data
|
return self._state.data
|
||||||
|
|
|
@ -286,15 +286,15 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
||||||
data["target_temperature_low"] = kwargs[ATTR_TARGET_TEMP_LOW]
|
data["target_temperature_low"] = kwargs[ATTR_TARGET_TEMP_LOW]
|
||||||
if ATTR_TARGET_TEMP_HIGH in kwargs:
|
if ATTR_TARGET_TEMP_HIGH in kwargs:
|
||||||
data["target_temperature_high"] = kwargs[ATTR_TARGET_TEMP_HIGH]
|
data["target_temperature_high"] = kwargs[ATTR_TARGET_TEMP_HIGH]
|
||||||
await self._client.climate_command(**data)
|
self._client.climate_command(**data)
|
||||||
|
|
||||||
async def async_set_humidity(self, humidity: int) -> None:
|
async def async_set_humidity(self, humidity: int) -> None:
|
||||||
"""Set new target humidity."""
|
"""Set new target humidity."""
|
||||||
await self._client.climate_command(key=self._key, target_humidity=humidity)
|
self._client.climate_command(key=self._key, target_humidity=humidity)
|
||||||
|
|
||||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||||
"""Set new target operation mode."""
|
"""Set new target operation mode."""
|
||||||
await self._client.climate_command(
|
self._client.climate_command(
|
||||||
key=self._key, mode=_CLIMATE_MODES.from_hass(hvac_mode)
|
key=self._key, mode=_CLIMATE_MODES.from_hass(hvac_mode)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
||||||
kwargs["custom_preset"] = preset_mode
|
kwargs["custom_preset"] = preset_mode
|
||||||
else:
|
else:
|
||||||
kwargs["preset"] = _PRESETS.from_hass(preset_mode)
|
kwargs["preset"] = _PRESETS.from_hass(preset_mode)
|
||||||
await self._client.climate_command(**kwargs)
|
self._client.climate_command(**kwargs)
|
||||||
|
|
||||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||||
"""Set new fan mode."""
|
"""Set new fan mode."""
|
||||||
|
@ -314,10 +314,10 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
|
||||||
kwargs["custom_fan_mode"] = fan_mode
|
kwargs["custom_fan_mode"] = fan_mode
|
||||||
else:
|
else:
|
||||||
kwargs["fan_mode"] = _FAN_MODES.from_hass(fan_mode)
|
kwargs["fan_mode"] = _FAN_MODES.from_hass(fan_mode)
|
||||||
await self._client.climate_command(**kwargs)
|
self._client.climate_command(**kwargs)
|
||||||
|
|
||||||
async def async_set_swing_mode(self, swing_mode: str) -> None:
|
async def async_set_swing_mode(self, swing_mode: str) -> None:
|
||||||
"""Set new swing mode."""
|
"""Set new swing mode."""
|
||||||
await self._client.climate_command(
|
self._client.climate_command(
|
||||||
key=self._key, swing_mode=_SWING_MODES.from_hass(swing_mode)
|
key=self._key, swing_mode=_SWING_MODES.from_hass(swing_mode)
|
||||||
)
|
)
|
||||||
|
|
|
@ -96,31 +96,29 @@ class EsphomeCover(EsphomeEntity[CoverInfo, CoverState], CoverEntity):
|
||||||
|
|
||||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||||
"""Open the cover."""
|
"""Open the cover."""
|
||||||
await self._client.cover_command(key=self._key, position=1.0)
|
self._client.cover_command(key=self._key, position=1.0)
|
||||||
|
|
||||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||||
"""Close cover."""
|
"""Close cover."""
|
||||||
await self._client.cover_command(key=self._key, position=0.0)
|
self._client.cover_command(key=self._key, position=0.0)
|
||||||
|
|
||||||
async def async_stop_cover(self, **kwargs: Any) -> None:
|
async def async_stop_cover(self, **kwargs: Any) -> None:
|
||||||
"""Stop the cover."""
|
"""Stop the cover."""
|
||||||
await self._client.cover_command(key=self._key, stop=True)
|
self._client.cover_command(key=self._key, stop=True)
|
||||||
|
|
||||||
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
||||||
"""Move the cover to a specific position."""
|
"""Move the cover to a specific position."""
|
||||||
await self._client.cover_command(
|
self._client.cover_command(key=self._key, position=kwargs[ATTR_POSITION] / 100)
|
||||||
key=self._key, position=kwargs[ATTR_POSITION] / 100
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_open_cover_tilt(self, **kwargs: Any) -> None:
|
async def async_open_cover_tilt(self, **kwargs: Any) -> None:
|
||||||
"""Open the cover tilt."""
|
"""Open the cover tilt."""
|
||||||
await self._client.cover_command(key=self._key, tilt=1.0)
|
self._client.cover_command(key=self._key, tilt=1.0)
|
||||||
|
|
||||||
async def async_close_cover_tilt(self, **kwargs: Any) -> None:
|
async def async_close_cover_tilt(self, **kwargs: Any) -> None:
|
||||||
"""Close the cover tilt."""
|
"""Close the cover tilt."""
|
||||||
await self._client.cover_command(key=self._key, tilt=0.0)
|
self._client.cover_command(key=self._key, tilt=0.0)
|
||||||
|
|
||||||
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
|
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
|
||||||
"""Move the cover tilt to a specific position."""
|
"""Move the cover tilt to a specific position."""
|
||||||
tilt_position: int = kwargs[ATTR_TILT_POSITION]
|
tilt_position: int = kwargs[ATTR_TILT_POSITION]
|
||||||
await self._client.cover_command(key=self._key, tilt=tilt_position / 100)
|
self._client.cover_command(key=self._key, tilt=tilt_position / 100)
|
||||||
|
|
|
@ -406,7 +406,7 @@ class RuntimeEntryData:
|
||||||
]
|
]
|
||||||
return infos, services
|
return infos, services
|
||||||
|
|
||||||
async def async_save_to_store(self) -> None:
|
def async_save_to_store(self) -> None:
|
||||||
"""Generate dynamic data to store and save it to the filesystem."""
|
"""Generate dynamic data to store and save it to the filesystem."""
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
assert self.device_info is not None
|
assert self.device_info is not None
|
||||||
|
|
|
@ -77,7 +77,7 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity):
|
||||||
ORDERED_NAMED_FAN_SPEEDS, percentage
|
ORDERED_NAMED_FAN_SPEEDS, percentage
|
||||||
)
|
)
|
||||||
data["speed"] = named_speed
|
data["speed"] = named_speed
|
||||||
await self._client.fan_command(**data)
|
self._client.fan_command(**data)
|
||||||
|
|
||||||
async def async_turn_on(
|
async def async_turn_on(
|
||||||
self,
|
self,
|
||||||
|
@ -90,21 +90,21 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity):
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn off the fan."""
|
"""Turn off the fan."""
|
||||||
await self._client.fan_command(key=self._key, state=False)
|
self._client.fan_command(key=self._key, state=False)
|
||||||
|
|
||||||
async def async_oscillate(self, oscillating: bool) -> None:
|
async def async_oscillate(self, oscillating: bool) -> None:
|
||||||
"""Oscillate the fan."""
|
"""Oscillate the fan."""
|
||||||
await self._client.fan_command(key=self._key, oscillating=oscillating)
|
self._client.fan_command(key=self._key, oscillating=oscillating)
|
||||||
|
|
||||||
async def async_set_direction(self, direction: str) -> None:
|
async def async_set_direction(self, direction: str) -> None:
|
||||||
"""Set direction of the fan."""
|
"""Set direction of the fan."""
|
||||||
await self._client.fan_command(
|
self._client.fan_command(
|
||||||
key=self._key, direction=_FAN_DIRECTIONS.from_hass(direction)
|
key=self._key, direction=_FAN_DIRECTIONS.from_hass(direction)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||||
"""Set the preset mode of the fan."""
|
"""Set the preset mode of the fan."""
|
||||||
await self._client.fan_command(key=self._key, preset_mode=preset_mode)
|
self._client.fan_command(key=self._key, preset_mode=preset_mode)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@esphome_state_property
|
@esphome_state_property
|
||||||
|
|
|
@ -285,7 +285,7 @@ class EsphomeLight(EsphomeEntity[LightInfo, LightState], LightEntity):
|
||||||
# (fewest capabilities set)
|
# (fewest capabilities set)
|
||||||
data["color_mode"] = _least_complex_color_mode(color_modes)
|
data["color_mode"] = _least_complex_color_mode(color_modes)
|
||||||
|
|
||||||
await self._client.light_command(**data)
|
self._client.light_command(**data)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity off."""
|
"""Turn the entity off."""
|
||||||
|
@ -294,7 +294,7 @@ class EsphomeLight(EsphomeEntity[LightInfo, LightState], LightEntity):
|
||||||
data["flash_length"] = FLASH_LENGTHS[kwargs[ATTR_FLASH]]
|
data["flash_length"] = FLASH_LENGTHS[kwargs[ATTR_FLASH]]
|
||||||
if ATTR_TRANSITION in kwargs:
|
if ATTR_TRANSITION in kwargs:
|
||||||
data["transition_length"] = kwargs[ATTR_TRANSITION]
|
data["transition_length"] = kwargs[ATTR_TRANSITION]
|
||||||
await self._client.light_command(**data)
|
self._client.light_command(**data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@esphome_state_property
|
@esphome_state_property
|
||||||
|
|
|
@ -71,13 +71,13 @@ class EsphomeLock(EsphomeEntity[LockInfo, LockEntityState], LockEntity):
|
||||||
|
|
||||||
async def async_lock(self, **kwargs: Any) -> None:
|
async def async_lock(self, **kwargs: Any) -> None:
|
||||||
"""Lock the lock."""
|
"""Lock the lock."""
|
||||||
await self._client.lock_command(self._key, LockCommand.LOCK)
|
self._client.lock_command(self._key, LockCommand.LOCK)
|
||||||
|
|
||||||
async def async_unlock(self, **kwargs: Any) -> None:
|
async def async_unlock(self, **kwargs: Any) -> None:
|
||||||
"""Unlock the lock."""
|
"""Unlock the lock."""
|
||||||
code = kwargs.get(ATTR_CODE, None)
|
code = kwargs.get(ATTR_CODE, None)
|
||||||
await self._client.lock_command(self._key, LockCommand.UNLOCK, code)
|
self._client.lock_command(self._key, LockCommand.UNLOCK, code)
|
||||||
|
|
||||||
async def async_open(self, **kwargs: Any) -> None:
|
async def async_open(self, **kwargs: Any) -> None:
|
||||||
"""Open the door latch."""
|
"""Open the door latch."""
|
||||||
await self._client.lock_command(self._key, LockCommand.OPEN)
|
self._client.lock_command(self._key, LockCommand.OPEN)
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Coroutine
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||||
|
@ -33,14 +32,7 @@ from homeassistant.const import (
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
EVENT_LOGGING_CHANGED,
|
EVENT_LOGGING_CHANGED,
|
||||||
)
|
)
|
||||||
from homeassistant.core import (
|
from homeassistant.core import Event, HomeAssistant, ServiceCall, State, callback
|
||||||
CALLBACK_TYPE,
|
|
||||||
Event,
|
|
||||||
HomeAssistant,
|
|
||||||
ServiceCall,
|
|
||||||
State,
|
|
||||||
callback,
|
|
||||||
)
|
|
||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
from homeassistant.helpers import template
|
from homeassistant.helpers import template
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
@ -266,7 +258,8 @@ class ESPHomeManager:
|
||||||
service_data,
|
service_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _send_home_assistant_state(
|
@callback
|
||||||
|
def _send_home_assistant_state(
|
||||||
self, entity_id: str, attribute: str | None, state: State | None
|
self, entity_id: str, attribute: str | None, state: State | None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Forward Home Assistant states to ESPHome."""
|
"""Forward Home Assistant states to ESPHome."""
|
||||||
|
@ -282,9 +275,10 @@ class ESPHomeManager:
|
||||||
else:
|
else:
|
||||||
send_state = attr_val
|
send_state = attr_val
|
||||||
|
|
||||||
await self.cli.send_home_assistant_state(entity_id, attribute, str(send_state))
|
self.cli.send_home_assistant_state(entity_id, attribute, str(send_state))
|
||||||
|
|
||||||
async def _send_home_assistant_state_event(
|
@callback
|
||||||
|
def _send_home_assistant_state_event(
|
||||||
self,
|
self,
|
||||||
attribute: str | None,
|
attribute: str | None,
|
||||||
event: EventType[EventStateChangedData],
|
event: EventType[EventStateChangedData],
|
||||||
|
@ -305,9 +299,7 @@ class ESPHomeManager:
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
await self._send_home_assistant_state(
|
self._send_home_assistant_state(event.data["entity_id"], attribute, new_state)
|
||||||
event.data["entity_id"], attribute, new_state
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_on_state_subscription(
|
def async_on_state_subscription(
|
||||||
|
@ -323,10 +315,8 @@ class ESPHomeManager:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Send initial state
|
# Send initial state
|
||||||
hass.async_create_task(
|
self._send_home_assistant_state(
|
||||||
self._send_home_assistant_state(
|
entity_id, attribute, hass.states.get(entity_id)
|
||||||
entity_id, attribute, hass.states.get(entity_id)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _handle_pipeline_finished(self) -> None:
|
def _handle_pipeline_finished(self) -> None:
|
||||||
|
@ -461,44 +451,33 @@ class ESPHomeManager:
|
||||||
reconnect_logic.name = device_info.name
|
reconnect_logic.name = device_info.name
|
||||||
|
|
||||||
self.device_id = _async_setup_device_registry(hass, entry, entry_data)
|
self.device_id = _async_setup_device_registry(hass, entry, entry_data)
|
||||||
|
|
||||||
entry_data.async_update_device_state(hass)
|
entry_data.async_update_device_state(hass)
|
||||||
await entry_data.async_update_static_infos(
|
await entry_data.async_update_static_infos(
|
||||||
hass, entry, entity_infos, device_info.mac_address
|
hass, entry, entity_infos, device_info.mac_address
|
||||||
)
|
)
|
||||||
_setup_services(hass, entry_data, services)
|
_setup_services(hass, entry_data, services)
|
||||||
|
|
||||||
setup_coros_with_disconnect_callbacks: list[
|
|
||||||
Coroutine[Any, Any, CALLBACK_TYPE]
|
|
||||||
] = []
|
|
||||||
if device_info.bluetooth_proxy_feature_flags_compat(api_version):
|
if device_info.bluetooth_proxy_feature_flags_compat(api_version):
|
||||||
setup_coros_with_disconnect_callbacks.append(
|
entry_data.disconnect_callbacks.add(
|
||||||
async_connect_scanner(
|
async_connect_scanner(
|
||||||
hass, entry_data, cli, device_info, self.domain_data.bluetooth_cache
|
hass, entry_data, cli, device_info, self.domain_data.bluetooth_cache
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if device_info.voice_assistant_version:
|
if device_info.voice_assistant_version:
|
||||||
setup_coros_with_disconnect_callbacks.append(
|
entry_data.disconnect_callbacks.add(
|
||||||
cli.subscribe_voice_assistant(
|
cli.subscribe_voice_assistant(
|
||||||
self._handle_pipeline_start,
|
self._handle_pipeline_start,
|
||||||
self._handle_pipeline_stop,
|
self._handle_pipeline_stop,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
setup_results = await asyncio.gather(
|
cli.subscribe_states(entry_data.async_update_state)
|
||||||
*setup_coros_with_disconnect_callbacks,
|
cli.subscribe_service_calls(self.async_on_service_call)
|
||||||
cli.subscribe_states(entry_data.async_update_state),
|
cli.subscribe_home_assistant_states(self.async_on_state_subscription)
|
||||||
cli.subscribe_service_calls(self.async_on_service_call),
|
|
||||||
cli.subscribe_home_assistant_states(self.async_on_state_subscription),
|
|
||||||
)
|
|
||||||
|
|
||||||
for result_idx in range(len(setup_coros_with_disconnect_callbacks)):
|
entry_data.async_save_to_store()
|
||||||
cancel_callback = setup_results[result_idx]
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
assert cancel_callback is not None
|
|
||||||
entry_data.disconnect_callbacks.add(cancel_callback)
|
|
||||||
|
|
||||||
hass.async_create_task(entry_data.async_save_to_store())
|
|
||||||
_async_check_firmware_version(hass, device_info, api_version)
|
_async_check_firmware_version(hass, device_info, api_version)
|
||||||
_async_check_using_api_password(hass, device_info, bool(self.password))
|
_async_check_using_api_password(hass, device_info, bool(self.password))
|
||||||
|
|
||||||
|
@ -706,11 +685,12 @@ ARG_TYPE_METADATA = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def execute_service(
|
@callback
|
||||||
|
def execute_service(
|
||||||
entry_data: RuntimeEntryData, service: UserService, call: ServiceCall
|
entry_data: RuntimeEntryData, service: UserService, call: ServiceCall
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Execute a service on a node."""
|
"""Execute a service on a node."""
|
||||||
await entry_data.client.execute_service(service, call.data)
|
entry_data.client.execute_service(service, call.data)
|
||||||
|
|
||||||
|
|
||||||
def build_service_name(device_info: EsphomeDeviceInfo, service: UserService) -> str:
|
def build_service_name(device_info: EsphomeDeviceInfo, service: UserService) -> str:
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["aioesphomeapi", "noiseprotocol", "bleak_esphome"],
|
"loggers": ["aioesphomeapi", "noiseprotocol", "bleak_esphome"],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"aioesphomeapi==21.0.3",
|
"aioesphomeapi==22.0.0",
|
||||||
"esphome-dashboard-api==1.2.3",
|
"esphome-dashboard-api==1.2.3",
|
||||||
"bleak-esphome==0.4.1"
|
"bleak-esphome==1.0.0"
|
||||||
],
|
],
|
||||||
"zeroconf": ["_esphomelib._tcp.local."]
|
"zeroconf": ["_esphomelib._tcp.local."]
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ class EsphomeMediaPlayer(
|
||||||
|
|
||||||
media_id = async_process_play_media_url(self.hass, media_id)
|
media_id = async_process_play_media_url(self.hass, media_id)
|
||||||
|
|
||||||
await self._client.media_player_command(
|
self._client.media_player_command(
|
||||||
self._key,
|
self._key,
|
||||||
media_url=media_id,
|
media_url=media_id,
|
||||||
)
|
)
|
||||||
|
@ -125,29 +125,23 @@ class EsphomeMediaPlayer(
|
||||||
|
|
||||||
async def async_set_volume_level(self, volume: float) -> None:
|
async def async_set_volume_level(self, volume: float) -> None:
|
||||||
"""Set volume level, range 0..1."""
|
"""Set volume level, range 0..1."""
|
||||||
await self._client.media_player_command(self._key, volume=volume)
|
self._client.media_player_command(self._key, volume=volume)
|
||||||
|
|
||||||
async def async_media_pause(self) -> None:
|
async def async_media_pause(self) -> None:
|
||||||
"""Send pause command."""
|
"""Send pause command."""
|
||||||
await self._client.media_player_command(
|
self._client.media_player_command(self._key, command=MediaPlayerCommand.PAUSE)
|
||||||
self._key, command=MediaPlayerCommand.PAUSE
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_media_play(self) -> None:
|
async def async_media_play(self) -> None:
|
||||||
"""Send play command."""
|
"""Send play command."""
|
||||||
await self._client.media_player_command(
|
self._client.media_player_command(self._key, command=MediaPlayerCommand.PLAY)
|
||||||
self._key, command=MediaPlayerCommand.PLAY
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_media_stop(self) -> None:
|
async def async_media_stop(self) -> None:
|
||||||
"""Send stop command."""
|
"""Send stop command."""
|
||||||
await self._client.media_player_command(
|
self._client.media_player_command(self._key, command=MediaPlayerCommand.STOP)
|
||||||
self._key, command=MediaPlayerCommand.STOP
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_mute_volume(self, mute: bool) -> None:
|
async def async_mute_volume(self, mute: bool) -> None:
|
||||||
"""Mute the volume."""
|
"""Mute the volume."""
|
||||||
await self._client.media_player_command(
|
self._client.media_player_command(
|
||||||
self._key,
|
self._key,
|
||||||
command=MediaPlayerCommand.MUTE if mute else MediaPlayerCommand.UNMUTE,
|
command=MediaPlayerCommand.MUTE if mute else MediaPlayerCommand.UNMUTE,
|
||||||
)
|
)
|
||||||
|
|
|
@ -79,4 +79,4 @@ class EsphomeNumber(EsphomeEntity[NumberInfo, NumberState], NumberEntity):
|
||||||
|
|
||||||
async def async_set_native_value(self, value: float) -> None:
|
async def async_set_native_value(self, value: float) -> None:
|
||||||
"""Update the current value."""
|
"""Update the current value."""
|
||||||
await self._client.number_command(self._key, value)
|
self._client.number_command(self._key, value)
|
||||||
|
|
|
@ -67,7 +67,7 @@ class EsphomeSelect(EsphomeEntity[SelectInfo, SelectState], SelectEntity):
|
||||||
|
|
||||||
async def async_select_option(self, option: str) -> None:
|
async def async_select_option(self, option: str) -> None:
|
||||||
"""Change the selected option."""
|
"""Change the selected option."""
|
||||||
await self._client.select_command(self._key, option)
|
self._client.select_command(self._key, option)
|
||||||
|
|
||||||
|
|
||||||
class EsphomeAssistPipelineSelect(EsphomeAssistEntity, AssistPipelineSelect):
|
class EsphomeAssistPipelineSelect(EsphomeAssistEntity, AssistPipelineSelect):
|
||||||
|
|
|
@ -49,8 +49,8 @@ class EsphomeSwitch(EsphomeEntity[SwitchInfo, SwitchState], SwitchEntity):
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity on."""
|
"""Turn the entity on."""
|
||||||
await self._client.switch_command(self._key, True)
|
self._client.switch_command(self._key, True)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the entity off."""
|
"""Turn the entity off."""
|
||||||
await self._client.switch_command(self._key, False)
|
self._client.switch_command(self._key, False)
|
||||||
|
|
|
@ -60,4 +60,4 @@ class EsphomeText(EsphomeEntity[TextInfo, TextState], TextEntity):
|
||||||
|
|
||||||
async def async_set_value(self, value: str) -> None:
|
async def async_set_value(self, value: str) -> None:
|
||||||
"""Update the current value."""
|
"""Update the current value."""
|
||||||
await self._client.text_command(self._key, value)
|
self._client.text_command(self._key, value)
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from aioesphomeapi import DeviceInfo as ESPHomeDeviceInfo, EntityInfo
|
from aioesphomeapi import DeviceInfo as ESPHomeDeviceInfo, EntityInfo
|
||||||
|
@ -29,8 +28,6 @@ KEY_UPDATE_LOCK = "esphome_update_lock"
|
||||||
|
|
||||||
NO_FEATURES = UpdateEntityFeature(0)
|
NO_FEATURES = UpdateEntityFeature(0)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
|
|
@ -245,7 +245,7 @@ aioelectricitymaps==0.4.0
|
||||||
aioemonitor==1.0.5
|
aioemonitor==1.0.5
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
# homeassistant.components.esphome
|
||||||
aioesphomeapi==21.0.3
|
aioesphomeapi==22.0.0
|
||||||
|
|
||||||
# homeassistant.components.flo
|
# homeassistant.components.flo
|
||||||
aioflo==2021.11.0
|
aioflo==2021.11.0
|
||||||
|
@ -550,7 +550,7 @@ bimmer-connected[china]==0.14.6
|
||||||
bizkaibus==0.1.1
|
bizkaibus==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
# homeassistant.components.esphome
|
||||||
bleak-esphome==0.4.1
|
bleak-esphome==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bleak-retry-connector==3.4.0
|
bleak-retry-connector==3.4.0
|
||||||
|
|
|
@ -224,7 +224,7 @@ aioelectricitymaps==0.4.0
|
||||||
aioemonitor==1.0.5
|
aioemonitor==1.0.5
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
# homeassistant.components.esphome
|
||||||
aioesphomeapi==21.0.3
|
aioesphomeapi==22.0.0
|
||||||
|
|
||||||
# homeassistant.components.flo
|
# homeassistant.components.flo
|
||||||
aioflo==2021.11.0
|
aioflo==2021.11.0
|
||||||
|
@ -469,7 +469,7 @@ bellows==0.38.0
|
||||||
bimmer-connected[china]==0.14.6
|
bimmer-connected[china]==0.14.6
|
||||||
|
|
||||||
# homeassistant.components.esphome
|
# homeassistant.components.esphome
|
||||||
bleak-esphome==0.4.1
|
bleak-esphome==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
bleak-retry-connector==3.4.0
|
bleak-retry-connector==3.4.0
|
||||||
|
|
|
@ -269,26 +269,26 @@ async def _mock_generic_device_entry(
|
||||||
}
|
}
|
||||||
device_info = DeviceInfo(**(default_device_info | mock_device_info))
|
device_info = DeviceInfo(**(default_device_info | mock_device_info))
|
||||||
|
|
||||||
async def _subscribe_states(callback: Callable[[EntityState], None]) -> None:
|
def _subscribe_states(callback: Callable[[EntityState], None]) -> None:
|
||||||
"""Subscribe to state."""
|
"""Subscribe to state."""
|
||||||
mock_device.set_state_callback(callback)
|
mock_device.set_state_callback(callback)
|
||||||
for state in states:
|
for state in states:
|
||||||
callback(state)
|
callback(state)
|
||||||
|
|
||||||
async def _subscribe_service_calls(
|
def _subscribe_service_calls(
|
||||||
callback: Callable[[HomeassistantServiceCall], None],
|
callback: Callable[[HomeassistantServiceCall], None],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Subscribe to service calls."""
|
"""Subscribe to service calls."""
|
||||||
mock_device.set_service_call_callback(callback)
|
mock_device.set_service_call_callback(callback)
|
||||||
|
|
||||||
async def _subscribe_home_assistant_states(
|
def _subscribe_home_assistant_states(
|
||||||
on_state_sub: Callable[[str, str | None], None],
|
on_state_sub: Callable[[str, str | None], None],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Subscribe to home assistant states."""
|
"""Subscribe to home assistant states."""
|
||||||
mock_device.set_home_assistant_state_subscription_callback(on_state_sub)
|
mock_device.set_home_assistant_state_subscription_callback(on_state_sub)
|
||||||
|
|
||||||
mock_client.device_info = AsyncMock(return_value=device_info)
|
mock_client.device_info = AsyncMock(return_value=device_info)
|
||||||
mock_client.subscribe_voice_assistant = AsyncMock(return_value=Mock())
|
mock_client.subscribe_voice_assistant = Mock()
|
||||||
mock_client.list_entities_services = AsyncMock(
|
mock_client.list_entities_services = AsyncMock(
|
||||||
return_value=mock_list_entities_services
|
return_value=mock_list_entities_services
|
||||||
)
|
)
|
||||||
|
|
|
@ -56,7 +56,7 @@ async def test_camera_single_image(
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_IDLE
|
assert state.state == STATE_IDLE
|
||||||
|
|
||||||
async def _mock_camera_image():
|
def _mock_camera_image():
|
||||||
mock_device.set_state(CameraState(key=1, data=SMALLEST_VALID_JPEG_BYTES))
|
mock_device.set_state(CameraState(key=1, data=SMALLEST_VALID_JPEG_BYTES))
|
||||||
|
|
||||||
mock_client.request_single_image = _mock_camera_image
|
mock_client.request_single_image = _mock_camera_image
|
||||||
|
@ -145,8 +145,8 @@ async def test_camera_single_image_unavailable_during_request(
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_IDLE
|
assert state.state == STATE_IDLE
|
||||||
|
|
||||||
async def _mock_camera_image():
|
def _mock_camera_image():
|
||||||
await mock_device.mock_disconnect(False)
|
hass.async_create_task(mock_device.mock_disconnect(False))
|
||||||
|
|
||||||
mock_client.request_single_image = _mock_camera_image
|
mock_client.request_single_image = _mock_camera_image
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ async def test_camera_stream(
|
||||||
assert state.state == STATE_IDLE
|
assert state.state == STATE_IDLE
|
||||||
remaining_responses = 3
|
remaining_responses = 3
|
||||||
|
|
||||||
async def _mock_camera_image():
|
def _mock_camera_image():
|
||||||
nonlocal remaining_responses
|
nonlocal remaining_responses
|
||||||
if remaining_responses == 0:
|
if remaining_responses == 0:
|
||||||
return
|
return
|
||||||
|
@ -291,12 +291,12 @@ async def test_camera_stream_with_disconnection(
|
||||||
assert state.state == STATE_IDLE
|
assert state.state == STATE_IDLE
|
||||||
remaining_responses = 3
|
remaining_responses = 3
|
||||||
|
|
||||||
async def _mock_camera_image():
|
def _mock_camera_image():
|
||||||
nonlocal remaining_responses
|
nonlocal remaining_responses
|
||||||
if remaining_responses == 0:
|
if remaining_responses == 0:
|
||||||
return
|
return
|
||||||
if remaining_responses == 2:
|
if remaining_responses == 2:
|
||||||
await mock_device.mock_disconnect(False)
|
hass.async_create_task(mock_device.mock_disconnect(False))
|
||||||
remaining_responses -= 1
|
remaining_responses -= 1
|
||||||
mock_device.set_state(CameraState(key=1, data=SMALLEST_VALID_JPEG_BYTES))
|
mock_device.set_state(CameraState(key=1, data=SMALLEST_VALID_JPEG_BYTES))
|
||||||
|
|
||||||
|
|
|
@ -357,7 +357,7 @@ async def test_unique_id_updated_to_mac(
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
subscribe_done = hass.loop.create_future()
|
subscribe_done = hass.loop.create_future()
|
||||||
|
|
||||||
async def async_subscribe_states(*args, **kwargs) -> None:
|
def async_subscribe_states(*args, **kwargs) -> None:
|
||||||
subscribe_done.set_result(None)
|
subscribe_done.set_result(None)
|
||||||
|
|
||||||
mock_client.subscribe_states = async_subscribe_states
|
mock_client.subscribe_states = async_subscribe_states
|
||||||
|
@ -392,7 +392,7 @@ async def test_unique_id_not_updated_if_name_same_and_already_mac(
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
disconnect_done = hass.loop.create_future()
|
disconnect_done = hass.loop.create_future()
|
||||||
|
|
||||||
async def async_disconnect(*args, **kwargs) -> None:
|
def async_disconnect(*args, **kwargs) -> None:
|
||||||
disconnect_done.set_result(None)
|
disconnect_done.set_result(None)
|
||||||
|
|
||||||
mock_client.disconnect = async_disconnect
|
mock_client.disconnect = async_disconnect
|
||||||
|
@ -421,7 +421,7 @@ async def test_unique_id_updated_if_name_unset_and_already_mac(
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
disconnect_done = hass.loop.create_future()
|
disconnect_done = hass.loop.create_future()
|
||||||
|
|
||||||
async def async_disconnect(*args, **kwargs) -> None:
|
def async_disconnect(*args, **kwargs) -> None:
|
||||||
disconnect_done.set_result(None)
|
disconnect_done.set_result(None)
|
||||||
|
|
||||||
mock_client.disconnect = async_disconnect
|
mock_client.disconnect = async_disconnect
|
||||||
|
@ -455,7 +455,7 @@ async def test_unique_id_not_updated_if_name_different_and_already_mac(
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
disconnect_done = hass.loop.create_future()
|
disconnect_done = hass.loop.create_future()
|
||||||
|
|
||||||
async def async_disconnect(*args, **kwargs) -> None:
|
def async_disconnect(*args, **kwargs) -> None:
|
||||||
disconnect_done.set_result(None)
|
disconnect_done.set_result(None)
|
||||||
|
|
||||||
mock_client.disconnect = async_disconnect
|
mock_client.disconnect = async_disconnect
|
||||||
|
@ -491,7 +491,7 @@ async def test_name_updated_only_if_mac_matches(
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
subscribe_done = hass.loop.create_future()
|
subscribe_done = hass.loop.create_future()
|
||||||
|
|
||||||
async def async_subscribe_states(*args, **kwargs) -> None:
|
def async_subscribe_states(*args, **kwargs) -> None:
|
||||||
subscribe_done.set_result(None)
|
subscribe_done.set_result(None)
|
||||||
|
|
||||||
mock_client.subscribe_states = async_subscribe_states
|
mock_client.subscribe_states = async_subscribe_states
|
||||||
|
@ -525,7 +525,7 @@ async def test_name_updated_only_if_mac_was_unset(
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
subscribe_done = hass.loop.create_future()
|
subscribe_done = hass.loop.create_future()
|
||||||
|
|
||||||
async def async_subscribe_states(*args, **kwargs) -> None:
|
def async_subscribe_states(*args, **kwargs) -> None:
|
||||||
subscribe_done.set_result(None)
|
subscribe_done.set_result(None)
|
||||||
|
|
||||||
mock_client.subscribe_states = async_subscribe_states
|
mock_client.subscribe_states = async_subscribe_states
|
||||||
|
@ -562,7 +562,7 @@ async def test_connection_aborted_wrong_device(
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
disconnect_done = hass.loop.create_future()
|
disconnect_done = hass.loop.create_future()
|
||||||
|
|
||||||
async def async_disconnect(*args, **kwargs) -> None:
|
def async_disconnect(*args, **kwargs) -> None:
|
||||||
disconnect_done.set_result(None)
|
disconnect_done.set_result(None)
|
||||||
|
|
||||||
mock_client.disconnect = async_disconnect
|
mock_client.disconnect = async_disconnect
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue