Add device_id parameter to ESPHome command calls for sub-device support (#148667)

This commit is contained in:
J. Nick Koston 2025-07-12 20:12:14 -10:00 committed by GitHub
parent 1c35aff510
commit 87fd45d4ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 458 additions and 135 deletions

View File

@ -100,49 +100,70 @@ class EsphomeAlarmControlPanel(
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
self._client.alarm_control_panel_command(
self._key, AlarmControlPanelCommand.DISARM, code
self._key,
AlarmControlPanelCommand.DISARM,
code,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
self._client.alarm_control_panel_command(
self._key, AlarmControlPanelCommand.ARM_HOME, code
self._key,
AlarmControlPanelCommand.ARM_HOME,
code,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
self._client.alarm_control_panel_command(
self._key, AlarmControlPanelCommand.ARM_AWAY, code
self._key,
AlarmControlPanelCommand.ARM_AWAY,
code,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm away command."""
self._client.alarm_control_panel_command(
self._key, AlarmControlPanelCommand.ARM_NIGHT, code
self._key,
AlarmControlPanelCommand.ARM_NIGHT,
code,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Send arm away command."""
self._client.alarm_control_panel_command(
self._key, AlarmControlPanelCommand.ARM_CUSTOM_BYPASS, code
self._key,
AlarmControlPanelCommand.ARM_CUSTOM_BYPASS,
code,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
"""Send arm away command."""
self._client.alarm_control_panel_command(
self._key, AlarmControlPanelCommand.ARM_VACATION, code
self._key,
AlarmControlPanelCommand.ARM_VACATION,
code,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_alarm_trigger(self, code: str | None = None) -> None:
"""Send alarm trigger command."""
self._client.alarm_control_panel_command(
self._key, AlarmControlPanelCommand.TRIGGER, code
self._key,
AlarmControlPanelCommand.TRIGGER,
code,
device_id=self._static_info.device_id,
)

View File

@ -48,7 +48,7 @@ class EsphomeButton(EsphomeEntity[ButtonInfo, EntityState], ButtonEntity):
@convert_api_error_ha_error
async def async_press(self) -> None:
"""Press the button."""
self._client.button_command(self._key)
self._client.button_command(self._key, device_id=self._static_info.device_id)
async_setup_entry = partial(

View File

@ -287,18 +287,24 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
data["target_temperature_low"] = kwargs[ATTR_TARGET_TEMP_LOW]
if ATTR_TARGET_TEMP_HIGH in kwargs:
data["target_temperature_high"] = kwargs[ATTR_TARGET_TEMP_HIGH]
self._client.climate_command(**data)
self._client.climate_command(**data, device_id=self._static_info.device_id)
@convert_api_error_ha_error
async def async_set_humidity(self, humidity: int) -> None:
"""Set new target humidity."""
self._client.climate_command(key=self._key, target_humidity=humidity)
self._client.climate_command(
key=self._key,
target_humidity=humidity,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target operation mode."""
self._client.climate_command(
key=self._key, mode=_CLIMATE_MODES.from_hass(hvac_mode)
key=self._key,
mode=_CLIMATE_MODES.from_hass(hvac_mode),
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
@ -309,7 +315,7 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
kwargs["custom_preset"] = preset_mode
else:
kwargs["preset"] = _PRESETS.from_hass(preset_mode)
self._client.climate_command(**kwargs)
self._client.climate_command(**kwargs, device_id=self._static_info.device_id)
@convert_api_error_ha_error
async def async_set_fan_mode(self, fan_mode: str) -> None:
@ -319,13 +325,15 @@ class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEnti
kwargs["custom_fan_mode"] = fan_mode
else:
kwargs["fan_mode"] = _FAN_MODES.from_hass(fan_mode)
self._client.climate_command(**kwargs)
self._client.climate_command(**kwargs, device_id=self._static_info.device_id)
@convert_api_error_ha_error
async def async_set_swing_mode(self, swing_mode: str) -> None:
"""Set new swing mode."""
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),
device_id=self._static_info.device_id,
)

View File

@ -90,38 +90,56 @@ class EsphomeCover(EsphomeEntity[CoverInfo, CoverState], CoverEntity):
@convert_api_error_ha_error
async def async_open_cover(self, **kwargs: Any) -> None:
"""Open the cover."""
self._client.cover_command(key=self._key, position=1.0)
self._client.cover_command(
key=self._key, position=1.0, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_close_cover(self, **kwargs: Any) -> None:
"""Close cover."""
self._client.cover_command(key=self._key, position=0.0)
self._client.cover_command(
key=self._key, position=0.0, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_stop_cover(self, **kwargs: Any) -> None:
"""Stop the cover."""
self._client.cover_command(key=self._key, stop=True)
self._client.cover_command(
key=self._key, stop=True, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_set_cover_position(self, **kwargs: Any) -> None:
"""Move the cover to a specific position."""
self._client.cover_command(key=self._key, position=kwargs[ATTR_POSITION] / 100)
self._client.cover_command(
key=self._key,
position=kwargs[ATTR_POSITION] / 100,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_open_cover_tilt(self, **kwargs: Any) -> None:
"""Open the cover tilt."""
self._client.cover_command(key=self._key, tilt=1.0)
self._client.cover_command(
key=self._key, tilt=1.0, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_close_cover_tilt(self, **kwargs: Any) -> None:
"""Close the cover tilt."""
self._client.cover_command(key=self._key, tilt=0.0)
self._client.cover_command(
key=self._key, tilt=0.0, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_set_cover_tilt_position(self, **kwargs: Any) -> None:
"""Move the cover tilt to a specific position."""
tilt_position: int = kwargs[ATTR_TILT_POSITION]
self._client.cover_command(key=self._key, tilt=tilt_position / 100)
self._client.cover_command(
key=self._key,
tilt=tilt_position / 100,
device_id=self._static_info.device_id,
)
async_setup_entry = partial(

View File

@ -28,7 +28,13 @@ class EsphomeDate(EsphomeEntity[DateInfo, DateState], DateEntity):
async def async_set_value(self, value: date) -> None:
"""Update the current date."""
self._client.date_command(self._key, value.year, value.month, value.day)
self._client.date_command(
self._key,
value.year,
value.month,
value.day,
device_id=self._static_info.device_id,
)
async_setup_entry = partial(

View File

@ -29,7 +29,9 @@ class EsphomeDateTime(EsphomeEntity[DateTimeInfo, DateTimeState], DateTimeEntity
async def async_set_value(self, value: datetime) -> None:
"""Update the current datetime."""
self._client.datetime_command(self._key, int(value.timestamp()))
self._client.datetime_command(
self._key, int(value.timestamp()), device_id=self._static_info.device_id
)
async_setup_entry = partial(

View File

@ -71,7 +71,7 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity):
ORDERED_NAMED_FAN_SPEEDS, percentage
)
data["speed"] = named_speed
self._client.fan_command(**data)
self._client.fan_command(**data, device_id=self._static_info.device_id)
async def async_turn_on(
self,
@ -85,24 +85,36 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity):
@convert_api_error_ha_error
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the fan."""
self._client.fan_command(key=self._key, state=False)
self._client.fan_command(
key=self._key, state=False, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_oscillate(self, oscillating: bool) -> None:
"""Oscillate the fan."""
self._client.fan_command(key=self._key, oscillating=oscillating)
self._client.fan_command(
key=self._key,
oscillating=oscillating,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_set_direction(self, direction: str) -> None:
"""Set direction of the fan."""
self._client.fan_command(
key=self._key, direction=_FAN_DIRECTIONS.from_hass(direction)
key=self._key,
direction=_FAN_DIRECTIONS.from_hass(direction),
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode of the fan."""
self._client.fan_command(key=self._key, preset_mode=preset_mode)
self._client.fan_command(
key=self._key,
preset_mode=preset_mode,
device_id=self._static_info.device_id,
)
@property
@esphome_state_property

View File

@ -280,7 +280,7 @@ class EsphomeLight(EsphomeEntity[LightInfo, LightState], LightEntity):
# (fewest capabilities set)
data["color_mode"] = _least_complex_color_mode(color_modes)
self._client.light_command(**data)
self._client.light_command(**data, device_id=self._static_info.device_id)
@convert_api_error_ha_error
async def async_turn_off(self, **kwargs: Any) -> None:
@ -290,7 +290,7 @@ class EsphomeLight(EsphomeEntity[LightInfo, LightState], LightEntity):
data["flash_length"] = FLASH_LENGTHS[kwargs[ATTR_FLASH]]
if ATTR_TRANSITION in kwargs:
data["transition_length"] = kwargs[ATTR_TRANSITION]
self._client.light_command(**data)
self._client.light_command(**data, device_id=self._static_info.device_id)
@property
@esphome_state_property

View File

@ -65,18 +65,24 @@ class EsphomeLock(EsphomeEntity[LockInfo, LockEntityState], LockEntity):
@convert_api_error_ha_error
async def async_lock(self, **kwargs: Any) -> None:
"""Lock the lock."""
self._client.lock_command(self._key, LockCommand.LOCK)
self._client.lock_command(
self._key, LockCommand.LOCK, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_unlock(self, **kwargs: Any) -> None:
"""Unlock the lock."""
code = kwargs.get(ATTR_CODE)
self._client.lock_command(self._key, LockCommand.UNLOCK, code)
self._client.lock_command(
self._key, LockCommand.UNLOCK, code, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_open(self, **kwargs: Any) -> None:
"""Open the door latch."""
self._client.lock_command(self._key, LockCommand.OPEN)
self._client.lock_command(
self._key, LockCommand.OPEN, device_id=self._static_info.device_id
)
async_setup_entry = partial(

View File

@ -132,7 +132,10 @@ class EsphomeMediaPlayer(
media_id = proxy_url
self._client.media_player_command(
self._key, media_url=media_id, announcement=announcement
self._key,
media_url=media_id,
announcement=announcement,
device_id=self._static_info.device_id,
)
async def async_will_remove_from_hass(self) -> None:
@ -214,22 +217,36 @@ class EsphomeMediaPlayer(
@convert_api_error_ha_error
async def async_set_volume_level(self, volume: float) -> None:
"""Set volume level, range 0..1."""
self._client.media_player_command(self._key, volume=volume)
self._client.media_player_command(
self._key, volume=volume, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_media_pause(self) -> None:
"""Send pause command."""
self._client.media_player_command(self._key, command=MediaPlayerCommand.PAUSE)
self._client.media_player_command(
self._key,
command=MediaPlayerCommand.PAUSE,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_media_play(self) -> None:
"""Send play command."""
self._client.media_player_command(self._key, command=MediaPlayerCommand.PLAY)
self._client.media_player_command(
self._key,
command=MediaPlayerCommand.PLAY,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_media_stop(self) -> None:
"""Send stop command."""
self._client.media_player_command(self._key, command=MediaPlayerCommand.STOP)
self._client.media_player_command(
self._key,
command=MediaPlayerCommand.STOP,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_mute_volume(self, mute: bool) -> None:
@ -237,6 +254,7 @@ class EsphomeMediaPlayer(
self._client.media_player_command(
self._key,
command=MediaPlayerCommand.MUTE if mute else MediaPlayerCommand.UNMUTE,
device_id=self._static_info.device_id,
)

View File

@ -67,7 +67,9 @@ class EsphomeNumber(EsphomeEntity[NumberInfo, NumberState], NumberEntity):
@convert_api_error_ha_error
async def async_set_native_value(self, value: float) -> None:
"""Update the current value."""
self._client.number_command(self._key, value)
self._client.number_command(
self._key, value, device_id=self._static_info.device_id
)
async_setup_entry = partial(

View File

@ -76,7 +76,9 @@ class EsphomeSelect(EsphomeEntity[SelectInfo, SelectState], SelectEntity):
@convert_api_error_ha_error
async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
self._client.select_command(self._key, option)
self._client.select_command(
self._key, option, device_id=self._static_info.device_id
)
class EsphomeAssistPipelineSelect(EsphomeAssistEntity, AssistPipelineSelect):

View File

@ -43,12 +43,16 @@ class EsphomeSwitch(EsphomeEntity[SwitchInfo, SwitchState], SwitchEntity):
@convert_api_error_ha_error
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
self._client.switch_command(self._key, True)
self._client.switch_command(
self._key, True, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off."""
self._client.switch_command(self._key, False)
self._client.switch_command(
self._key, False, device_id=self._static_info.device_id
)
async_setup_entry = partial(

View File

@ -50,7 +50,9 @@ class EsphomeText(EsphomeEntity[TextInfo, TextState], TextEntity):
@convert_api_error_ha_error
async def async_set_value(self, value: str) -> None:
"""Update the current value."""
self._client.text_command(self._key, value)
self._client.text_command(
self._key, value, device_id=self._static_info.device_id
)
async_setup_entry = partial(

View File

@ -28,7 +28,13 @@ class EsphomeTime(EsphomeEntity[TimeInfo, TimeState], TimeEntity):
async def async_set_value(self, value: time) -> None:
"""Update the current time."""
self._client.time_command(self._key, value.hour, value.minute, value.second)
self._client.time_command(
self._key,
value.hour,
value.minute,
value.second,
device_id=self._static_info.device_id,
)
async_setup_entry = partial(

View File

@ -334,11 +334,19 @@ class ESPHomeUpdateEntity(EsphomeEntity[UpdateInfo, UpdateState], UpdateEntity):
async def async_update(self) -> None:
"""Command device to check for update."""
if self.available:
self._client.update_command(key=self._key, command=UpdateCommand.CHECK)
self._client.update_command(
key=self._key,
command=UpdateCommand.CHECK,
device_id=self._static_info.device_id,
)
@convert_api_error_ha_error
async def async_install(
self, version: str | None, backup: bool, **kwargs: Any
) -> None:
"""Command device to install update."""
self._client.update_command(key=self._key, command=UpdateCommand.INSTALL)
self._client.update_command(
key=self._key,
command=UpdateCommand.INSTALL,
device_id=self._static_info.device_id,
)

View File

@ -72,22 +72,32 @@ class EsphomeValve(EsphomeEntity[ValveInfo, ValveState], ValveEntity):
@convert_api_error_ha_error
async def async_open_valve(self, **kwargs: Any) -> None:
"""Open the valve."""
self._client.valve_command(key=self._key, position=1.0)
self._client.valve_command(
key=self._key, position=1.0, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_close_valve(self, **kwargs: Any) -> None:
"""Close valve."""
self._client.valve_command(key=self._key, position=0.0)
self._client.valve_command(
key=self._key, position=0.0, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_stop_valve(self, **kwargs: Any) -> None:
"""Stop the valve."""
self._client.valve_command(key=self._key, stop=True)
self._client.valve_command(
key=self._key, stop=True, device_id=self._static_info.device_id
)
@convert_api_error_ha_error
async def async_set_valve_position(self, position: float) -> None:
"""Move the valve to a specific position."""
self._client.valve_command(key=self._key, position=position / 100)
self._client.valve_command(
key=self._key,
position=position / 100,
device_id=self._static_info.device_id,
)
async_setup_entry = partial(

View File

@ -73,7 +73,7 @@ async def test_generic_alarm_control_panel_requires_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.ARM_AWAY, "1234")]
[call(1, AlarmControlPanelCommand.ARM_AWAY, "1234", device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()
@ -87,7 +87,7 @@ async def test_generic_alarm_control_panel_requires_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.ARM_CUSTOM_BYPASS, "1234")]
[call(1, AlarmControlPanelCommand.ARM_CUSTOM_BYPASS, "1234", device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()
@ -101,7 +101,7 @@ async def test_generic_alarm_control_panel_requires_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.ARM_HOME, "1234")]
[call(1, AlarmControlPanelCommand.ARM_HOME, "1234", device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()
@ -115,7 +115,7 @@ async def test_generic_alarm_control_panel_requires_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.ARM_NIGHT, "1234")]
[call(1, AlarmControlPanelCommand.ARM_NIGHT, "1234", device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()
@ -129,7 +129,7 @@ async def test_generic_alarm_control_panel_requires_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.ARM_VACATION, "1234")]
[call(1, AlarmControlPanelCommand.ARM_VACATION, "1234", device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()
@ -143,7 +143,7 @@ async def test_generic_alarm_control_panel_requires_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.TRIGGER, "1234")]
[call(1, AlarmControlPanelCommand.TRIGGER, "1234", device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()
@ -157,7 +157,7 @@ async def test_generic_alarm_control_panel_requires_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.DISARM, "1234")]
[call(1, AlarmControlPanelCommand.DISARM, "1234", device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()
@ -203,7 +203,7 @@ async def test_generic_alarm_control_panel_no_code(
blocking=True,
)
mock_client.alarm_control_panel_command.assert_has_calls(
[call(1, AlarmControlPanelCommand.DISARM, None)]
[call(1, AlarmControlPanelCommand.DISARM, None, device_id=0)]
)
mock_client.alarm_control_panel_command.reset_mock()

View File

@ -39,7 +39,7 @@ async def test_button_generic_entity(
{ATTR_ENTITY_ID: "button.test_my_button"},
blocking=True,
)
mock_client.button_command.assert_has_calls([call(1)])
mock_client.button_command.assert_has_calls([call(1, device_id=0)])
state = hass.states.get("button.test_my_button")
assert state is not None
assert state.state != STATE_UNKNOWN

View File

@ -93,7 +93,9 @@ async def test_climate_entity(
{ATTR_ENTITY_ID: "climate.test_my_climate", ATTR_TEMPERATURE: 25},
blocking=True,
)
mock_client.climate_command.assert_has_calls([call(key=1, target_temperature=25.0)])
mock_client.climate_command.assert_has_calls(
[call(key=1, target_temperature=25.0, device_id=0)]
)
mock_client.climate_command.reset_mock()
@ -167,6 +169,7 @@ async def test_climate_entity_with_step_and_two_point(
mode=ClimateMode.AUTO,
target_temperature_low=20.0,
target_temperature_high=30.0,
device_id=0,
)
]
)
@ -232,7 +235,7 @@ async def test_climate_entity_with_step_and_target_temp(
blocking=True,
)
mock_client.climate_command.assert_has_calls(
[call(key=1, mode=ClimateMode.AUTO, target_temperature=25.0)]
[call(key=1, mode=ClimateMode.AUTO, target_temperature=25.0, device_id=0)]
)
mock_client.climate_command.reset_mock()
@ -263,6 +266,7 @@ async def test_climate_entity_with_step_and_target_temp(
call(
key=1,
mode=ClimateMode.HEAT,
device_id=0,
)
]
)
@ -279,6 +283,7 @@ async def test_climate_entity_with_step_and_target_temp(
call(
key=1,
preset=ClimatePreset.AWAY,
device_id=0,
)
]
)
@ -290,7 +295,9 @@ async def test_climate_entity_with_step_and_target_temp(
{ATTR_ENTITY_ID: "climate.test_my_climate", ATTR_PRESET_MODE: "preset1"},
blocking=True,
)
mock_client.climate_command.assert_has_calls([call(key=1, custom_preset="preset1")])
mock_client.climate_command.assert_has_calls(
[call(key=1, custom_preset="preset1", device_id=0)]
)
mock_client.climate_command.reset_mock()
await hass.services.async_call(
@ -300,7 +307,7 @@ async def test_climate_entity_with_step_and_target_temp(
blocking=True,
)
mock_client.climate_command.assert_has_calls(
[call(key=1, fan_mode=ClimateFanMode.HIGH)]
[call(key=1, fan_mode=ClimateFanMode.HIGH, device_id=0)]
)
mock_client.climate_command.reset_mock()
@ -310,7 +317,9 @@ async def test_climate_entity_with_step_and_target_temp(
{ATTR_ENTITY_ID: "climate.test_my_climate", ATTR_FAN_MODE: "fan2"},
blocking=True,
)
mock_client.climate_command.assert_has_calls([call(key=1, custom_fan_mode="fan2")])
mock_client.climate_command.assert_has_calls(
[call(key=1, custom_fan_mode="fan2", device_id=0)]
)
mock_client.climate_command.reset_mock()
await hass.services.async_call(
@ -320,7 +329,7 @@ async def test_climate_entity_with_step_and_target_temp(
blocking=True,
)
mock_client.climate_command.assert_has_calls(
[call(key=1, swing_mode=ClimateSwingMode.BOTH)]
[call(key=1, swing_mode=ClimateSwingMode.BOTH, device_id=0)]
)
mock_client.climate_command.reset_mock()
@ -383,7 +392,9 @@ async def test_climate_entity_with_humidity(
{ATTR_ENTITY_ID: "climate.test_my_climate", ATTR_HUMIDITY: 23},
blocking=True,
)
mock_client.climate_command.assert_has_calls([call(key=1, target_humidity=23)])
mock_client.climate_command.assert_has_calls(
[call(key=1, target_humidity=23, device_id=0)]
)
mock_client.climate_command.reset_mock()

View File

@ -74,7 +74,7 @@ async def test_cover_entity(
{ATTR_ENTITY_ID: "cover.test_my_cover"},
blocking=True,
)
mock_client.cover_command.assert_has_calls([call(key=1, position=0.0)])
mock_client.cover_command.assert_has_calls([call(key=1, position=0.0, device_id=0)])
mock_client.cover_command.reset_mock()
await hass.services.async_call(
@ -83,7 +83,7 @@ async def test_cover_entity(
{ATTR_ENTITY_ID: "cover.test_my_cover"},
blocking=True,
)
mock_client.cover_command.assert_has_calls([call(key=1, position=1.0)])
mock_client.cover_command.assert_has_calls([call(key=1, position=1.0, device_id=0)])
mock_client.cover_command.reset_mock()
await hass.services.async_call(
@ -92,7 +92,7 @@ async def test_cover_entity(
{ATTR_ENTITY_ID: "cover.test_my_cover", ATTR_POSITION: 50},
blocking=True,
)
mock_client.cover_command.assert_has_calls([call(key=1, position=0.5)])
mock_client.cover_command.assert_has_calls([call(key=1, position=0.5, device_id=0)])
mock_client.cover_command.reset_mock()
await hass.services.async_call(
@ -101,7 +101,7 @@ async def test_cover_entity(
{ATTR_ENTITY_ID: "cover.test_my_cover"},
blocking=True,
)
mock_client.cover_command.assert_has_calls([call(key=1, stop=True)])
mock_client.cover_command.assert_has_calls([call(key=1, stop=True, device_id=0)])
mock_client.cover_command.reset_mock()
await hass.services.async_call(
@ -110,7 +110,7 @@ async def test_cover_entity(
{ATTR_ENTITY_ID: "cover.test_my_cover"},
blocking=True,
)
mock_client.cover_command.assert_has_calls([call(key=1, tilt=1.0)])
mock_client.cover_command.assert_has_calls([call(key=1, tilt=1.0, device_id=0)])
mock_client.cover_command.reset_mock()
await hass.services.async_call(
@ -119,7 +119,7 @@ async def test_cover_entity(
{ATTR_ENTITY_ID: "cover.test_my_cover"},
blocking=True,
)
mock_client.cover_command.assert_has_calls([call(key=1, tilt=0.0)])
mock_client.cover_command.assert_has_calls([call(key=1, tilt=0.0, device_id=0)])
mock_client.cover_command.reset_mock()
await hass.services.async_call(
@ -128,7 +128,7 @@ async def test_cover_entity(
{ATTR_ENTITY_ID: "cover.test_my_cover", ATTR_TILT_POSITION: 50},
blocking=True,
)
mock_client.cover_command.assert_has_calls([call(key=1, tilt=0.5)])
mock_client.cover_command.assert_has_calls([call(key=1, tilt=0.5, device_id=0)])
mock_client.cover_command.reset_mock()
mock_device.set_state(

View File

@ -47,7 +47,7 @@ async def test_generic_date_entity(
{ATTR_ENTITY_ID: "date.test_my_date", ATTR_DATE: "1999-01-01"},
blocking=True,
)
mock_client.date_command.assert_has_calls([call(1, 1999, 1, 1)])
mock_client.date_command.assert_has_calls([call(1, 1999, 1, 1, device_id=0)])
mock_client.date_command.reset_mock()

View File

@ -50,7 +50,7 @@ async def test_generic_datetime_entity(
},
blocking=True,
)
mock_client.datetime_command.assert_has_calls([call(1, 946689825)])
mock_client.datetime_command.assert_has_calls([call(1, 946689825, device_id=0)])
mock_client.datetime_command.reset_mock()

View File

@ -77,7 +77,7 @@ async def test_fan_entity_with_all_features_old_api(
blocking=True,
)
mock_client.fan_command.assert_has_calls(
[call(key=1, speed=FanSpeed.LOW, state=True)]
[call(key=1, speed=FanSpeed.LOW, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -88,7 +88,7 @@ async def test_fan_entity_with_all_features_old_api(
blocking=True,
)
mock_client.fan_command.assert_has_calls(
[call(key=1, speed=FanSpeed.MEDIUM, state=True)]
[call(key=1, speed=FanSpeed.MEDIUM, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -99,7 +99,7 @@ async def test_fan_entity_with_all_features_old_api(
blocking=True,
)
mock_client.fan_command.assert_has_calls(
[call(key=1, speed=FanSpeed.LOW, state=True)]
[call(key=1, speed=FanSpeed.LOW, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -110,7 +110,7 @@ async def test_fan_entity_with_all_features_old_api(
blocking=True,
)
mock_client.fan_command.assert_has_calls(
[call(key=1, speed=FanSpeed.HIGH, state=True)]
[call(key=1, speed=FanSpeed.HIGH, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -120,7 +120,7 @@ async def test_fan_entity_with_all_features_old_api(
{ATTR_ENTITY_ID: "fan.test_my_fan"},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, state=False)])
mock_client.fan_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -130,7 +130,7 @@ async def test_fan_entity_with_all_features_old_api(
blocking=True,
)
mock_client.fan_command.assert_has_calls(
[call(key=1, speed=FanSpeed.HIGH, state=True)]
[call(key=1, speed=FanSpeed.HIGH, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -182,7 +182,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan", ATTR_PERCENTAGE: 20},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, speed_level=1, state=True)])
mock_client.fan_command.assert_has_calls(
[call(key=1, speed_level=1, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -191,7 +193,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan", ATTR_PERCENTAGE: 50},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, speed_level=2, state=True)])
mock_client.fan_command.assert_has_calls(
[call(key=1, speed_level=2, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -200,7 +204,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan"},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, speed_level=2, state=True)])
mock_client.fan_command.assert_has_calls(
[call(key=1, speed_level=2, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -209,7 +215,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan"},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, speed_level=4, state=True)])
mock_client.fan_command.assert_has_calls(
[call(key=1, speed_level=4, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -218,7 +226,7 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan"},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, state=False)])
mock_client.fan_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -227,7 +235,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan", ATTR_PERCENTAGE: 100},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, speed_level=4, state=True)])
mock_client.fan_command.assert_has_calls(
[call(key=1, speed_level=4, state=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -236,7 +246,7 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan", ATTR_PERCENTAGE: 0},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, state=False)])
mock_client.fan_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -245,7 +255,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan", ATTR_OSCILLATING: True},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, oscillating=True)])
mock_client.fan_command.assert_has_calls(
[call(key=1, oscillating=True, device_id=0)]
)
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -254,7 +266,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan", ATTR_OSCILLATING: False},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, oscillating=False)])
mock_client.fan_command.assert_has_calls(
[call(key=1, oscillating=False, device_id=0)]
)
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -264,7 +278,7 @@ async def test_fan_entity_with_all_features_new_api(
blocking=True,
)
mock_client.fan_command.assert_has_calls(
[call(key=1, direction=FanDirection.FORWARD)]
[call(key=1, direction=FanDirection.FORWARD, device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -275,7 +289,7 @@ async def test_fan_entity_with_all_features_new_api(
blocking=True,
)
mock_client.fan_command.assert_has_calls(
[call(key=1, direction=FanDirection.REVERSE)]
[call(key=1, direction=FanDirection.REVERSE, device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -285,7 +299,9 @@ async def test_fan_entity_with_all_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan", ATTR_PRESET_MODE: "Preset1"},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, preset_mode="Preset1")])
mock_client.fan_command.assert_has_calls(
[call(key=1, preset_mode="Preset1", device_id=0)]
)
mock_client.fan_command.reset_mock()
@ -326,7 +342,7 @@ async def test_fan_entity_with_no_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan"},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, state=True)])
mock_client.fan_command.assert_has_calls([call(key=1, state=True, device_id=0)])
mock_client.fan_command.reset_mock()
await hass.services.async_call(
@ -335,5 +351,5 @@ async def test_fan_entity_with_no_features_new_api(
{ATTR_ENTITY_ID: "fan.test_my_fan"},
blocking=True,
)
mock_client.fan_command.assert_has_calls([call(key=1, state=False)])
mock_client.fan_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.fan_command.reset_mock()

View File

@ -81,7 +81,7 @@ async def test_light_on_off(
blocking=True,
)
mock_client.light_command.assert_has_calls(
[call(key=1, state=True, color_mode=LightColorCapability.ON_OFF)]
[call(key=1, state=True, color_mode=LightColorCapability.ON_OFF, device_id=0)]
)
mock_client.light_command.reset_mock()
@ -123,7 +123,14 @@ async def test_light_brightness(
blocking=True,
)
mock_client.light_command.assert_has_calls(
[call(key=1, state=True, color_mode=LightColorCapability.BRIGHTNESS)]
[
call(
key=1,
state=True,
color_mode=LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
mock_client.light_command.reset_mock()
@ -140,6 +147,7 @@ async def test_light_brightness(
state=True,
color_mode=LightColorCapability.BRIGHTNESS,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -152,7 +160,7 @@ async def test_light_brightness(
blocking=True,
)
mock_client.light_command.assert_has_calls(
[call(key=1, state=False, transition_length=2.0)]
[call(key=1, state=False, transition_length=2.0, device_id=0)]
)
mock_client.light_command.reset_mock()
@ -163,7 +171,7 @@ async def test_light_brightness(
blocking=True,
)
mock_client.light_command.assert_has_calls(
[call(key=1, state=False, flash_length=10.0)]
[call(key=1, state=False, flash_length=10.0, device_id=0)]
)
mock_client.light_command.reset_mock()
@ -180,6 +188,7 @@ async def test_light_brightness(
state=True,
transition_length=2.0,
color_mode=LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -198,6 +207,7 @@ async def test_light_brightness(
state=True,
flash_length=2.0,
color_mode=LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -248,7 +258,14 @@ async def test_light_legacy_brightness(
blocking=True,
)
mock_client.light_command.assert_has_calls(
[call(key=1, state=True, color_mode=LightColorCapability.BRIGHTNESS)]
[
call(
key=1,
state=True,
color_mode=LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
mock_client.light_command.reset_mock()
@ -303,6 +320,7 @@ async def test_light_brightness_on_off(
key=1,
state=True,
color_mode=ESPColorMode.BRIGHTNESS.value,
device_id=0,
)
]
)
@ -321,6 +339,7 @@ async def test_light_brightness_on_off(
state=True,
color_mode=ESPColorMode.BRIGHTNESS.value,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -375,6 +394,7 @@ async def test_light_legacy_white_converted_to_brightness(
color_mode=LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS
| LightColorCapability.WHITE,
device_id=0,
)
]
)
@ -439,6 +459,7 @@ async def test_light_legacy_white_with_rgb(
brightness=pytest.approx(0.23529411764705882),
white=1.0,
color_mode=color_mode,
device_id=0,
)
]
)
@ -496,6 +517,7 @@ async def test_light_brightness_on_off_with_unknown_color_mode(
key=1,
state=True,
color_mode=LIGHT_COLOR_CAPABILITY_UNKNOWN,
device_id=0,
)
]
)
@ -514,6 +536,7 @@ async def test_light_brightness_on_off_with_unknown_color_mode(
state=True,
color_mode=ESPColorMode.BRIGHTNESS,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -560,7 +583,7 @@ async def test_light_on_and_brightness(
blocking=True,
)
mock_client.light_command.assert_has_calls(
[call(key=1, state=True, color_mode=LightColorCapability.ON_OFF)]
[call(key=1, state=True, color_mode=LightColorCapability.ON_OFF, device_id=0)]
)
mock_client.light_command.reset_mock()
@ -618,6 +641,7 @@ async def test_rgb_color_temp_light(
key=1,
state=True,
color_mode=ESPColorMode.BRIGHTNESS,
device_id=0,
)
]
)
@ -636,6 +660,7 @@ async def test_rgb_color_temp_light(
state=True,
color_mode=ESPColorMode.BRIGHTNESS,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -654,6 +679,7 @@ async def test_rgb_color_temp_light(
state=True,
color_mode=ESPColorMode.COLOR_TEMPERATURE,
color_temperature=400,
device_id=0,
)
]
)
@ -706,6 +732,7 @@ async def test_light_rgb(
color_mode=LightColorCapability.RGB
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -726,6 +753,7 @@ async def test_light_rgb(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -752,6 +780,7 @@ async def test_light_rgb(
| LightColorCapability.BRIGHTNESS,
rgb=(pytest.approx(0.3333333333333333), 1.0, 0.0),
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -773,6 +802,7 @@ async def test_light_rgb(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
rgb=(1, 1, 1),
device_id=0,
)
]
)
@ -843,6 +873,7 @@ async def test_light_rgbw(
| LightColorCapability.WHITE
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -864,6 +895,7 @@ async def test_light_rgbw(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -892,6 +924,7 @@ async def test_light_rgbw(
white=0,
rgb=(pytest.approx(0.3333333333333333), 1.0, 0.0),
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -915,6 +948,7 @@ async def test_light_rgbw(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
rgb=(0, 0, 0),
device_id=0,
)
]
)
@ -938,6 +972,7 @@ async def test_light_rgbw(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
rgb=(1, 1, 1),
device_id=0,
)
]
)
@ -1017,6 +1052,7 @@ async def test_light_rgbww_with_cold_warm_white_support(
key=1,
state=True,
color_mode=ESPColorMode.RGB_COLD_WARM_WHITE,
device_id=0,
)
]
)
@ -1035,6 +1071,7 @@ async def test_light_rgbww_with_cold_warm_white_support(
state=True,
color_mode=ESPColorMode.RGB_COLD_WARM_WHITE,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -1059,6 +1096,7 @@ async def test_light_rgbww_with_cold_warm_white_support(
color_mode=ESPColorMode.RGB,
rgb=(pytest.approx(0.3333333333333333), 1.0, 0.0),
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -1078,6 +1116,7 @@ async def test_light_rgbww_with_cold_warm_white_support(
color_brightness=1.0,
color_mode=ESPColorMode.RGB,
rgb=(1.0, 1.0, 1.0),
device_id=0,
)
]
)
@ -1098,6 +1137,7 @@ async def test_light_rgbww_with_cold_warm_white_support(
white=1,
color_mode=ESPColorMode.RGB_WHITE,
rgb=(1.0, 1.0, 1.0),
device_id=0,
)
]
)
@ -1122,6 +1162,7 @@ async def test_light_rgbww_with_cold_warm_white_support(
warm_white=1,
color_mode=ESPColorMode.RGB_COLD_WARM_WHITE,
rgb=(1, 1, 1),
device_id=0,
)
]
)
@ -1140,6 +1181,7 @@ async def test_light_rgbww_with_cold_warm_white_support(
state=True,
color_temperature=400.0,
color_mode=ESPColorMode.COLOR_TEMPERATURE,
device_id=0,
)
]
)
@ -1217,6 +1259,7 @@ async def test_light_rgbww_without_cold_warm_white_support(
| LightColorCapability.COLOR_TEMPERATURE
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -1239,6 +1282,7 @@ async def test_light_rgbww_without_cold_warm_white_support(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -1268,6 +1312,7 @@ async def test_light_rgbww_without_cold_warm_white_support(
white=0,
rgb=(pytest.approx(0.3333333333333333), 1.0, 0.0),
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -1294,6 +1339,7 @@ async def test_light_rgbww_without_cold_warm_white_support(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
rgb=(0, pytest.approx(0.5462962962962963), 1.0),
device_id=0,
)
]
)
@ -1319,6 +1365,7 @@ async def test_light_rgbww_without_cold_warm_white_support(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
rgb=(0, pytest.approx(0.5462962962962963), 1.0),
device_id=0,
)
]
)
@ -1347,6 +1394,7 @@ async def test_light_rgbww_without_cold_warm_white_support(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
rgb=(1, 1, 1),
device_id=0,
)
]
)
@ -1372,6 +1420,7 @@ async def test_light_rgbww_without_cold_warm_white_support(
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
rgb=(0, 0, 0),
device_id=0,
)
]
)
@ -1437,6 +1486,7 @@ async def test_light_color_temp(
color_mode=LightColorCapability.COLOR_TEMPERATURE
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -1448,7 +1498,7 @@ async def test_light_color_temp(
{ATTR_ENTITY_ID: "light.test_my_light"},
blocking=True,
)
mock_client.light_command.assert_has_calls([call(key=1, state=False)])
mock_client.light_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.light_command.reset_mock()
@ -1511,6 +1561,7 @@ async def test_light_color_temp_no_mireds_set(
color_mode=LightColorCapability.COLOR_TEMPERATURE
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -1531,6 +1582,7 @@ async def test_light_color_temp_no_mireds_set(
color_mode=LightColorCapability.COLOR_TEMPERATURE
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -1542,7 +1594,7 @@ async def test_light_color_temp_no_mireds_set(
{ATTR_ENTITY_ID: "light.test_my_light"},
blocking=True,
)
mock_client.light_command.assert_has_calls([call(key=1, state=False)])
mock_client.light_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.light_command.reset_mock()
@ -1615,6 +1667,7 @@ async def test_light_color_temp_legacy(
color_mode=LightColorCapability.COLOR_TEMPERATURE
| LightColorCapability.ON_OFF
| LightColorCapability.BRIGHTNESS,
device_id=0,
)
]
)
@ -1626,7 +1679,7 @@ async def test_light_color_temp_legacy(
{ATTR_ENTITY_ID: "light.test_my_light"},
blocking=True,
)
mock_client.light_command.assert_has_calls([call(key=1, state=False)])
mock_client.light_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.light_command.reset_mock()
@ -1695,6 +1748,7 @@ async def test_light_rgb_legacy(
call(
key=1,
state=True,
device_id=0,
)
]
)
@ -1706,7 +1760,7 @@ async def test_light_rgb_legacy(
{ATTR_ENTITY_ID: "light.test_my_light"},
blocking=True,
)
mock_client.light_command.assert_has_calls([call(key=1, state=False)])
mock_client.light_command.assert_has_calls([call(key=1, state=False, device_id=0)])
mock_client.light_command.reset_mock()
await hass.services.async_call(
@ -1722,6 +1776,7 @@ async def test_light_rgb_legacy(
state=True,
rgb=(1.0, 1.0, 1.0),
color_brightness=1.0,
device_id=0,
)
]
)
@ -1780,6 +1835,7 @@ async def test_light_effects(
state=True,
color_mode=ESPColorMode.BRIGHTNESS,
effect="effect1",
device_id=0,
)
]
)
@ -1843,7 +1899,7 @@ async def test_only_cold_warm_white_support(
blocking=True,
)
mock_client.light_command.assert_has_calls(
[call(key=1, state=True, color_mode=color_modes)]
[call(key=1, state=True, color_mode=color_modes, device_id=0)]
)
mock_client.light_command.reset_mock()
@ -1860,6 +1916,7 @@ async def test_only_cold_warm_white_support(
state=True,
color_mode=color_modes,
brightness=pytest.approx(0.4980392156862745),
device_id=0,
)
]
)
@ -1878,6 +1935,7 @@ async def test_only_cold_warm_white_support(
state=True,
color_mode=color_modes,
color_temperature=400.0,
device_id=0,
)
]
)
@ -1922,5 +1980,7 @@ async def test_light_no_color_modes(
{ATTR_ENTITY_ID: "light.test_my_light"},
blocking=True,
)
mock_client.light_command.assert_has_calls([call(key=1, state=True, color_mode=0)])
mock_client.light_command.assert_has_calls(
[call(key=1, state=True, color_mode=0, device_id=0)]
)
mock_client.light_command.reset_mock()

View File

@ -57,7 +57,7 @@ async def test_lock_entity_no_open(
{ATTR_ENTITY_ID: "lock.test_my_lock"},
blocking=True,
)
mock_client.lock_command.assert_has_calls([call(1, LockCommand.LOCK)])
mock_client.lock_command.assert_has_calls([call(1, LockCommand.LOCK, device_id=0)])
mock_client.lock_command.reset_mock()
@ -122,7 +122,7 @@ async def test_lock_entity_supports_open(
{ATTR_ENTITY_ID: "lock.test_my_lock"},
blocking=True,
)
mock_client.lock_command.assert_has_calls([call(1, LockCommand.LOCK)])
mock_client.lock_command.assert_has_calls([call(1, LockCommand.LOCK, device_id=0)])
mock_client.lock_command.reset_mock()
await hass.services.async_call(
@ -131,7 +131,9 @@ async def test_lock_entity_supports_open(
{ATTR_ENTITY_ID: "lock.test_my_lock"},
blocking=True,
)
mock_client.lock_command.assert_has_calls([call(1, LockCommand.UNLOCK, None)])
mock_client.lock_command.assert_has_calls(
[call(1, LockCommand.UNLOCK, None, device_id=0)]
)
mock_client.lock_command.reset_mock()
await hass.services.async_call(
@ -140,4 +142,4 @@ async def test_lock_entity_supports_open(
{ATTR_ENTITY_ID: "lock.test_my_lock"},
blocking=True,
)
mock_client.lock_command.assert_has_calls([call(1, LockCommand.OPEN)])
mock_client.lock_command.assert_has_calls([call(1, LockCommand.OPEN, device_id=0)])

View File

@ -85,7 +85,7 @@ async def test_media_player_entity(
blocking=True,
)
mock_client.media_player_command.assert_has_calls(
[call(1, command=MediaPlayerCommand.MUTE)]
[call(1, command=MediaPlayerCommand.MUTE, device_id=0)]
)
mock_client.media_player_command.reset_mock()
@ -99,7 +99,7 @@ async def test_media_player_entity(
blocking=True,
)
mock_client.media_player_command.assert_has_calls(
[call(1, command=MediaPlayerCommand.MUTE)]
[call(1, command=MediaPlayerCommand.MUTE, device_id=0)]
)
mock_client.media_player_command.reset_mock()
@ -112,7 +112,9 @@ async def test_media_player_entity(
},
blocking=True,
)
mock_client.media_player_command.assert_has_calls([call(1, volume=0.5)])
mock_client.media_player_command.assert_has_calls(
[call(1, volume=0.5, device_id=0)]
)
mock_client.media_player_command.reset_mock()
await hass.services.async_call(
@ -124,7 +126,7 @@ async def test_media_player_entity(
blocking=True,
)
mock_client.media_player_command.assert_has_calls(
[call(1, command=MediaPlayerCommand.PAUSE)]
[call(1, command=MediaPlayerCommand.PAUSE, device_id=0)]
)
mock_client.media_player_command.reset_mock()
@ -137,7 +139,7 @@ async def test_media_player_entity(
blocking=True,
)
mock_client.media_player_command.assert_has_calls(
[call(1, command=MediaPlayerCommand.PLAY)]
[call(1, command=MediaPlayerCommand.PLAY, device_id=0)]
)
mock_client.media_player_command.reset_mock()
@ -150,7 +152,7 @@ async def test_media_player_entity(
blocking=True,
)
mock_client.media_player_command.assert_has_calls(
[call(1, command=MediaPlayerCommand.STOP)]
[call(1, command=MediaPlayerCommand.STOP, device_id=0)]
)
mock_client.media_player_command.reset_mock()
@ -257,7 +259,14 @@ async def test_media_player_entity_with_source(
)
mock_client.media_player_command.assert_has_calls(
[call(1, media_url="http://www.example.com/xy.mp3", announcement=None)]
[
call(
1,
media_url="http://www.example.com/xy.mp3",
announcement=None,
device_id=0,
)
]
)
client = await hass_ws_client()
@ -284,7 +293,14 @@ async def test_media_player_entity_with_source(
)
mock_client.media_player_command.assert_has_calls(
[call(1, media_url="media-source://tts?message=hello", announcement=True)]
[
call(
1,
media_url="media-source://tts?message=hello",
announcement=True,
device_id=0,
)
]
)

View File

@ -60,7 +60,7 @@ async def test_generic_number_entity(
{ATTR_ENTITY_ID: "number.test_my_number", ATTR_VALUE: 50},
blocking=True,
)
mock_client.number_command.assert_has_calls([call(1, 50)])
mock_client.number_command.assert_has_calls([call(1, 50, device_id=0)])
mock_client.number_command.reset_mock()

View File

@ -89,7 +89,7 @@ async def test_select_generic_entity(
{ATTR_ENTITY_ID: "select.test_my_select", ATTR_OPTION: "b"},
blocking=True,
)
mock_client.select_command.assert_has_calls([call(1, "b")])
mock_client.select_command.assert_has_calls([call(1, "b", device_id=0)])
async def test_wake_word_select_no_wake_words(

View File

@ -2,17 +2,17 @@
from unittest.mock import call
from aioesphomeapi import APIClient, SwitchInfo, SwitchState
from aioesphomeapi import APIClient, SubDeviceInfo, SwitchInfo, SwitchState
from homeassistant.components.switch import (
DOMAIN as SWITCH_DOMAIN,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_ON
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from .conftest import MockGenericDeviceEntryType
from .conftest import MockESPHomeDeviceType, MockGenericDeviceEntryType
async def test_switch_generic_entity(
@ -47,7 +47,7 @@ async def test_switch_generic_entity(
{ATTR_ENTITY_ID: "switch.test_my_switch"},
blocking=True,
)
mock_client.switch_command.assert_has_calls([call(1, True)])
mock_client.switch_command.assert_has_calls([call(1, True, device_id=0)])
await hass.services.async_call(
SWITCH_DOMAIN,
@ -55,4 +55,95 @@ async def test_switch_generic_entity(
{ATTR_ENTITY_ID: "switch.test_my_switch"},
blocking=True,
)
mock_client.switch_command.assert_has_calls([call(1, False)])
mock_client.switch_command.assert_has_calls([call(1, False, device_id=0)])
async def test_switch_sub_device_non_zero_device_id(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: MockESPHomeDeviceType,
) -> None:
"""Test switch on sub-device with non-zero device_id passes through to API."""
# Create sub-device
sub_devices = [
SubDeviceInfo(device_id=11111111, name="Sub Device", area_id=0),
]
device_info = {
"name": "test",
"devices": sub_devices,
}
# Create switches on both main device and sub-device
entity_info = [
SwitchInfo(
object_id="main_switch",
key=1,
name="Main Switch",
unique_id="main_switch_1",
device_id=0, # Main device
),
SwitchInfo(
object_id="sub_switch",
key=2,
name="Sub Switch",
unique_id="sub_switch_1",
device_id=11111111, # Sub-device
),
]
# States for both switches
states = [
SwitchState(key=1, state=True, device_id=0),
SwitchState(key=2, state=False, device_id=11111111),
]
await mock_esphome_device(
mock_client=mock_client,
device_info=device_info,
entity_info=entity_info,
states=states,
)
# Verify both entities exist with correct states
main_state = hass.states.get("switch.test_main_switch")
assert main_state is not None
assert main_state.state == STATE_ON
sub_state = hass.states.get("switch.sub_device_sub_switch")
assert sub_state is not None
assert sub_state.state == STATE_OFF
# Test turning on the sub-device switch - should pass device_id=11111111
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.sub_device_sub_switch"},
blocking=True,
)
mock_client.switch_command.assert_has_calls([call(2, True, device_id=11111111)])
mock_client.switch_command.reset_mock()
# Test turning off the sub-device switch - should pass device_id=11111111
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.sub_device_sub_switch"},
blocking=True,
)
mock_client.switch_command.assert_has_calls([call(2, False, device_id=11111111)])
mock_client.switch_command.reset_mock()
# Test main device switch still uses device_id=0
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.test_main_switch"},
blocking=True,
)
mock_client.switch_command.assert_has_calls([call(1, True, device_id=0)])
mock_client.switch_command.reset_mock()
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.test_main_switch"},
blocking=True,
)
mock_client.switch_command.assert_has_calls([call(1, False, device_id=0)])

View File

@ -51,7 +51,7 @@ async def test_generic_text_entity(
{ATTR_ENTITY_ID: "text.test_my_text", ATTR_VALUE: "goodbye"},
blocking=True,
)
mock_client.text_command.assert_has_calls([call(1, "goodbye")])
mock_client.text_command.assert_has_calls([call(1, "goodbye", device_id=0)])
mock_client.text_command.reset_mock()

View File

@ -47,7 +47,7 @@ async def test_generic_time_entity(
{ATTR_ENTITY_ID: "time.test_my_time", ATTR_TIME: "01:23:45"},
blocking=True,
)
mock_client.time_command.assert_has_calls([call(1, 1, 23, 45)])
mock_client.time_command.assert_has_calls([call(1, 1, 23, 45, device_id=0)])
mock_client.time_command.reset_mock()

View File

@ -544,7 +544,9 @@ async def test_generic_device_update_entity_has_update(
assert state.attributes[ATTR_IN_PROGRESS] is True
assert state.attributes[ATTR_UPDATE_PERCENTAGE] is None
mock_client.update_command.assert_called_with(key=1, command=UpdateCommand.CHECK)
mock_client.update_command.assert_called_with(
key=1, command=UpdateCommand.CHECK, device_id=0
)
async def test_update_entity_release_notes(

View File

@ -66,7 +66,7 @@ async def test_valve_entity(
{ATTR_ENTITY_ID: "valve.test_my_valve"},
blocking=True,
)
mock_client.valve_command.assert_has_calls([call(key=1, position=0.0)])
mock_client.valve_command.assert_has_calls([call(key=1, position=0.0, device_id=0)])
mock_client.valve_command.reset_mock()
await hass.services.async_call(
@ -75,7 +75,7 @@ async def test_valve_entity(
{ATTR_ENTITY_ID: "valve.test_my_valve"},
blocking=True,
)
mock_client.valve_command.assert_has_calls([call(key=1, position=1.0)])
mock_client.valve_command.assert_has_calls([call(key=1, position=1.0, device_id=0)])
mock_client.valve_command.reset_mock()
await hass.services.async_call(
@ -84,7 +84,7 @@ async def test_valve_entity(
{ATTR_ENTITY_ID: "valve.test_my_valve", ATTR_POSITION: 50},
blocking=True,
)
mock_client.valve_command.assert_has_calls([call(key=1, position=0.5)])
mock_client.valve_command.assert_has_calls([call(key=1, position=0.5, device_id=0)])
mock_client.valve_command.reset_mock()
await hass.services.async_call(
@ -93,7 +93,7 @@ async def test_valve_entity(
{ATTR_ENTITY_ID: "valve.test_my_valve"},
blocking=True,
)
mock_client.valve_command.assert_has_calls([call(key=1, stop=True)])
mock_client.valve_command.assert_has_calls([call(key=1, stop=True, device_id=0)])
mock_client.valve_command.reset_mock()
mock_device.set_state(
@ -164,7 +164,7 @@ async def test_valve_entity_without_position(
{ATTR_ENTITY_ID: "valve.test_my_valve"},
blocking=True,
)
mock_client.valve_command.assert_has_calls([call(key=1, position=0.0)])
mock_client.valve_command.assert_has_calls([call(key=1, position=0.0, device_id=0)])
mock_client.valve_command.reset_mock()
await hass.services.async_call(
@ -173,7 +173,7 @@ async def test_valve_entity_without_position(
{ATTR_ENTITY_ID: "valve.test_my_valve"},
blocking=True,
)
mock_client.valve_command.assert_has_calls([call(key=1, position=1.0)])
mock_client.valve_command.assert_has_calls([call(key=1, position=1.0, device_id=0)])
mock_client.valve_command.reset_mock()
mock_device.set_state(