mirror of
https://github.com/home-assistant/core.git
synced 2026-08-24 10:13:52 -05:00
Fix line length violations in tests/components b (#170825)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: frenck <195327+frenck@users.noreply.github.com>
This commit is contained in:
co-authored by
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
frenck
parent
5f811e856f
commit
31f98c12af
@@ -172,7 +172,9 @@ def b2_fixture():
|
||||
return MockDownloadedFile(metadata_json_content_bytes)
|
||||
return MockDownloadedFile(test_backup_data)
|
||||
raise ValueError(
|
||||
f"Mocked download_file_by_id: File with id {file_id} or name {file_name} not found."
|
||||
"Mocked download_file_by_id: "
|
||||
f"File with id {file_id} or name "
|
||||
f"{file_name} not found."
|
||||
)
|
||||
|
||||
def ls(
|
||||
|
||||
@@ -902,7 +902,10 @@ async def test_metadata_downloads_are_sequential(
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test that metadata downloads are processed sequentially to avoid exhausting executor pool."""
|
||||
"""Test metadata downloads are processed sequentially.
|
||||
|
||||
This avoids exhausting the executor pool.
|
||||
"""
|
||||
current_concurrent = 0
|
||||
max_concurrent = 0
|
||||
lock = threading.Lock()
|
||||
|
||||
@@ -247,8 +247,8 @@ async def test_downloading_backup_not_found_get_backup_returns_none(
|
||||
resp = await client.get("/api/backup/download/abc123?agent_id=test.test")
|
||||
assert resp.status == 404
|
||||
assert (
|
||||
"Detected that integration 'test' returns None from BackupAgent.async_get_backup."
|
||||
in caplog.text
|
||||
"Detected that integration 'test' returns None from"
|
||||
" BackupAgent.async_get_backup." in caplog.text
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -376,7 +376,8 @@ async def test_create_backup_when_busy(
|
||||
),
|
||||
(
|
||||
{"agent_ids": ["non_existing"]},
|
||||
"At least one available backup agent must be selected, got ['non_existing']",
|
||||
"At least one available backup agent must be"
|
||||
" selected, got ['non_existing']",
|
||||
),
|
||||
(
|
||||
{"include_addons": ["ssl"], "include_all_addons": True},
|
||||
|
||||
@@ -251,7 +251,10 @@ async def test_onboarding_backup_restore(
|
||||
None,
|
||||
400,
|
||||
{
|
||||
"message": "Message format incorrect: required key not provided @ data['agent_id']"
|
||||
"message": (
|
||||
"Message format incorrect: required key"
|
||||
" not provided @ data['agent_id']"
|
||||
)
|
||||
},
|
||||
0,
|
||||
),
|
||||
@@ -261,7 +264,10 @@ async def test_onboarding_backup_restore(
|
||||
None,
|
||||
400,
|
||||
{
|
||||
"message": "Message format incorrect: required key not provided @ data['backup_id']"
|
||||
"message": (
|
||||
"Message format incorrect: required key"
|
||||
" not provided @ data['backup_id']"
|
||||
)
|
||||
},
|
||||
0,
|
||||
),
|
||||
@@ -275,7 +281,11 @@ async def test_onboarding_backup_restore(
|
||||
None,
|
||||
400,
|
||||
{
|
||||
"message": "Message format incorrect: expected bool for dictionary value @ data['restore_database']"
|
||||
"message": (
|
||||
"Message format incorrect: expected bool"
|
||||
" for dictionary value"
|
||||
" @ data['restore_database']"
|
||||
)
|
||||
},
|
||||
0,
|
||||
),
|
||||
@@ -289,7 +299,12 @@ async def test_onboarding_backup_restore(
|
||||
None,
|
||||
400,
|
||||
{
|
||||
"message": "Message format incorrect: expected Folder or one of 'share', 'addons/local', 'ssl', 'media' @ data['restore_folders'][0]"
|
||||
"message": (
|
||||
"Message format incorrect: expected"
|
||||
" Folder or one of 'share',"
|
||||
" 'addons/local', 'ssl', 'media'"
|
||||
" @ data['restore_folders'][0]"
|
||||
)
|
||||
},
|
||||
0,
|
||||
),
|
||||
|
||||
@@ -152,7 +152,8 @@ def test_read_backup(backup_json_content: bytes, expected_backup: AgentBackup) -
|
||||
mock_path.stat.return_value.st_size = 1234
|
||||
|
||||
with patch("homeassistant.components.backup.util.tarfile.open") as mock_open_tar:
|
||||
mock_open_tar.return_value.__enter__.return_value.extractfile.return_value.read.return_value = backup_json_content
|
||||
tar_ctx = mock_open_tar.return_value.__enter__.return_value
|
||||
tar_ctx.extractfile.return_value.read.return_value = backup_json_content
|
||||
backup = read_backup(mock_path)
|
||||
assert backup == expected_backup
|
||||
|
||||
|
||||
@@ -271,8 +271,8 @@ async def test_details_get_backup_returns_none(
|
||||
)
|
||||
assert await client.receive_json() == snapshot
|
||||
assert (
|
||||
"Detected that integration 'test' returns None from BackupAgent.async_get_backup."
|
||||
in caplog.text
|
||||
"Detected that integration 'test' returns None from"
|
||||
" BackupAgent.async_get_backup." in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@@ -798,8 +798,8 @@ async def test_restore_remote_agent_get_backup_returns_none(
|
||||
assert await client.receive_json() == snapshot
|
||||
assert len(restart_calls) == 0
|
||||
assert (
|
||||
"Detected that integration 'test' returns None from BackupAgent.async_get_backup."
|
||||
in caplog.text
|
||||
"Detected that integration 'test' returns None from"
|
||||
" BackupAgent.async_get_backup." in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@@ -4139,6 +4139,6 @@ async def test_can_decrypt_on_download_get_backup_returns_none(
|
||||
)
|
||||
assert await client.receive_json() == snapshot
|
||||
assert (
|
||||
"Detected that integration 'test' returns None from BackupAgent.async_get_backup."
|
||||
in caplog.text
|
||||
"Detected that integration 'test' returns None from"
|
||||
" BackupAgent.async_get_backup." in caplog.text
|
||||
)
|
||||
|
||||
@@ -305,7 +305,8 @@ def mock_mozart_client() -> Generator[AsyncMock]:
|
||||
fixed=False,
|
||||
id="b6591565-80f4-4356-bcd9-c92ca247f0a9",
|
||||
),
|
||||
# The parent remote menu item. Has the TV label and should therefore not be included in video sources
|
||||
# The parent remote menu item. Has the TV label and
|
||||
# should therefore not be included in video sources
|
||||
"b66c835b-6b98-4400-8f84-6348043792c7": RemoteMenuItem(
|
||||
action_list=[],
|
||||
scene_list=None,
|
||||
|
||||
@@ -48,27 +48,39 @@ TEST_NAME = f"{TEST_MODEL_BALANCE}-{TEST_SERIAL_NUMBER}"
|
||||
TEST_FRIENDLY_NAME = "Living room Balance"
|
||||
TEST_TYPE_NUMBER = "1111"
|
||||
TEST_ITEM_NUMBER = "1111111"
|
||||
TEST_JID_1 = f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}.{TEST_SERIAL_NUMBER}@products.bang-olufsen.com"
|
||||
TEST_JID_1 = (
|
||||
f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}"
|
||||
f".{TEST_SERIAL_NUMBER}@products.bang-olufsen.com"
|
||||
)
|
||||
TEST_MEDIA_PLAYER_ENTITY_ID = "media_player.living_room_balance"
|
||||
|
||||
TEST_FRIENDLY_NAME_2 = "Laundry room Core"
|
||||
TEST_SERIAL_NUMBER_2 = "22222222"
|
||||
TEST_NAME_2 = f"{TEST_MODEL_CORE}-{TEST_SERIAL_NUMBER_2}"
|
||||
TEST_JID_2 = f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}.{TEST_SERIAL_NUMBER_2}@products.bang-olufsen.com"
|
||||
TEST_JID_2 = (
|
||||
f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}"
|
||||
f".{TEST_SERIAL_NUMBER_2}@products.bang-olufsen.com"
|
||||
)
|
||||
TEST_MEDIA_PLAYER_ENTITY_ID_2 = "media_player.laundry_room_core"
|
||||
TEST_HOST_2 = "192.168.0.2"
|
||||
|
||||
TEST_FRIENDLY_NAME_3 = "Bedroom Premiere"
|
||||
TEST_SERIAL_NUMBER_3 = "33333333"
|
||||
TEST_NAME_3 = f"{TEST_MODEL_PREMIERE}-{TEST_SERIAL_NUMBER_3}"
|
||||
TEST_JID_3 = f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}.{TEST_SERIAL_NUMBER_3}@products.bang-olufsen.com"
|
||||
TEST_JID_3 = (
|
||||
f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}"
|
||||
f".{TEST_SERIAL_NUMBER_3}@products.bang-olufsen.com"
|
||||
)
|
||||
TEST_MEDIA_PLAYER_ENTITY_ID_3 = "media_player.bedroom_premiere"
|
||||
TEST_HOST_3 = "192.168.0.3"
|
||||
|
||||
TEST_FRIENDLY_NAME_4 = "Lounge room A5"
|
||||
TEST_SERIAL_NUMBER_4 = "44444444"
|
||||
TEST_NAME_4 = f"{TEST_MODEL_A5}-{TEST_SERIAL_NUMBER_4}"
|
||||
TEST_JID_4 = f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}.{TEST_SERIAL_NUMBER_4}@products.bang-olufsen.com"
|
||||
TEST_JID_4 = (
|
||||
f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}"
|
||||
f".{TEST_SERIAL_NUMBER_4}@products.bang-olufsen.com"
|
||||
)
|
||||
TEST_MEDIA_PLAYER_ENTITY_ID_4 = "media_player.lounge_room_a5"
|
||||
TEST_HOST_4 = "192.168.0.4"
|
||||
TEST_BATTERY_SENSOR_ENTITY_ID = "sensor.lounge_room_a5_battery"
|
||||
|
||||
@@ -76,7 +76,11 @@ async def test_button_event_creation_balance(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_mozart_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test button event entities are created when using a Balance (Most devices support all buttons like the Balance)."""
|
||||
"""Test button event entities are created.
|
||||
|
||||
Uses a Balance (Most devices support all buttons
|
||||
like the Balance).
|
||||
"""
|
||||
|
||||
await _check_button_event_creation(
|
||||
hass,
|
||||
@@ -95,7 +99,10 @@ async def test_no_button_and_remote_key_event_creation_core(
|
||||
entity_registry: EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test button event entities are not created when using a Beoconnect Core with no Beoremote One connected."""
|
||||
"""Test button event entities are not created.
|
||||
|
||||
Uses a Beoconnect Core with no Beoremote One connected.
|
||||
"""
|
||||
mock_mozart_client.get_bluetooth_remotes.return_value = PairedRemoteResponse(
|
||||
items=[]
|
||||
)
|
||||
@@ -117,7 +124,10 @@ async def test_button_event_creation_premiere(
|
||||
entity_registry: EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test Bluetooth and Microphone button event entities are not created when using a Beosound Premiere."""
|
||||
"""Test Bluetooth and Microphone button event entities.
|
||||
|
||||
These are not created when using a Beosound Premiere.
|
||||
"""
|
||||
mock_mozart_client.get_beolink_self.return_value = BeolinkSelf(
|
||||
friendly_name=TEST_FRIENDLY_NAME_3, jid=TEST_JID_3
|
||||
)
|
||||
|
||||
@@ -39,7 +39,8 @@ async def test_setup_entry(
|
||||
assert device.name == TEST_FRIENDLY_NAME
|
||||
assert device.model == TEST_MODEL_BALANCE
|
||||
|
||||
# Ensure that the connection has been checked WebSocket connection has been initialized
|
||||
# Ensure that the connection has been checked
|
||||
# WebSocket connection has been initialized
|
||||
assert mock_mozart_client.check_device_connection.call_count == 1
|
||||
assert mock_mozart_client.close_api_client.call_count == 0
|
||||
assert mock_mozart_client.connect_notifications.call_count == 1
|
||||
|
||||
@@ -128,7 +128,10 @@ async def test_initialization(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_mozart_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test the integration is initialized properly in _initialize, async_added_to_hass and __init__."""
|
||||
"""Test the integration is initialized properly.
|
||||
|
||||
Checks _initialize, async_added_to_hass and __init__.
|
||||
"""
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
# Setup entity
|
||||
@@ -218,7 +221,7 @@ async def test_async_update_sources_availability(
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test that the playback_source WebSocket event updates available playback sources."""
|
||||
"""Test playback_source WebSocket event updates sources."""
|
||||
# Remove video sources to simplify test
|
||||
mock_mozart_client.get_remote_menu.return_value = {}
|
||||
|
||||
@@ -237,7 +240,8 @@ async def test_async_update_sources_availability(
|
||||
items=[TEST_SOURCE]
|
||||
)
|
||||
|
||||
# Send playback_source. The source is not actually used, so its attributes don't matter
|
||||
# Send playback_source. The source is not actually
|
||||
# used, so its attributes don't matter
|
||||
playback_source_callback(Source())
|
||||
|
||||
assert mock_mozart_client.get_available_sources.call_count == 2
|
||||
@@ -298,12 +302,15 @@ async def test_async_update_playback_error(
|
||||
mock_mozart_client.get_playback_error_notifications.call_args[0][0]
|
||||
)
|
||||
|
||||
# The async_dispatcher_send function seems to swallow exceptions, making pytest.raises unusable
|
||||
# The async_dispatcher_send function seems to swallow
|
||||
# exceptions, making pytest.raises unusable
|
||||
playback_error_callback(TEST_PLAYBACK_ERROR)
|
||||
|
||||
assert (
|
||||
"Exception in _async_update_playback_error when dispatching 'bang_olufsen_11111111_playback_error': (PlaybackError(error='Test error', item=None),)"
|
||||
in caplog.text
|
||||
"Exception in _async_update_playback_error when"
|
||||
" dispatching"
|
||||
" 'bang_olufsen_11111111_playback_error':"
|
||||
" (PlaybackError(error='Test error', item=None),)" in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@@ -589,7 +596,8 @@ async def test_async_update_beolink_listener(
|
||||
# Called once for each entity during _initialize
|
||||
assert mock_mozart_client.get_beolink_listeners.call_count == 3
|
||||
# Called once for each entity during _initialize and
|
||||
# once more during _async_update_beolink for the entity that has the callback associated with it.
|
||||
# once more during _async_update_beolink for the entity
|
||||
# that has the callback associated with it.
|
||||
assert mock_mozart_client.get_beolink_peers.call_count == 4
|
||||
|
||||
# Main entity
|
||||
@@ -850,7 +858,7 @@ async def test_async_select_source(
|
||||
audio_source_call: int,
|
||||
video_source_call: int,
|
||||
) -> None:
|
||||
"""Test async_select_source with an invalid source and valid audio and video sources."""
|
||||
"""Test async_select_source with invalid/valid sources."""
|
||||
with expected_result:
|
||||
await hass.services.async_call(
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
@@ -970,7 +978,7 @@ async def test_async_play_media_overlay_absolute_volume_uri(
|
||||
integration: None,
|
||||
mock_mozart_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test async_play_media overlay with Home Assistant local URI and absolute volume."""
|
||||
"""Test async_play_media overlay with local URI."""
|
||||
await async_setup_component(hass, "media_source", {"media_source": {}})
|
||||
|
||||
await hass.services.async_call(
|
||||
@@ -1564,8 +1572,12 @@ async def test_async_beolink_join_invalid(
|
||||
[TEST_JID_3, TEST_JID_4],
|
||||
NotFoundException(),
|
||||
[
|
||||
f"Unable to expand to {TEST_JID_3}. Is the device available on the network?",
|
||||
f"Unable to expand to {TEST_JID_4}. Is the device available on the network?",
|
||||
"Unable to expand to "
|
||||
f"{TEST_JID_3}. Is the device "
|
||||
"available on the network?",
|
||||
"Unable to expand to "
|
||||
f"{TEST_JID_4}. Is the device "
|
||||
"available on the network?",
|
||||
],
|
||||
2,
|
||||
),
|
||||
@@ -1607,7 +1619,8 @@ async def test_async_beolink_expand(
|
||||
for log_message in log_messages:
|
||||
assert log_message in caplog.text
|
||||
|
||||
# Called once during _initialize and once during async_beolink_expand for all_discovered
|
||||
# Called once during _initialize and once during
|
||||
# async_beolink_expand for all_discovered
|
||||
assert mock_mozart_client.get_beolink_peers.call_count == peers_call_count
|
||||
|
||||
assert mock_mozart_client.post_beolink_expand.call_count == len(
|
||||
|
||||
@@ -124,7 +124,7 @@ async def test_on_remote_control_already_added(
|
||||
mock_mozart_client: AsyncMock,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test that the integration does nothing when a remote that already has a device triggers a check."""
|
||||
"""Test that a remote with existing device triggers no action."""
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
@@ -225,8 +225,9 @@ async def test_on_remote_control_paired(
|
||||
|
||||
# Check logger
|
||||
assert (
|
||||
f"A Beoremote One has been paired or unpaired to {mock_config_entry.title}. Reloading config entry to add device and entities"
|
||||
in caplog.text
|
||||
f"A Beoremote One has been paired or unpaired to"
|
||||
f" {mock_config_entry.title}. Reloading config entry"
|
||||
" to add device and entities" in caplog.text
|
||||
)
|
||||
|
||||
# Check number of entities (remote and button events and media_player)
|
||||
@@ -287,8 +288,9 @@ async def test_on_remote_control_unpaired(
|
||||
|
||||
# Check logger
|
||||
assert (
|
||||
f"A Beoremote One has been paired or unpaired to {mock_config_entry.title}. Reloading config entry to add device and entities"
|
||||
in caplog.text
|
||||
f"A Beoremote One has been paired or unpaired to"
|
||||
f" {mock_config_entry.title}. Reloading config entry"
|
||||
" to add device and entities" in caplog.text
|
||||
)
|
||||
|
||||
# Check number of entities (button events and media_player)
|
||||
@@ -305,13 +307,15 @@ async def test_on_remote_control_unpaired(
|
||||
# mock_config_entry: MockConfigEntry,
|
||||
# mock_mozart_client: AsyncMock,
|
||||
# ) -> None:
|
||||
# """Test async_setup_entry where a remote has been unpaired and should be removed."""
|
||||
# """Test async_setup_entry for unpaired remote removal."""
|
||||
|
||||
# # Load entry
|
||||
# mock_config_entry.add_to_hass(hass)
|
||||
# await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
# # Check device and API call count (called once during init and once in async_setup_entry in event.py)
|
||||
# # Check device and API call count
|
||||
# # (called once during init and once in
|
||||
# # async_setup_entry in event.py)
|
||||
# assert mock_mozart_client.get_bluetooth_remotes.call_count == 2
|
||||
# assert device_registry.async_get_device({(DOMAIN, TEST_REMOTE_SERIAL_PAIRED)})
|
||||
|
||||
@@ -357,7 +361,8 @@ async def test_on_all_notifications_raw(
|
||||
"eventType": "WebSocketEventVolume",
|
||||
}
|
||||
|
||||
# Get device ID for the modified notification that is sent as an event and in the log
|
||||
# Get device ID for the modified notification that is
|
||||
# sent as an event and in the log
|
||||
assert mock_config_entry.unique_id
|
||||
assert (
|
||||
device := device_registry.async_get_device(
|
||||
|
||||
@@ -25,7 +25,9 @@ from .const import (
|
||||
def _get_button_entity_ids(id_prefix: str = "living_room_balance") -> list[str]:
|
||||
"""Return a list of button entity_ids that Mozart devices provide.
|
||||
|
||||
Beoconnect Core, Beosound A5, Beosound A9 and Beosound Premiere do not have (all of the) physical buttons and need filtering.
|
||||
Beoconnect Core, Beosound A5, Beosound A9 and Beosound
|
||||
Premiere do not have (all of the) physical buttons and
|
||||
need filtering.
|
||||
"""
|
||||
return [
|
||||
f"event.{id_prefix}_{underscore(button_type)}".replace("preset", "favorite_")
|
||||
|
||||
@@ -347,7 +347,7 @@ async def test_battery_level_crossed_threshold_sensor_behavior_first(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test battery level_crossed_threshold trigger fires on the first sensor state change."""
|
||||
"""Test trigger fires on the first sensor state change."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
@@ -385,7 +385,7 @@ async def test_battery_level_crossed_threshold_sensor_behavior_last(
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test battery level_crossed_threshold trigger fires when the last sensor changes state."""
|
||||
"""Test trigger fires when the last sensor changes."""
|
||||
await assert_trigger_behavior_last(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
|
||||
@@ -217,9 +217,14 @@ async def _test_sensor_numeric_state(
|
||||
"sensor.test_monitored"
|
||||
]
|
||||
assert abs(state.attributes.get("probability") - 0.111) < 0.01
|
||||
# As abve but since the value is equal to 4 then this is a negative observation (~B) where P(~B) == 1 - P(B) because B is binary
|
||||
# We therefore want to calculate P(A|~B) so we use P(~B|A) (1-0.7) and P(~B|~A) (1-0.4)
|
||||
# Calculated using bayes theorum where P(A) = 0.2, P(~B|A) = 1-0.7 (as negative observation), P(~B|notA) = 1-0.4 -> 0.11
|
||||
# As above but since the value is equal to 4 then this
|
||||
# is a negative observation (~B) where
|
||||
# P(~B) == 1 - P(B) because B is binary
|
||||
# We therefore want to calculate P(A|~B) so we use
|
||||
# P(~B|A) (1-0.7) and P(~B|~A) (1-0.4)
|
||||
# Calculated using bayes theorem where P(A) = 0.2,
|
||||
# P(~B|A) = 1-0.7 (as negative observation),
|
||||
# P(~B|notA) = 1-0.4 -> 0.11
|
||||
|
||||
assert state.state == "off"
|
||||
|
||||
@@ -233,7 +238,9 @@ async def _test_sensor_numeric_state(
|
||||
assert state.attributes.get("observations")[1]["prob_given_true"] == 0.9
|
||||
assert state.attributes.get("observations")[1]["prob_given_false"] == 0.2
|
||||
assert abs(state.attributes.get("probability") - 0.663) < 0.01
|
||||
# Here we have two positive observations as both are in range. We do a 2-step bayes. The output of the first is used as the (updated) prior in the second.
|
||||
# Here we have two positive observations as both are in
|
||||
# range. We do a 2-step bayes. The output of the first
|
||||
# is used as the (updated) prior in the second.
|
||||
# 1st step P(A) = 0.2, P(B|A) = 0.7, P(B|notA) = 0.4 -> 0.304
|
||||
# 2nd update: P(A) = 0.304, P(B|A) = 0.9, P(B|notA) = 0.2 -> 0.663
|
||||
|
||||
@@ -246,7 +253,8 @@ async def _test_sensor_numeric_state(
|
||||
|
||||
state = hass.states.get("binary_sensor.test_binary")
|
||||
assert abs(state.attributes.get("probability") - 0.0153) < 0.01
|
||||
# Calculated using bayes theorum where P(A) = 0.2, P(~B|A) = 0.3, P(~B|notA) = 0.6 -> 0.11
|
||||
# Calculated using bayes theorem where P(A) = 0.2,
|
||||
# P(~B|A) = 0.3, P(~B|notA) = 0.6 -> 0.11
|
||||
# 2nd update: P(A) = 0.111, P(~B|A) = 0.1, P(~B|notA) = 0.8
|
||||
|
||||
assert state.state == "off"
|
||||
@@ -336,7 +344,9 @@ async def _test_sensor_state(hass: HomeAssistant, prior: float) -> None:
|
||||
assert state.attributes.get("observations")[0]["prob_given_true"] == 0.8
|
||||
assert state.attributes.get("observations")[0]["prob_given_false"] == 0.4
|
||||
assert abs(0.0769 - state.attributes.get("probability")) < 0.01
|
||||
# Calculated using bayes theorum where P(A) = 0.2, P(~B|A) = 0.2 (as negative observation), P(~B|notA) = 0.6
|
||||
# Calculated using bayes theorem where P(A) = 0.2,
|
||||
# P(~B|A) = 0.2 (as negative observation),
|
||||
# P(~B|notA) = 0.6
|
||||
assert state.state == "off"
|
||||
|
||||
hass.states.async_set("sensor.test_monitored", "off")
|
||||
@@ -347,7 +357,9 @@ async def _test_sensor_state(hass: HomeAssistant, prior: float) -> None:
|
||||
"sensor.test_monitored"
|
||||
]
|
||||
assert abs(0.33 - state.attributes.get("probability")) < 0.01
|
||||
# Calculated using bayes theorum where P(A) = 0.2, P(~B|A) = 0.8 (as negative observation), P(~B|notA) = 0.4
|
||||
# Calculated using bayes theorem where P(A) = 0.2,
|
||||
# P(~B|A) = 0.8 (as negative observation),
|
||||
# P(~B|notA) = 0.4
|
||||
assert state.state == "on"
|
||||
|
||||
hass.states.async_remove("sensor.test_monitored")
|
||||
@@ -441,7 +453,9 @@ async def _test_sensor_value_template(hass: HomeAssistant) -> None:
|
||||
|
||||
assert state.attributes.get("occurred_observation_entities") == []
|
||||
assert abs(0.0769 - state.attributes.get("probability")) < 0.01
|
||||
# Calculated using bayes theorum where P(A) = 0.2, P(~B|A) = 0.2 (as negative observation), P(~B|notA) = 0.6
|
||||
# Calculated using bayes theorem where P(A) = 0.2,
|
||||
# P(~B|A) = 0.2 (as negative observation),
|
||||
# P(~B|notA) = 0.6
|
||||
|
||||
assert state.state == "off"
|
||||
|
||||
@@ -461,7 +475,9 @@ async def _test_sensor_value_template(hass: HomeAssistant) -> None:
|
||||
|
||||
state = hass.states.get("binary_sensor.test_binary")
|
||||
assert abs(0.076923 - state.attributes.get("probability")) < 0.01
|
||||
# Calculated using bayes theorum where P(A) = 0.2, P(~B|A) = 0.2 (as negative observation), P(~B|notA) = 0.6
|
||||
# Calculated using bayes theorem where P(A) = 0.2,
|
||||
# P(~B|A) = 0.2 (as negative observation),
|
||||
# P(~B|notA) = 0.6
|
||||
|
||||
assert state.state == "off"
|
||||
|
||||
@@ -594,8 +610,10 @@ async def _test_mixed_states(hass: HomeAssistant) -> None:
|
||||
# Calculated where P(A) = 0.3, P(B|A) = 0.3 , P(B|notA) = 0.15 = 0.46153846
|
||||
# Step 2, prior is now 0.46153846, B now refers to sensor.anyone_home=='on'
|
||||
# P(A) = 0.46153846, P(B|A) = 0.6 , P(B|notA) = 0.05, result = 0.91139240
|
||||
# Step 3, prior is now 0.91139240, B now refers to sensor.temperature in range [19,24]
|
||||
# However since the temp is 15 we take the inverse probability for this negative observation
|
||||
# Step 3, prior is now 0.91139240, B now refers to
|
||||
# sensor.temperature in range [19,24]
|
||||
# However since the temp is 15 we take the inverse
|
||||
# probability for this negative observation
|
||||
# P(A) = 0.91139240, P(B|A) = (1-0.1) , P(B|notA) = (1-0.6), result = 0.95857988
|
||||
|
||||
|
||||
@@ -677,8 +695,12 @@ async def _test_threshold(
|
||||
async def test_multiple_observations(hass: HomeAssistant) -> None:
|
||||
"""Test sensor with multiple observations of same entity.
|
||||
|
||||
these entries should be labelled as 'state' and negative observations ignored - as the outcome is not known to be binary.
|
||||
Before the merge of #67631 this practice was a common work-around for bayesian's ignoring of negative observations,
|
||||
these entries should be labelled as 'state' and negative
|
||||
observations ignored - as the outcome is not known to be
|
||||
binary.
|
||||
Before the merge of #67631 this practice was a common
|
||||
work-around for bayesian's ignoring of negative
|
||||
observations,
|
||||
this also preserves that function
|
||||
"""
|
||||
prior = 0.2
|
||||
@@ -771,7 +793,8 @@ async def _test_multiple_observations(hass: HomeAssistant, prior: float) -> None
|
||||
json.dumps(attrs)
|
||||
assert state.attributes.get("occurred_observation_entities") == []
|
||||
assert state.attributes.get("probability") == prior
|
||||
# probability should be the same as the prior as negative observations are ignored in multi-state
|
||||
# probability should be the same as the prior as
|
||||
# negative observations are ignored in multi-state
|
||||
|
||||
assert state.state == "off"
|
||||
|
||||
@@ -979,7 +1002,8 @@ async def _test_multiple_numeric_observations(
|
||||
# Bayes theorum is P(A|B) = P(B|A) * P(A) / ( P(B|A)*P(A) + P(B|~A)*P(~A) ).
|
||||
# Where P(B|A) is prob_given_true and P(B|~A) is prob_given_false
|
||||
# Calculated using P(A) = 0.3, P(B|A) = 0.05, P(B|~A) = 0.2 -> 0.09677
|
||||
# Because >1 range is defined for sensor.test_temp we should not infer anything from the
|
||||
# Because >1 range is defined for sensor.test_temp we
|
||||
# should not infer anything from the
|
||||
# ranges not observed
|
||||
assert state.state == "off"
|
||||
|
||||
@@ -995,7 +1019,8 @@ async def _test_multiple_numeric_observations(
|
||||
# Bayes theorum is P(A|B) = P(B|A) * P(A) / ( P(B|A)*P(A) + P(B|~A)*P(~A) ).
|
||||
# Where P(B|A) is prob_given_true and P(B|~A) is prob_given_false
|
||||
# Calculated using P(A) = 0.3, P(B|A) = 0.1, P(B|~A) = 0.25 -> 0.14634146
|
||||
# Because >1 range is defined for sensor.test_temp we should not infer anything from the
|
||||
# Because >1 range is defined for sensor.test_temp we
|
||||
# should not infer anything from the
|
||||
# ranges not observed
|
||||
|
||||
assert state.state == "off"
|
||||
@@ -1010,7 +1035,8 @@ async def _test_multiple_numeric_observations(
|
||||
# Bayes theorum is P(A|B) = P(B|A) * P(A) / ( P(B|A)*P(A) + P(B|~A)*P(~A) ).
|
||||
# Where P(B|A) is prob_given_true and P(B|~A) is prob_given_false
|
||||
# Calculated using P(A) = 0.3, P(B|A) = 0.2, P(B|~A) = 0.35 -> 0.19672131
|
||||
# Because >1 range is defined for sensor.test_temp we should not infer anything from the
|
||||
# Because >1 range is defined for sensor.test_temp we
|
||||
# should not infer anything from the
|
||||
# ranges not observed
|
||||
|
||||
assert state.state == "off"
|
||||
@@ -1025,7 +1051,8 @@ async def _test_multiple_numeric_observations(
|
||||
# Bayes theorum is P(A|B) = P(B|A) * P(A) / ( P(B|A)*P(A) + P(B|~A)*P(~A) ).
|
||||
# Where P(B|A) is prob_given_true and P(B|~A) is prob_given_false
|
||||
# Calculated using P(A) = 0.3, P(B|A) = 0.5, P(B|~A) = 0.15 -> 0.58823529
|
||||
# Because >1 range is defined for sensor.test_temp we should not infer anything from the
|
||||
# Because >1 range is defined for sensor.test_temp we
|
||||
# should not infer anything from the
|
||||
# ranges not observed
|
||||
|
||||
assert state.state == "on"
|
||||
@@ -1040,7 +1067,8 @@ async def _test_multiple_numeric_observations(
|
||||
# Bayes theorum is P(A|B) = P(B|A) * P(A) / ( P(B|A)*P(A) + P(B|~A)*P(~A) ).
|
||||
# Where P(B|A) is prob_given_true and P(B|~A) is prob_given_false
|
||||
# Calculated using P(A) = 0.3, P(B|A) = 0.15, P(B|~A) = 0.05 -> 0.562500
|
||||
# Because >1 range is defined for sensor.test_temp we should not infer anything from the
|
||||
# Because >1 range is defined for sensor.test_temp we
|
||||
# should not infer anything from the
|
||||
# ranges not observed
|
||||
|
||||
assert state.state == "on"
|
||||
@@ -1061,7 +1089,8 @@ async def _test_multiple_numeric_observations(
|
||||
# Bayes theorum is P(A|B) = P(B|A) * P(A) / ( P(B|A)*P(A) + P(B|~A)*P(~A) ).
|
||||
# Where P(B|A) is prob_given_true and P(B|~A) is prob_given_false
|
||||
# Calculated using P(A) = 0.3, P(B|A) = 0.2, P(B|~A) = 0.35 -> 0.19672131
|
||||
# Because >1 range is defined for sensor.test_temp we should not infer anything from the
|
||||
# Because >1 range is defined for sensor.test_temp we
|
||||
# should not infer anything from the
|
||||
# ranges not observed
|
||||
|
||||
assert state.state == "off"
|
||||
@@ -1333,7 +1362,7 @@ async def _test_mirrored_observations(
|
||||
async def test_missing_prob_given_false(
|
||||
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||
) -> None:
|
||||
"""Test whether missing prob_given_false in YAML are detected and appropriate issues are created."""
|
||||
"""Test missing prob_given_false detection in YAML."""
|
||||
|
||||
config = {
|
||||
"binary_sensor": {
|
||||
@@ -1381,7 +1410,11 @@ async def test_bad_multi_numeric(
|
||||
issue_registry: ir.IssueRegistry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test whether overlaps are detected in YAML configs, in Config Entries this is detected during the config flow and is tested elsewhere."""
|
||||
"""Test whether overlaps are detected in YAML configs.
|
||||
|
||||
In Config Entries this is detected during the config
|
||||
flow and is tested elsewhere.
|
||||
"""
|
||||
|
||||
config = {
|
||||
"binary_sensor": {
|
||||
@@ -1443,7 +1476,11 @@ async def test_inverted_numeric(
|
||||
issue_registry: ir.IssueRegistry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test whether inverted numeric states are detected in YAML configs, for config entries this is detected during config flow validation and so is tested elsewhere."""
|
||||
"""Test inverted numeric state detection in YAML.
|
||||
|
||||
For config entries this is detected during config flow
|
||||
validation and so is tested elsewhere.
|
||||
"""
|
||||
|
||||
config = {
|
||||
"binary_sensor": {
|
||||
@@ -1475,7 +1512,11 @@ async def test_no_value_numeric(
|
||||
issue_registry: ir.IssueRegistry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Tests whether numeric states with no above or below are detected in YAML configs, for config entries this is detected during config flow validation and so is tested elsewhere."""
|
||||
"""Test numeric states with no above or below in YAML.
|
||||
|
||||
For config entries this is detected during config flow
|
||||
validation and so is tested elsewhere.
|
||||
"""
|
||||
|
||||
config = {
|
||||
"binary_sensor": {
|
||||
@@ -1606,7 +1647,12 @@ async def test_observed_entities_config_entry(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def _test_observed_entities(hass: HomeAssistant) -> None:
|
||||
"""Common test code for occurred_observation_entities. This test reveals some interesting historic behaviour - the last entity to update a template is the one that is recorded as having made the observation."""
|
||||
"""Common test code for occurred_observation_entities.
|
||||
|
||||
This test reveals some interesting historic behaviour -
|
||||
the last entity to update a template is the one that is
|
||||
recorded as having made the observation.
|
||||
"""
|
||||
hass.states.async_set("sensor.test_monitored", "on")
|
||||
await hass.async_block_till_done()
|
||||
hass.states.async_set("sensor.test_monitored1", "off")
|
||||
@@ -2001,7 +2047,8 @@ async def _test_monitored_sensor_goes_away(hass: HomeAssistant, prior: float) ->
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("binary_sensor.test_binary").state == "on"
|
||||
# Calculated using bayes theorum where P(A) = 0.2, P(B|A) = 0.9, P(B|notA) = 0.4 -> 0.36 (>0.32)
|
||||
# Calculated using bayes theorem where P(A) = 0.2,
|
||||
# P(B|A) = 0.9, P(B|notA) = 0.4 -> 0.36 (>0.32)
|
||||
|
||||
hass.states.async_remove("sensor.test_monitored")
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -215,7 +215,16 @@ False
|
||||
},
|
||||
{
|
||||
CONF_PLATFORM: str(ObservationTypes.TEMPLATE),
|
||||
CONF_VALUE_TEMPLATE: '{% set current_time = now().time() %}\n{% set start_time = strptime("07:00", "%H:%M").time() %}\n{% set end_time = strptime("18:30", "%H:%M").time() %}\n{% if start_time <= current_time <= end_time %}\nTrue\n{% else %}\nFalse\n{% endif %}',
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{% set current_time = now().time() %}\n"
|
||||
'{% set start_time = strptime("07:00",'
|
||||
' "%H:%M").time() %}\n'
|
||||
'{% set end_time = strptime("18:30",'
|
||||
' "%H:%M").time() %}\n'
|
||||
"{% if start_time <= current_time"
|
||||
" <= end_time %}\nTrue\n"
|
||||
"{% else %}\nFalse\n{% endif %}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 0.45,
|
||||
CONF_P_GIVEN_F: 0.05,
|
||||
CONF_NAME: "Daylight hours",
|
||||
@@ -307,7 +316,8 @@ async def test_single_state_observation(hass: HomeAssistant) -> None:
|
||||
async def test_single_numeric_state_observation(hass: HomeAssistant) -> None:
|
||||
"""Test a Bayesian sensor with just one numeric_state observation added.
|
||||
|
||||
Combines the config flow and the options flow for a single numeric_state observation.
|
||||
Combines the config flow and the options flow for a
|
||||
single numeric_state observation.
|
||||
"""
|
||||
|
||||
with patch(
|
||||
@@ -551,7 +561,14 @@ async def test_single_template_observation(hass: HomeAssistant) -> None:
|
||||
result = await hass.config_entries.subentries.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
CONF_VALUE_TEMPLATE: "{{is_state('device_tracker.paulus','not_home') and ((as_timestamp(now()) - as_timestamp(states.device_tracker.paulus.last_changed)) > 300)}}",
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{{is_state('device_tracker.paulus',"
|
||||
"'not_home') and"
|
||||
" ((as_timestamp(now()) -"
|
||||
" as_timestamp(states"
|
||||
".device_tracker.paulus"
|
||||
".last_changed)) > 300)}}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 5,
|
||||
CONF_P_GIVEN_F: 99,
|
||||
CONF_NAME: "Not seen in last 5 minutes",
|
||||
@@ -568,7 +585,14 @@ async def test_single_template_observation(hass: HomeAssistant) -> None:
|
||||
assert len(config_entry.subentries) == 1
|
||||
assert list(config_entry.subentries.values())[0].data == {
|
||||
CONF_PLATFORM: str(ObservationTypes.TEMPLATE),
|
||||
CONF_VALUE_TEMPLATE: "{{is_state('device_tracker.paulus','not_home') and ((as_timestamp(now()) - as_timestamp(states.device_tracker.paulus.last_changed)) > 300)}}",
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{{is_state('device_tracker.paulus',"
|
||||
"'not_home') and"
|
||||
" ((as_timestamp(now()) -"
|
||||
" as_timestamp(states"
|
||||
".device_tracker.paulus"
|
||||
".last_changed)) > 300)}}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 0.05,
|
||||
CONF_P_GIVEN_F: 0.99,
|
||||
CONF_NAME: "Not seen in last 5 minutes",
|
||||
@@ -710,7 +734,16 @@ async def test_reconfiguring_observations(hass: HomeAssistant) -> None:
|
||||
data=MappingProxyType(
|
||||
{
|
||||
CONF_PLATFORM: str(ObservationTypes.TEMPLATE),
|
||||
CONF_VALUE_TEMPLATE: '{% set current_time = now().time() %}\n{% set start_time = strptime("07:00", "%H:%M").time() %}\n{% set end_time = strptime("18:30", "%H:%M").time() %}\n{% if start_time <= current_time <= end_time %}\nTrue\n{% else %}\nFalse\n{% endif %}',
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{% set current_time = now().time() %}\n"
|
||||
'{% set start_time = strptime("07:00",'
|
||||
' "%H:%M").time() %}\n'
|
||||
'{% set end_time = strptime("18:30",'
|
||||
' "%H:%M").time() %}\n'
|
||||
"{% if start_time <= current_time"
|
||||
" <= end_time %}\nTrue\n"
|
||||
"{% else %}\nFalse\n{% endif %}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 0.45,
|
||||
CONF_P_GIVEN_F: 0.05,
|
||||
CONF_NAME: "Daylight hours",
|
||||
@@ -790,7 +823,16 @@ async def test_reconfiguring_observations(hass: HomeAssistant) -> None:
|
||||
},
|
||||
{
|
||||
CONF_PLATFORM: str(ObservationTypes.TEMPLATE),
|
||||
CONF_VALUE_TEMPLATE: '{% set current_time = now().time() %}\n{% set start_time = strptime("07:00", "%H:%M").time() %}\n{% set end_time = strptime("18:30", "%H:%M").time() %}\n{% if start_time <= current_time <= end_time %}\nTrue\n{% else %}\nFalse\n{% endif %}',
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{% set current_time = now().time() %}\n"
|
||||
'{% set start_time = strptime("07:00",'
|
||||
' "%H:%M").time() %}\n'
|
||||
'{% set end_time = strptime("18:30",'
|
||||
' "%H:%M").time() %}\n'
|
||||
"{% if start_time <= current_time"
|
||||
" <= end_time %}\nTrue\n"
|
||||
"{% else %}\nFalse\n{% endif %}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 0.45,
|
||||
CONF_P_GIVEN_F: 0.05,
|
||||
CONF_NAME: "Daylight hours",
|
||||
@@ -873,7 +915,16 @@ async def test_reconfiguring_observations(hass: HomeAssistant) -> None:
|
||||
},
|
||||
{
|
||||
CONF_PLATFORM: str(ObservationTypes.TEMPLATE),
|
||||
CONF_VALUE_TEMPLATE: '{% set current_time = now().time() %}\n{% set start_time = strptime("07:00", "%H:%M").time() %}\n{% set end_time = strptime("18:30", "%H:%M").time() %}\n{% if start_time <= current_time <= end_time %}\nTrue\n{% else %}\nFalse\n{% endif %}',
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{% set current_time = now().time() %}\n"
|
||||
'{% set start_time = strptime("07:00",'
|
||||
' "%H:%M").time() %}\n'
|
||||
'{% set end_time = strptime("18:30",'
|
||||
' "%H:%M").time() %}\n'
|
||||
"{% if start_time <= current_time"
|
||||
" <= end_time %}\nTrue\n"
|
||||
"{% else %}\nFalse\n{% endif %}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 0.45,
|
||||
CONF_P_GIVEN_F: 0.05,
|
||||
CONF_NAME: "Daylight hours",
|
||||
@@ -943,7 +994,16 @@ False
|
||||
},
|
||||
{
|
||||
CONF_PLATFORM: str(ObservationTypes.TEMPLATE),
|
||||
CONF_VALUE_TEMPLATE: '{% set current_time = now().time() %}\n{% set start_time = strptime("07:00", "%H:%M").time() %}\n{% set end_time = strptime("17:30", "%H:%M").time() %}\n{% if start_time <= current_time <= end_time %}\nTrue\n{% else %}\nFalse\n{% endif %}',
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{% set current_time = now().time() %}\n"
|
||||
'{% set start_time = strptime("07:00",'
|
||||
' "%H:%M").time() %}\n'
|
||||
'{% set end_time = strptime("17:30",'
|
||||
' "%H:%M").time() %}\n'
|
||||
"{% if start_time <= current_time"
|
||||
" <= end_time %}\nTrue\n"
|
||||
"{% else %}\nFalse\n{% endif %}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 0.55,
|
||||
CONF_P_GIVEN_F: 0.13,
|
||||
CONF_NAME: "Office hours",
|
||||
@@ -1141,7 +1201,9 @@ async def test_invalid_configs(hass: HomeAssistant) -> None:
|
||||
result = await hass.config_entries.subentries.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
CONF_VALUE_TEMPLATE: "{{ is_state('device_tracker.paulus', 'not_home') }}",
|
||||
CONF_VALUE_TEMPLATE: (
|
||||
"{{ is_state('device_tracker.paulus', 'not_home') }}"
|
||||
),
|
||||
CONF_P_GIVEN_T: 50,
|
||||
CONF_P_GIVEN_F: 50,
|
||||
CONF_NAME: "Paulus not home",
|
||||
|
||||
@@ -193,6 +193,6 @@ async def test_entity_category_config_raises_error(
|
||||
state2 = hass.states.get("binary_sensor.test2")
|
||||
assert state2 is None
|
||||
assert (
|
||||
"Entity binary_sensor.test2 cannot be added as the entity category is set to config"
|
||||
in caplog.text
|
||||
"Entity binary_sensor.test2 cannot be added as the"
|
||||
" entity category is set to config" in caplog.text
|
||||
)
|
||||
|
||||
@@ -108,7 +108,7 @@ async def test_toggle(
|
||||
async def test_setting_change(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, entity_registry: EntityRegistry
|
||||
) -> None:
|
||||
"""Test if the state of the switches are updated when an update message from the websocket comes in."""
|
||||
"""Test switch state updates from websocket messages."""
|
||||
integration = await init_integration(hass, config_entry, Platform.SWITCH)
|
||||
client_mock = integration[0]
|
||||
|
||||
|
||||
@@ -54,7 +54,12 @@ NOT_BLUEMAESTRO_SERVICE_INFO = make_bluetooth_service_info(
|
||||
BLUEMAESTRO_SERVICE_INFO = make_bluetooth_service_info(
|
||||
name="FA17B62C",
|
||||
manufacturer_data={
|
||||
307: b"\x17d\x0e\x10\x00\x02\x00\xf2\x01\xf2\x00\x83\x01\x00\x01\r\x02\xab\x00\xf2\x01\xf2\x01\r\x02\xab\x00\xf2\x01\xf2\x00\xff\x02N\x00\x00\x00\x00\x00"
|
||||
307: (
|
||||
b"\x17d\x0e\x10\x00\x02\x00\xf2\x01\xf2\x00\x83"
|
||||
b"\x01\x00\x01\r\x02\xab\x00\xf2\x01\xf2\x01\r"
|
||||
b"\x02\xab\x00\xf2\x01\xf2\x00\xff\x02N\x00\x00"
|
||||
b"\x00\x00\x00"
|
||||
)
|
||||
},
|
||||
address="aa:bb:cc:dd:ee:ff",
|
||||
rssi=-60,
|
||||
|
||||
@@ -44,7 +44,8 @@ def blueprint_2(request: pytest.FixtureRequest) -> models.Blueprint:
|
||||
"example-default": Input("test-input-default"),
|
||||
}
|
||||
if request.param:
|
||||
# Replace the inputs with inputs in sections. Test should otherwise behave the same.
|
||||
# Replace the inputs with inputs in sections.
|
||||
# Test should otherwise behave the same.
|
||||
blueprint["blueprint"]["input"] = {
|
||||
"section-1": {
|
||||
"name": "Section 1",
|
||||
|
||||
@@ -191,7 +191,10 @@ async def player_mocks() -> AsyncGenerator[PlayerMocks]:
|
||||
)
|
||||
|
||||
# to simulate a player that is already configured
|
||||
player_mocks.player_data_for_already_configured.sync_status_long_polling_mock.get().mac = player_mocks.player_data.sync_status_long_polling_mock.get().mac
|
||||
already_configured = player_mocks.player_data_for_already_configured
|
||||
already_configured.sync_status_long_polling_mock.get().mac = (
|
||||
player_mocks.player_data.sync_status_long_polling_mock.get().mac
|
||||
)
|
||||
|
||||
def select_player(*args: Any, **kwargs: Any) -> AsyncMock:
|
||||
match args[0]:
|
||||
|
||||
@@ -36,7 +36,8 @@ async def test_unload_entry_while_player_is_offline(
|
||||
)
|
||||
player_mocks.player_data.status_long_polling_mock.trigger()
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
|
||||
@@ -182,7 +182,8 @@ async def test_stop_maps_to_idle(
|
||||
)
|
||||
)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert (
|
||||
@@ -204,7 +205,8 @@ async def test_status_updated(
|
||||
status = dataclasses.replace(status, state="pause", volume=50, etag="changed")
|
||||
player_mocks.player_data.status_long_polling_mock.set(status)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
post_state = hass.states.get("media_player.player_name1111")
|
||||
@@ -227,7 +229,8 @@ async def test_unavailable_when_offline(
|
||||
)
|
||||
player_mocks.player_data.status_long_polling_mock.trigger()
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
post_state = hass.states.get("media_player.player_name1111")
|
||||
@@ -286,7 +289,8 @@ async def test_unjoin(
|
||||
)
|
||||
player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
@@ -318,7 +322,8 @@ async def test_attr_master(
|
||||
)
|
||||
player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
attr_master = hass.states.get("media_player.player_name1111").attributes[
|
||||
@@ -346,7 +351,8 @@ async def test_attr_bluesound_group(
|
||||
)
|
||||
player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
attr_bluesound_group = hass.states.get(
|
||||
@@ -374,7 +380,8 @@ async def test_attr_bluesound_group_for_follower(
|
||||
)
|
||||
player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
updated_sync_status = dataclasses.replace(
|
||||
@@ -385,7 +392,8 @@ async def test_attr_bluesound_group_for_follower(
|
||||
updated_sync_status
|
||||
)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
attr_bluesound_group = hass.states.get(
|
||||
@@ -402,7 +410,9 @@ async def test_volume_up_from_6_to_7(
|
||||
) -> None:
|
||||
"""Test the media player volume up from 6 to 7.
|
||||
|
||||
This fails if if rounding is not done correctly. See https://github.com/home-assistant/core/issues/129956 for more details.
|
||||
This fails if rounding is not done correctly. See
|
||||
https://github.com/home-assistant/core/issues/129956
|
||||
for more details.
|
||||
"""
|
||||
player_mocks.player_data.status_long_polling_mock.set(
|
||||
dataclasses.replace(
|
||||
@@ -410,7 +420,8 @@ async def test_volume_up_from_6_to_7(
|
||||
)
|
||||
)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
@@ -441,7 +452,8 @@ async def test_attr_group_members(
|
||||
)
|
||||
player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
attr_group_members = hass.states.get("media_player.player_name1111").attributes.get(
|
||||
@@ -505,7 +517,8 @@ async def test_unjoin_player(
|
||||
)
|
||||
player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status)
|
||||
|
||||
# give the long polling loop a chance to update the state; this could be any async call
|
||||
# give the long polling loop a chance to update the
|
||||
# state; this could be any async call
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
|
||||
@@ -190,7 +190,7 @@ def inject_advertisement_with_time_and_source_connectable(
|
||||
connectable: bool,
|
||||
raw: bytes | None = None,
|
||||
) -> None:
|
||||
"""Inject an advertisement into the manager from a specific source at a time and connectable status."""
|
||||
"""Inject an advertisement at a time from a source with connectable status."""
|
||||
async_get_advertisement_callback(hass)(
|
||||
BluetoothServiceInfoBleak(
|
||||
name=adv.local_name or device.name or device.address,
|
||||
|
||||
@@ -133,7 +133,7 @@ async def test_advertisment_interval_longer_than_adapter_stack_timeout_connectab
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth", "macos_adapter")
|
||||
async def test_advertisment_interval_longer_than_adapter_stack_timeout_adapter_change_connectable(
|
||||
async def test_adv_interval_longer_than_stack_timeout_adapter_change_connectable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test device with a long advertisement interval with an adapter change."""
|
||||
@@ -199,7 +199,11 @@ async def test_advertisment_interval_longer_than_adapter_stack_timeout_adapter_c
|
||||
async def test_advertisment_interval_longer_than_adapter_stack_timeout_not_connectable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test device with a long advertisement interval that is not connectable not reaching the advertising interval."""
|
||||
"""Test device with a long advertisement interval.
|
||||
|
||||
Device is not connectable and not reaching the
|
||||
advertising interval.
|
||||
"""
|
||||
start_monotonic_time = time.monotonic()
|
||||
switchbot_device = generate_ble_device("44:44:33:11:23:45", "wohand")
|
||||
switchbot_adv = generate_advertisement_data(
|
||||
@@ -249,10 +253,13 @@ async def test_advertisment_interval_longer_than_adapter_stack_timeout_not_conne
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth", "macos_adapter")
|
||||
async def test_advertisment_interval_shorter_than_adapter_stack_timeout_adapter_change_not_connectable(
|
||||
async def test_adv_interval_shorter_than_stack_timeout_change_not_connectable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test device with a short advertisement interval with an adapter change that is not connectable."""
|
||||
"""Test device with short adv interval, adapter change.
|
||||
|
||||
Device is not connectable.
|
||||
"""
|
||||
start_monotonic_time = time.monotonic()
|
||||
switchbot_device = generate_ble_device("44:44:33:11:23:5C", "wohand")
|
||||
switchbot_adv = generate_advertisement_data(
|
||||
@@ -322,10 +329,13 @@ async def test_advertisment_interval_shorter_than_adapter_stack_timeout_adapter_
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth", "macos_adapter")
|
||||
async def test_advertisment_interval_longer_than_adapter_stack_timeout_adapter_change_not_connectable(
|
||||
async def test_adv_interval_longer_than_stack_timeout_change_not_connectable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test device with a long advertisement interval with an adapter change that is not connectable."""
|
||||
"""Test device with long adv interval, adapter change.
|
||||
|
||||
Device is not connectable.
|
||||
"""
|
||||
start_monotonic_time = time.monotonic()
|
||||
switchbot_device = generate_ble_device("44:44:33:11:23:45", "wohand")
|
||||
switchbot_adv = generate_advertisement_data(
|
||||
@@ -426,10 +436,13 @@ async def test_advertisment_interval_longer_than_adapter_stack_timeout_adapter_c
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth", "macos_adapter")
|
||||
async def test_advertisment_interval_longer_increasing_than_adapter_stack_timeout_adapter_change_not_connectable(
|
||||
async def test_adv_interval_longer_increasing_than_stack_timeout_not_connectable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test device with a increasing advertisement interval with an adapter change that is not connectable."""
|
||||
"""Test device with increasing adv interval.
|
||||
|
||||
Adapter change, device is not connectable.
|
||||
"""
|
||||
start_monotonic_time = time.monotonic()
|
||||
switchbot_device = generate_ble_device("44:44:33:11:23:45", "wohand")
|
||||
switchbot_adv = generate_advertisement_data(
|
||||
|
||||
@@ -258,7 +258,7 @@ async def test_remote_scanner_expires_non_connectable(hass: HomeAssistant) -> No
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_base_scanner_connecting_behavior(hass: HomeAssistant) -> None:
|
||||
"""Test that the default behavior is to mark the scanner as not scanning when connecting."""
|
||||
"""Test scanner is marked as not scanning when connecting."""
|
||||
manager = _get_manager()
|
||||
|
||||
switchbot_device = generate_ble_device(
|
||||
@@ -481,7 +481,8 @@ async def test_scanner_stops_responding(hass: HomeAssistant) -> None:
|
||||
+ SCANNER_WATCHDOG_TIMEOUT
|
||||
+ SCANNER_WATCHDOG_INTERVAL.total_seconds()
|
||||
)
|
||||
# We hit the timer with no detections, so we reset the adapter and restart the scanner
|
||||
# We hit the timer with no detections, so we reset the
|
||||
# adapter and restart the scanner
|
||||
with patch_bluetooth_time(failure_reached_time):
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -363,7 +363,7 @@ async def test_no_race_during_manual_reload_in_retry_state(
|
||||
async def test_calling_async_discovered_devices_no_bluetooth(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test we fail gracefully when asking for discovered devices and there is no blueooth."""
|
||||
"""Test we fail gracefully when there is no bluetooth."""
|
||||
mock_bt = []
|
||||
with (
|
||||
patch(
|
||||
@@ -488,7 +488,7 @@ def _domains_from_mock_config_flow(mock_config_flow: Mock) -> list[str]:
|
||||
async def test_discovery_match_by_service_uuid_connectable(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test bluetooth discovery match by service_uuid and the ble device is connectable."""
|
||||
"""Test discovery match by service_uuid, connectable."""
|
||||
mock_bt = [
|
||||
{
|
||||
"domain": "switchbot",
|
||||
@@ -540,7 +540,7 @@ async def test_discovery_match_by_service_uuid_connectable(
|
||||
async def test_discovery_match_by_service_uuid_not_connectable(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test bluetooth discovery match by service_uuid and the ble device is not connectable."""
|
||||
"""Test discovery match by service_uuid, not connectable."""
|
||||
mock_bt = [
|
||||
{
|
||||
"domain": "switchbot",
|
||||
@@ -590,7 +590,7 @@ async def test_discovery_match_by_service_uuid_not_connectable(
|
||||
async def test_discovery_match_by_name_connectable_false(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test bluetooth discovery match by name and the integration will take non-connectable devices."""
|
||||
"""Test discovery match by name with non-connectable."""
|
||||
mock_bt = [
|
||||
{
|
||||
"domain": "qingping",
|
||||
@@ -708,7 +708,7 @@ async def test_discovery_match_by_local_name(
|
||||
async def test_discovery_match_by_service_uuid_when_name_changes_from_mac(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test bluetooth discovery still matches when name changes from MAC address to real name."""
|
||||
"""Test discovery matches when name changes from MAC."""
|
||||
mock_bt = [
|
||||
{
|
||||
"domain": "improv_ble",
|
||||
@@ -1128,7 +1128,7 @@ async def test_discovery_match_by_service_data_uuid_bthome(
|
||||
async def test_discovery_match_first_by_service_uuid_and_then_manufacturer_id(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test bluetooth discovery matches twice for service_uuid and then manufacturer_id."""
|
||||
"""Test discovery matches for service_uuid then mfr_id."""
|
||||
mock_bt = [
|
||||
{
|
||||
"domain": "my_domain",
|
||||
@@ -1283,7 +1283,8 @@ async def test_clear_address_from_match_history(
|
||||
# No new discovery should have been triggered
|
||||
assert len(mock_config_flow.mock_calls) == 1
|
||||
|
||||
# But when we inject new advertisement with different data, it should be discovered
|
||||
# But when we inject new advertisement with
|
||||
# different data, it should be discovered
|
||||
inject_advertisement(hass, switchbot_device, switchbot_adv_2)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -1305,7 +1306,8 @@ async def test_async_discovered_device_api(
|
||||
return_value=mock_bt,
|
||||
),
|
||||
patch(
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data", # Must patch before we setup
|
||||
# Must patch before we setup
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data",
|
||||
{
|
||||
"44:44:33:11:23:45": (
|
||||
MagicMock(address="44:44:33:11:23:45"),
|
||||
@@ -2497,7 +2499,8 @@ async def test_process_advertisements_ignore_bad_advertisement(
|
||||
)
|
||||
)
|
||||
|
||||
# The goal of this loop is to make sure that async_process_advertisements sees at least one
|
||||
# The goal of this loop is to make sure that
|
||||
# async_process_advertisements sees at least one
|
||||
# callback that returns False
|
||||
while not done.is_set():
|
||||
inject_advertisement(hass, device, adv)
|
||||
@@ -2535,7 +2538,7 @@ async def test_process_advertisements_timeout(
|
||||
async def test_wrapped_instance_with_filter(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test consumers can use the wrapped instance with a filter as if it was normal BleakScanner."""
|
||||
"""Test wrapped instance with a filter works like BleakScanner."""
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.async_get_bluetooth", return_value=[]
|
||||
):
|
||||
@@ -2608,7 +2611,7 @@ async def test_wrapped_instance_with_filter(
|
||||
async def test_wrapped_instance_with_service_uuids(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test consumers can use the wrapped instance with a service_uuids list as if it was normal BleakScanner."""
|
||||
"""Test wrapped instance with service_uuids list."""
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.async_get_bluetooth", return_value=[]
|
||||
):
|
||||
@@ -2665,7 +2668,7 @@ async def test_wrapped_instance_with_service_uuids(
|
||||
async def test_wrapped_instance_with_service_uuids_with_coro_callback(
|
||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock
|
||||
) -> None:
|
||||
"""Test consumers can use the wrapped instance with a service_uuids list as if it was normal BleakScanner.
|
||||
"""Test wrapped instance with service_uuids list.
|
||||
|
||||
Verify that coro callbacks are supported.
|
||||
"""
|
||||
@@ -2921,7 +2924,8 @@ async def test_async_ble_device_from_address(
|
||||
return_value=mock_bt,
|
||||
),
|
||||
patch(
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data", # Must patch before we setup
|
||||
# Must patch before we setup
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data",
|
||||
{
|
||||
"44:44:33:11:23:45": (
|
||||
MagicMock(address="44:44:33:11:23:45"),
|
||||
|
||||
@@ -487,7 +487,7 @@ async def test_restore_history_from_dbus_and_corrupted_remote_adapters(
|
||||
hass_storage: dict[str, Any],
|
||||
disable_new_discovery_flows,
|
||||
) -> None:
|
||||
"""Test we can restore history from dbus when the remote adapters data is corrupted."""
|
||||
"""Test history restore when remote adapters data is corrupted."""
|
||||
address = "AA:BB:CC:CC:CC:FF"
|
||||
|
||||
data = hass_storage[storage.REMOTE_SCANNER_STORAGE_KEY] = json_loads(
|
||||
@@ -617,12 +617,12 @@ async def test_switching_adapters_based_on_rssi_connectable_to_non_connectable(
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth")
|
||||
async def test_connectable_advertisement_can_be_retrieved_with_best_path_is_non_connectable(
|
||||
async def test_connectable_adv_retrieved_when_best_path_is_non_connectable(
|
||||
hass: HomeAssistant,
|
||||
register_hci0_scanner: None,
|
||||
register_hci1_scanner: None,
|
||||
) -> None:
|
||||
"""Test we can still get a connectable BLEDevice when the best path is non-connectable.
|
||||
"""Test connectable BLEDevice when best path is non-connectable.
|
||||
|
||||
In this case the device is closer to a non-connectable scanner, but the
|
||||
at least one connectable scanner has the device in range.
|
||||
@@ -791,7 +791,10 @@ async def test_switching_adapters_when_one_stop_scanning(
|
||||
async def test_goes_unavailable_connectable_only_and_recovers(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test all connectable scanners go unavailable, and than recover when there is a non-connectable scanner."""
|
||||
"""Test connectable scanners go unavailable and recover.
|
||||
|
||||
Uses a non-connectable scanner for recovery.
|
||||
"""
|
||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
@@ -953,7 +956,7 @@ async def test_goes_unavailable_connectable_only_and_recovers(
|
||||
async def test_goes_unavailable_dismisses_discovery_and_makes_discoverable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test that unavailable will dismiss any active discoveries and make device discoverable again."""
|
||||
"""Test unavailable dismisses discoveries and re-enables them."""
|
||||
mock_bt = [
|
||||
{
|
||||
"domain": "switchbot",
|
||||
@@ -1240,7 +1243,8 @@ async def test_set_fallback_interval_big(hass: HomeAssistant) -> None:
|
||||
"""Test we can set the fallback advertisement interval."""
|
||||
assert async_get_fallback_availability_interval(hass, "44:44:33:11:23:12") is None
|
||||
|
||||
# Force the interval to be really big and check it doesn't expire using the default timeout (900)
|
||||
# Force the interval to be really big and check it
|
||||
# doesn't expire using the default timeout (900)
|
||||
|
||||
async_set_fallback_availability_interval(hass, "44:44:33:11:23:12", 604800.0)
|
||||
assert (
|
||||
|
||||
@@ -224,7 +224,7 @@ async def test_wrapped_bleak_client_set_disconnected_callback_after_connected(
|
||||
async def test_ble_device_with_proxy_client_out_of_connections_no_scanners(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test we switch to the next available proxy when one runs out of connections with no scanners."""
|
||||
"""Test switching proxy when out of connections, no scanners."""
|
||||
manager = _get_manager()
|
||||
|
||||
switchbot_proxy_device_no_connection_slot = generate_ble_device(
|
||||
@@ -492,10 +492,10 @@ async def test_ble_device_with_proxy_client_out_of_connections_uses_best_availab
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_bluetooth", "macos_adapter")
|
||||
async def test_ble_device_with_proxy_client_out_of_connections_uses_best_available_macos(
|
||||
async def test_ble_device_proxy_client_out_of_connections_best_available_macos(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test we switch to the next available proxy when one runs out of connections on MacOS."""
|
||||
"""Test switching proxy when out of connections on MacOS."""
|
||||
manager = _get_manager()
|
||||
|
||||
switchbot_proxy_device_no_connection_slot = generate_ble_device(
|
||||
|
||||
@@ -141,10 +141,11 @@ async def test_context_compatiblity_with_data_update_coordinator(
|
||||
async def test_unavailable_callbacks_mark_the_coordinator_unavailable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test that the coordinator goes unavailable when the bluetooth stack no longer sees the device."""
|
||||
"""Test coordinator goes unavailable when device unseen."""
|
||||
start_monotonic = time.monotonic()
|
||||
with patch(
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data", # Must patch before we setup
|
||||
# Must patch before we setup
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data",
|
||||
{"44:44:33:11:23:45": (MagicMock(address="44:44:33:11:23:45"), MagicMock())},
|
||||
):
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
@@ -199,7 +200,7 @@ async def test_unavailable_callbacks_mark_the_coordinator_unavailable(
|
||||
|
||||
@pytest.mark.usefixtures("mock_bleak_scanner_start", "mock_bluetooth_adapters")
|
||||
async def test_passive_bluetooth_coordinator_entity(hass: HomeAssistant) -> None:
|
||||
"""Test integration of PassiveBluetoothDataUpdateCoordinator with PassiveBluetoothCoordinatorEntity."""
|
||||
"""Test PassiveBluetoothDataUpdateCoordinator with entity."""
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
coordinator = MyCoordinator(
|
||||
hass, _LOGGER, "aa:bb:cc:dd:ee:ff", BluetoothScanningMode.ACTIVE
|
||||
|
||||
@@ -506,7 +506,8 @@ async def test_unavailable_after_no_data(hass: HomeAssistant) -> None:
|
||||
start_monotonic = time.monotonic()
|
||||
|
||||
with patch(
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data", # Must patch before we setup
|
||||
# Must patch before we setup
|
||||
"bleak.BleakScanner.discovered_devices_and_advertisement_data",
|
||||
{"44:44:33:11:23:45": (MagicMock(address="44:44:33:11:23:45"), MagicMock())},
|
||||
):
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
@@ -804,7 +805,10 @@ GOVEE_B5178_REMOTE_SERVICE_INFO = BluetoothServiceInfo(
|
||||
address="749A17CB-F7A9-D466-C29F-AABE601938A0",
|
||||
rssi=-95,
|
||||
manufacturer_data={
|
||||
1: b"\x01\x01\x01\x04\xb5\xa2d\x00\x06L\x00\x02\x15INTELLI_ROCKS_HWPu\xf2\xff\xc2"
|
||||
1: (
|
||||
b"\x01\x01\x01\x04\xb5\xa2d\x00\x06L\x00"
|
||||
b"\x02\x15INTELLI_ROCKS_HWPu\xf2\xff\xc2"
|
||||
)
|
||||
},
|
||||
service_data={},
|
||||
service_uuids=["0000ec88-0000-1000-8000-00805f9b34fb"],
|
||||
@@ -1089,7 +1093,7 @@ GOVEE_B5178_PRIMARY_AND_REMOTE_PASSIVE_BLUETOOTH_DATA_UPDATE = (
|
||||
|
||||
@pytest.mark.usefixtures("mock_bleak_scanner_start", "mock_bluetooth_adapters")
|
||||
async def test_integration_with_entity(hass: HomeAssistant) -> None:
|
||||
"""Test integration of PassiveBluetoothProcessorCoordinator with PassiveBluetoothCoordinatorEntity."""
|
||||
"""Test PassiveBluetoothProcessorCoordinator with entity."""
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
|
||||
update_count = 0
|
||||
@@ -1162,7 +1166,8 @@ async def test_integration_with_entity(hass: HomeAssistant) -> None:
|
||||
assert len(entity_key_events) == 1
|
||||
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
# Third call with primary and remote sensor entities adds the primary sensor entities
|
||||
# Third call with primary and remote sensor entities
|
||||
# adds the primary sensor entities
|
||||
assert len(mock_add_entities.mock_calls) == 2
|
||||
|
||||
# should not have triggered the entity key listener since there
|
||||
@@ -1417,7 +1422,7 @@ DEVICE_ONLY_PASSIVE_BLUETOOTH_DATA_UPDATE = PassiveBluetoothDataUpdate(
|
||||
|
||||
@pytest.mark.usefixtures("mock_bleak_scanner_start", "mock_bluetooth_adapters")
|
||||
async def test_integration_multiple_entity_platforms(hass: HomeAssistant) -> None:
|
||||
"""Test integration of PassiveBluetoothProcessorCoordinator with multiple platforms."""
|
||||
"""Test coordinator with multiple platforms."""
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
|
||||
@callback
|
||||
@@ -1568,7 +1573,7 @@ async def test_exception_from_coordinator_update_method(
|
||||
async def test_integration_multiple_entity_platforms_with_reload_and_restart(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test integration of PassiveBluetoothProcessorCoordinator with multiple platforms with reload."""
|
||||
"""Test coordinator with multiple platforms and reload."""
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
entry = MockConfigEntry(domain=DOMAIN, data={})
|
||||
|
||||
|
||||
@@ -354,7 +354,8 @@ async def test_adapter_recovery(hass: HomeAssistant) -> None:
|
||||
|
||||
assert called_start == 1
|
||||
|
||||
# We hit the timer with no detections, so we reset the adapter and restart the scanner
|
||||
# We hit the timer with no detections, so we reset
|
||||
# the adapter and restart the scanner
|
||||
with (
|
||||
patch_bluetooth_time(
|
||||
start_time_monotonic
|
||||
@@ -374,7 +375,7 @@ async def test_adapter_recovery(hass: HomeAssistant) -> None:
|
||||
|
||||
@pytest.mark.usefixtures("one_adapter")
|
||||
async def test_adapter_scanner_fails_to_start_first_time(hass: HomeAssistant) -> None:
|
||||
"""Test we can recover when the adapter stops responding and the first recovery fails."""
|
||||
"""Test recovery when adapter stops and first recovery fails."""
|
||||
|
||||
called_start = 0
|
||||
called_stop = 0
|
||||
@@ -443,7 +444,8 @@ async def test_adapter_scanner_fails_to_start_first_time(hass: HomeAssistant) ->
|
||||
|
||||
assert called_start == 1
|
||||
|
||||
# We hit the timer with no detections, so we reset the adapter and restart the scanner
|
||||
# We hit the timer with no detections, so we reset
|
||||
# the adapter and restart the scanner
|
||||
with (
|
||||
patch_bluetooth_time(
|
||||
start_time_monotonic
|
||||
@@ -553,7 +555,7 @@ async def test_adapter_fails_to_start_and_takes_a_bit_to_init(
|
||||
async def test_restart_takes_longer_than_watchdog_time(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test we do not try to recover the adapter again if the restart is still in progress."""
|
||||
"""Test no recovery attempt while restart is in progress."""
|
||||
|
||||
release_start_event = asyncio.Event()
|
||||
called_start = 0
|
||||
|
||||
@@ -267,7 +267,7 @@ async def test_subscribe_connection_allocations_invalid_config_entry_id(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
) -> None:
|
||||
"""Test bluetooth subscribe_connection_allocations for an invalid config entry id."""
|
||||
"""Test subscribe_connection_allocations, invalid entry."""
|
||||
client = await hass_ws_client()
|
||||
await client.send_json(
|
||||
{
|
||||
|
||||
@@ -69,7 +69,10 @@ class MockBleakClientBattery5(MockBleakClient):
|
||||
|
||||
@pytest.mark.usefixtures("mock_device_tracker_conf")
|
||||
async def test_do_not_see_device_if_time_not_updated(hass: HomeAssistant) -> None:
|
||||
"""Test device going not_home after consider_home threshold from first scan if the subsequent scans have not incremented last seen time."""
|
||||
"""Test device goes not_home after consider_home threshold.
|
||||
|
||||
Subsequent scans have not incremented last seen time.
|
||||
"""
|
||||
|
||||
address = "DE:AD:BE:EF:13:37"
|
||||
name = "Mock device name"
|
||||
@@ -121,7 +124,8 @@ async def test_do_not_see_device_if_time_not_updated(hass: HomeAssistant) -> Non
|
||||
async_fire_time_changed(hass, time_after_consider_home)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Advance time over the consider home threshold and trigger update after the threshold
|
||||
# Advance time over the consider home threshold
|
||||
# and trigger update after the threshold
|
||||
time_after_consider_home = dt_util.utcnow() + config[CONF_CONSIDER_HOME]
|
||||
with freeze_time(time_after_consider_home):
|
||||
async_fire_time_changed(hass, time_after_consider_home)
|
||||
@@ -134,7 +138,10 @@ async def test_do_not_see_device_if_time_not_updated(hass: HomeAssistant) -> Non
|
||||
|
||||
@pytest.mark.usefixtures("mock_device_tracker_conf")
|
||||
async def test_see_device_if_time_updated(hass: HomeAssistant) -> None:
|
||||
"""Test device remaining home after consider_home threshold from first scan if the subsequent scans have incremented last seen time."""
|
||||
"""Test device stays home after consider_home threshold.
|
||||
|
||||
Subsequent scans have incremented last seen time.
|
||||
"""
|
||||
|
||||
address = "DE:AD:BE:EF:13:37"
|
||||
name = "Mock device name"
|
||||
@@ -202,7 +209,8 @@ async def test_see_device_if_time_updated(hass: HomeAssistant) -> None:
|
||||
async_fire_time_changed(hass, time_after_consider_home)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Advance time over the consider home threshold and trigger update after the threshold
|
||||
# Advance time over the consider home threshold
|
||||
# and trigger update after the threshold
|
||||
time_after_consider_home = dt_util.utcnow() + config[CONF_CONSIDER_HOME]
|
||||
with freeze_time(time_after_consider_home):
|
||||
async_fire_time_changed(hass, time_after_consider_home)
|
||||
|
||||
@@ -15,7 +15,7 @@ from tests.common import MockConfigEntry
|
||||
async def test_bmw_connected_drive_repair_issue(
|
||||
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||
) -> None:
|
||||
"""Test the BMW Connected Drive configuration entry loading/unloading handles the repair."""
|
||||
"""Test the BMW Connected Drive config entry loading/unloading handles repair."""
|
||||
config_entry_1 = MockConfigEntry(
|
||||
title="Example 1",
|
||||
domain=DOMAIN,
|
||||
|
||||
@@ -536,7 +536,7 @@ async def test_zeroconf_form_with_token_available(hass: HomeAssistant) -> None:
|
||||
async def test_zeroconf_form_with_token_available_name_unavailable(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test we get the discovery form when we can get the token but the name is unavailable."""
|
||||
"""Test discovery form when we can get the token but name is unavailable."""
|
||||
|
||||
with (
|
||||
patch_bond_version(
|
||||
@@ -649,7 +649,7 @@ async def test_zeroconf_in_setup_retry_state(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_zeroconf_already_configured_refresh_token(hass: HomeAssistant) -> None:
|
||||
"""Test starting a flow from zeroconf when already configured and the token is out of date."""
|
||||
"""Test zeroconf flow when already configured and token is outdated."""
|
||||
entry2 = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="not-the-same-bond-id",
|
||||
@@ -700,7 +700,7 @@ async def test_zeroconf_already_configured_refresh_token(hass: HomeAssistant) ->
|
||||
async def test_zeroconf_already_configured_no_reload_same_host(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test starting a flow from zeroconf when already configured does not reload if the host is the same."""
|
||||
"""Test zeroconf when already configured does not reload if host is the same."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="already-registered-bond-id",
|
||||
|
||||
@@ -227,7 +227,7 @@ async def test_tilt_and_open(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_open_cover(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports cover is open."""
|
||||
"""Tests that update sets correct state when Bond API reports cover is open."""
|
||||
await setup_platform(hass, COVER_DOMAIN, shades("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"open": 1}):
|
||||
@@ -238,7 +238,7 @@ async def test_update_reports_open_cover(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_closed_cover(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports cover is closed."""
|
||||
"""Tests that update sets correct state when Bond API reports cover is closed."""
|
||||
await setup_platform(hass, COVER_DOMAIN, shades("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"open": 0}):
|
||||
|
||||
@@ -100,7 +100,7 @@ async def test_entity_registry(
|
||||
|
||||
|
||||
async def test_non_standard_speed_list(hass: HomeAssistant) -> None:
|
||||
"""Tests that the device is registered with custom speed list if number of supported speeds differs form 3."""
|
||||
"""Tests device is registered with custom speed list if speeds differ from 3."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
FAN_DOMAIN,
|
||||
@@ -130,7 +130,7 @@ async def test_non_standard_speed_list(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_fan_speed_with_no_max_speed(hass: HomeAssistant) -> None:
|
||||
"""Tests that fans without max speed (increase/decrease controls) map speed to HA standard."""
|
||||
"""Tests fans without max speed (increase/decrease) map speed to HA standard."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
FAN_DOMAIN,
|
||||
@@ -414,7 +414,7 @@ async def test_set_speed_belief_speed_100(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_fan_on(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports fan power is on."""
|
||||
"""Tests that update sets correct state when Bond API reports fan power is on."""
|
||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"power": 1, "speed": 1}):
|
||||
@@ -425,7 +425,7 @@ async def test_update_reports_fan_on(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_fan_off(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports fan power is off."""
|
||||
"""Tests that update sets correct state when Bond API reports fan power is off."""
|
||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"power": 0, "speed": 1}):
|
||||
@@ -436,7 +436,7 @@ async def test_update_reports_fan_off(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_direction_forward(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct direction when Bond API reports fan direction is forward."""
|
||||
"""Tests update sets correct direction when Bond API reports forward."""
|
||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"direction": Direction.FORWARD}):
|
||||
@@ -447,7 +447,7 @@ async def test_update_reports_direction_forward(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_direction_reverse(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct direction when Bond API reports fan direction is reverse."""
|
||||
"""Tests update sets correct direction when Bond API reports reverse."""
|
||||
await setup_platform(hass, FAN_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"direction": Direction.REVERSE}):
|
||||
|
||||
@@ -320,7 +320,7 @@ async def test_light_set_brightness_belief_full(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_light_set_brightness_belief_api_error(hass: HomeAssistant) -> None:
|
||||
"""Tests that the set brightness belief throws HomeAssistantError in the event of an api error."""
|
||||
"""Tests that set brightness belief throws HomeAssistantError on api error."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -365,7 +365,7 @@ async def test_fp_light_set_brightness_belief_full(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_fp_light_set_brightness_belief_api_error(hass: HomeAssistant) -> None:
|
||||
"""Tests that the set brightness belief throws HomeAssistantError in the event of an api error."""
|
||||
"""Tests that set brightness belief throws HomeAssistantError on api error."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -389,7 +389,7 @@ async def test_fp_light_set_brightness_belief_api_error(hass: HomeAssistant) ->
|
||||
async def test_light_set_brightness_belief_brightness_not_supported(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Tests that the set brightness belief function of a light that doesn't support setting brightness returns an error."""
|
||||
"""Tests that set brightness belief returns error when brightness is unsupported."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -476,7 +476,7 @@ async def test_light_set_power_belief(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_light_set_power_belief_api_error(hass: HomeAssistant) -> None:
|
||||
"""Tests that the set brightness belief function of a light throws HomeAssistantError in the event of an api error."""
|
||||
"""Tests that set power belief throws HomeAssistantError on api error."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -521,7 +521,7 @@ async def test_fp_light_set_power_belief(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_fp_light_set_power_belief_api_error(hass: HomeAssistant) -> None:
|
||||
"""Tests that the set brightness belief function of a light throws HomeAssistantError in the event of an api error."""
|
||||
"""Tests that set power belief throws HomeAssistantError on api error."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -545,7 +545,7 @@ async def test_fp_light_set_power_belief_api_error(hass: HomeAssistant) -> None:
|
||||
async def test_fp_light_set_brightness_belief_brightness_not_supported(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Tests that the set brightness belief function of a fireplace light that doesn't support setting brightness returns an error."""
|
||||
"""Tests set brightness belief returns error for fireplace without brightness."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -563,7 +563,7 @@ async def test_fp_light_set_brightness_belief_brightness_not_supported(
|
||||
|
||||
|
||||
async def test_light_start_increasing_brightness(hass: HomeAssistant) -> None:
|
||||
"""Tests a light that can only increase or decrease brightness delegates to API can start increasing brightness."""
|
||||
"""Tests a light with only increase/decrease brightness can start increasing."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -603,7 +603,7 @@ async def test_light_start_increasing_brightness_missing_service(
|
||||
|
||||
|
||||
async def test_light_start_decreasing_brightness(hass: HomeAssistant) -> None:
|
||||
"""Tests a light that can only increase or decrease brightness delegates to API can start decreasing brightness."""
|
||||
"""Tests a light with only increase/decrease brightness can start decreasing."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -646,7 +646,7 @@ async def test_light_start_decreasing_brightness_missing_service(
|
||||
|
||||
|
||||
async def test_light_stop(hass: HomeAssistant) -> None:
|
||||
"""Tests a light that can only increase or decrease brightness delegates to API can stop."""
|
||||
"""Tests a light with only increase/decrease brightness can stop."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -777,7 +777,7 @@ async def test_brightness_not_supported(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_turn_on_light_with_brightness(hass: HomeAssistant) -> None:
|
||||
"""Tests that turn on command, on a dimmable light, delegates to API and parses brightness."""
|
||||
"""Tests turning on a dimmable light delegates to API and parses brightness."""
|
||||
await setup_platform(
|
||||
hass,
|
||||
LIGHT_DOMAIN,
|
||||
@@ -892,7 +892,7 @@ async def test_turn_off_down_light(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_light_is_on(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the light is on."""
|
||||
"""Tests that update sets correct state when Bond API reports light is on."""
|
||||
await setup_platform(hass, LIGHT_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"light": 1}):
|
||||
@@ -903,7 +903,7 @@ async def test_update_reports_light_is_on(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_light_is_off(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the light is off."""
|
||||
"""Tests that update sets correct state when Bond API reports light is off."""
|
||||
await setup_platform(hass, LIGHT_DOMAIN, ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"light": 0}):
|
||||
@@ -914,7 +914,7 @@ async def test_update_reports_light_is_off(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_up_light_is_on(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the up light is on."""
|
||||
"""Tests that update sets correct state when Bond API reports up light is on."""
|
||||
await setup_platform(hass, LIGHT_DOMAIN, up_light_ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"up_light": 1, "light": 1}):
|
||||
@@ -925,7 +925,7 @@ async def test_update_reports_up_light_is_on(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_up_light_is_off(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the up light is off."""
|
||||
"""Tests that update sets correct state when Bond API reports up light is off."""
|
||||
await setup_platform(hass, LIGHT_DOMAIN, up_light_ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"up_light": 0, "light": 0}):
|
||||
@@ -936,7 +936,7 @@ async def test_update_reports_up_light_is_off(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_down_light_is_on(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the down light is on."""
|
||||
"""Tests that update sets correct state when Bond API reports down light is on."""
|
||||
await setup_platform(hass, LIGHT_DOMAIN, down_light_ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"down_light": 1, "light": 1}):
|
||||
@@ -947,7 +947,7 @@ async def test_update_reports_down_light_is_on(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_down_light_is_off(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the down light is off."""
|
||||
"""Tests that update sets correct state when Bond API reports down light is off."""
|
||||
await setup_platform(hass, LIGHT_DOMAIN, down_light_ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"down_light": 0, "light": 0}):
|
||||
@@ -1030,7 +1030,7 @@ async def test_light_available(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_parse_brightness(hass: HomeAssistant) -> None:
|
||||
"""Tests that reported brightness level (0..100) converted to HA brightness (0...255)."""
|
||||
"""Tests that reported brightness (0..100) converted to HA brightness (0..255)."""
|
||||
await setup_platform(hass, LIGHT_DOMAIN, dimmable_ceiling_fan("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"light": 1, "brightness": 50}):
|
||||
|
||||
@@ -107,7 +107,7 @@ async def test_switch_set_power_belief(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_switch_set_power_belief_api_error(hass: HomeAssistant) -> None:
|
||||
"""Tests that the set power belief service throws HomeAssistantError in the event of an api error."""
|
||||
"""Tests that set power belief throws HomeAssistantError on api error."""
|
||||
await setup_platform(
|
||||
hass, SWITCH_DOMAIN, generic_device("name-1"), bond_device_id="test-device-id"
|
||||
)
|
||||
@@ -126,7 +126,7 @@ async def test_switch_set_power_belief_api_error(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_switch_is_on(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the device is on."""
|
||||
"""Tests that update sets correct state when Bond API reports device is on."""
|
||||
await setup_platform(hass, SWITCH_DOMAIN, generic_device("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"power": 1}):
|
||||
@@ -137,7 +137,7 @@ async def test_update_reports_switch_is_on(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_update_reports_switch_is_off(hass: HomeAssistant) -> None:
|
||||
"""Tests that update command sets correct state when Bond API reports the device is off."""
|
||||
"""Tests that update sets correct state when Bond API reports device is off."""
|
||||
await setup_platform(hass, SWITCH_DOMAIN, generic_device("name-1"))
|
||||
|
||||
with patch_bond_device_state(return_value={"power": 0}):
|
||||
|
||||
@@ -320,7 +320,7 @@ async def test_dhcp_discovery_if_panel_setup_config_flow(
|
||||
panel_model: PanelModel,
|
||||
config_flow_data: dict[str, Any],
|
||||
) -> None:
|
||||
"""Test DHCP discovery doesn't fail if a different panel was set up via config flow."""
|
||||
"""Test DHCP discovery doesn't fail if a different panel was set up."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
# change out the serial number so we can test discovery for a different panel
|
||||
@@ -400,7 +400,7 @@ async def test_dhcp_updates_mac(
|
||||
serial_number: str,
|
||||
config_flow_data: dict[str, Any],
|
||||
) -> None:
|
||||
"""Test DHCP discovery flow updates mac if the previous entry did not have a mac address."""
|
||||
"""Test DHCP discovery flow updates mac if previous entry had no mac address."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
assert CONF_MAC not in mock_config_entry.data
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ async def test_set_date_time_service_fails_bad_entity(
|
||||
area: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test that the service calls fail if the service call is done for an incorrect entity."""
|
||||
"""Test that the service calls fail if done for an incorrect entity."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
with pytest.raises(ServiceValidationError) as err:
|
||||
await hass.services.async_call(
|
||||
@@ -79,7 +79,7 @@ async def test_set_date_time_service_fails_bad_params(
|
||||
area: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test that the service calls fail if the service call is done with incorrect params."""
|
||||
"""Test that the service calls fail if done with incorrect params."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
with pytest.raises(
|
||||
vol.MultipleInvalid,
|
||||
|
||||
@@ -94,7 +94,7 @@ async def test_heartbeat_unload(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_heartbeat_do_not_unload(hass: HomeAssistant) -> None:
|
||||
"""Test that the heartbeat is not deactivated until the last config entry is removed."""
|
||||
"""Test heartbeat is not deactivated until the last config entry is removed."""
|
||||
device_a = get_device("Office")
|
||||
device_b = get_device("Bedroom")
|
||||
|
||||
|
||||
@@ -44,7 +44,10 @@ async def test_button_press_syncs_time(
|
||||
|
||||
# Mock device time that differs from HA time
|
||||
mock_bsblan.time.return_value = DeviceTime.model_validate_json(
|
||||
'{"time": {"name": "Time", "value": "01.01.2020 00:00:00", "unit": "", "desc": "", "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
'{"time": {"name": "Time",'
|
||||
' "value": "01.01.2020 00:00:00",'
|
||||
' "unit": "", "desc": "",'
|
||||
' "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
)
|
||||
|
||||
# Press the button
|
||||
@@ -75,7 +78,10 @@ async def test_button_press_no_update_when_same(
|
||||
# Mock device time that matches HA time
|
||||
current_time_str = dt_util.now().strftime("%d.%m.%Y %H:%M:%S")
|
||||
mock_bsblan.time.return_value = DeviceTime.model_validate_json(
|
||||
f'{{"time": {{"name": "Time", "value": "{current_time_str}", "unit": "", "desc": "", "dataType": 0, "readonly": 0, "error": 0}}}}'
|
||||
f'{{"time": {{"name": "Time",'
|
||||
f' "value": "{current_time_str}",'
|
||||
f' "unit": "", "desc": "",'
|
||||
f' "dataType": 0, "readonly": 0, "error": 0}}}}'
|
||||
)
|
||||
|
||||
# Press the button
|
||||
@@ -124,7 +130,10 @@ async def test_button_press_set_time_error(
|
||||
|
||||
# Mock device time that differs
|
||||
mock_bsblan.time.return_value = DeviceTime.model_validate_json(
|
||||
'{"time": {"name": "Time", "value": "01.01.2020 00:00:00", "unit": "", "desc": "", "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
'{"time": {"name": "Time",'
|
||||
' "value": "01.01.2020 00:00:00",'
|
||||
' "unit": "", "desc": "",'
|
||||
' "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
)
|
||||
|
||||
# Mock set_time() to raise an error
|
||||
|
||||
@@ -54,7 +54,7 @@ def zeroconf_discovery_info_no_mac() -> ZeroconfServiceInfo:
|
||||
|
||||
@pytest.fixture
|
||||
def zeroconf_discovery_info_different_mac() -> ZeroconfServiceInfo:
|
||||
"""Return zeroconf discovery info with a different MAC than the device API returns."""
|
||||
"""Return zeroconf discovery info with a different MAC than the device API."""
|
||||
return ZeroconfServiceInfo(
|
||||
ip_address=ip_address("10.0.2.60"),
|
||||
ip_addresses=[ip_address("10.0.2.60")],
|
||||
@@ -485,7 +485,8 @@ async def test_zeroconf_discovery_no_mac_requires_auth(
|
||||
"00:80:41:19:69:90",
|
||||
)
|
||||
|
||||
# Should be called 3 times: once without auth (fails), twice with auth (in _validate_and_create)
|
||||
# Should be called 3 times: once without auth (fails),
|
||||
# twice with auth (in _validate_and_create)
|
||||
assert len(mock_bsblan.device.mock_calls) == 3
|
||||
|
||||
|
||||
@@ -495,7 +496,7 @@ async def test_zeroconf_discovery_no_mac_no_auth_required(
|
||||
mock_setup_entry: AsyncMock,
|
||||
zeroconf_discovery_info_no_mac: ZeroconfServiceInfo,
|
||||
) -> None:
|
||||
"""Test Zeroconf discovery when no MAC in announcement but device accessible without auth."""
|
||||
"""Test Zeroconf discovery when no MAC but device accessible without auth."""
|
||||
result = await _init_zeroconf_flow(hass, zeroconf_discovery_info_no_mac)
|
||||
|
||||
# Should now show the discovery_confirm form to the user
|
||||
@@ -729,7 +730,7 @@ async def test_zeroconf_discovery_no_mac_duplicate_host_port(
|
||||
mock_bsblan: MagicMock,
|
||||
zeroconf_discovery_info_no_mac: ZeroconfServiceInfo,
|
||||
) -> None:
|
||||
"""Test Zeroconf discovery aborts when no MAC and same host/port already configured."""
|
||||
"""Test Zeroconf discovery aborts when no MAC and same host/port configured."""
|
||||
# Create an existing entry with same host/port but no unique_id
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
|
||||
@@ -148,7 +148,7 @@ async def test_coordinator_dhw_config_update_error(
|
||||
mock_bsblan: MagicMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test coordinator handling when DHW config update fails but keeps existing data."""
|
||||
"""Test coordinator when DHW config update fails but keeps existing data."""
|
||||
# First, set up the integration successfully
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
@@ -436,7 +436,10 @@ async def test_sync_time_service(
|
||||
|
||||
# Mock device time that differs from HA time
|
||||
mock_bsblan.time.return_value = DeviceTime.model_validate_json(
|
||||
'{"time": {"name": "Time", "value": "01.01.2020 00:00:00", "unit": "", "desc": "", "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
'{"time": {"name": "Time",'
|
||||
' "value": "01.01.2020 00:00:00",'
|
||||
' "unit": "", "desc": "",'
|
||||
' "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
)
|
||||
|
||||
# Call the service
|
||||
@@ -474,7 +477,10 @@ async def test_sync_time_service_no_update_when_same(
|
||||
# Mock device time that matches HA time
|
||||
current_time_str = dt_util.now().strftime("%d.%m.%Y %H:%M:%S")
|
||||
mock_bsblan.time.return_value = DeviceTime.model_validate_json(
|
||||
f'{{"time": {{"name": "Time", "value": "{current_time_str}", "unit": "", "desc": "", "dataType": 0, "readonly": 0, "error": 0}}}}'
|
||||
f'{{"time": {{"name": "Time",'
|
||||
f' "value": "{current_time_str}",'
|
||||
f' "unit": "", "desc": "",'
|
||||
f' "dataType": 0, "readonly": 0, "error": 0}}}}'
|
||||
)
|
||||
|
||||
# Call the service
|
||||
@@ -537,7 +543,10 @@ async def test_sync_time_service_set_time_error(
|
||||
|
||||
# Mock device time that differs
|
||||
mock_bsblan.time.return_value = DeviceTime.model_validate_json(
|
||||
'{"time": {"name": "Time", "value": "01.01.2020 00:00:00", "unit": "", "desc": "", "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
'{"time": {"name": "Time",'
|
||||
' "value": "01.01.2020 00:00:00",'
|
||||
' "unit": "", "desc": "",'
|
||||
' "dataType": 0, "readonly": 0, "error": 0}}'
|
||||
)
|
||||
|
||||
# Mock set_time() to raise an error
|
||||
|
||||
@@ -181,7 +181,11 @@ async def test_set_invalid_operation_mode(
|
||||
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match=r"Operation mode invalid_mode is not valid for water_heater\.water_heater\. Valid operation modes are: off, performance, eco",
|
||||
match=(
|
||||
r"Operation mode invalid_mode is not valid for"
|
||||
r" water_heater\.water_heater\."
|
||||
r" Valid operation modes are: off, performance, eco"
|
||||
),
|
||||
):
|
||||
await hass.services.async_call(
|
||||
domain=WATER_HEATER_DOMAIN,
|
||||
|
||||
@@ -90,7 +90,7 @@ async def test_async_step_bluetooth_valid_device_with_encryption(
|
||||
async def test_async_step_bluetooth_valid_device_encryption_wrong_key(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test discovery via bluetooth with a valid device, with encryption and invalid key."""
|
||||
"""Test bluetooth discovery with a valid device, encryption and invalid key."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||
@@ -122,7 +122,7 @@ async def test_async_step_bluetooth_valid_device_encryption_wrong_key(
|
||||
async def test_async_step_bluetooth_valid_device_encryption_wrong_key_length(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test discovery via bluetooth with a valid device, with encryption and wrong key length."""
|
||||
"""Test bluetooth discovery with a valid device, encryption and wrong key length."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||
@@ -280,7 +280,7 @@ async def test_async_step_user_with_found_devices_encryption(
|
||||
async def test_async_step_user_with_found_devices_encryption_wrong_key(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test setup from service info cache with devices found, with encryption and wrong key."""
|
||||
"""Test setup from service info cache with devices, encryption and wrong key."""
|
||||
# Get a list of devices
|
||||
with patch(
|
||||
"homeassistant.components.bthome.config_flow.async_discovered_service_info",
|
||||
@@ -326,7 +326,7 @@ async def test_async_step_user_with_found_devices_encryption_wrong_key(
|
||||
async def test_async_step_user_with_found_devices_encryption_wrong_key_length(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test setup from service info cache with devices found, with encryption and wrong key length."""
|
||||
"""Test setup from service info cache, encryption and wrong key length."""
|
||||
# Get a list of devices
|
||||
with patch(
|
||||
"homeassistant.components.bthome.config_flow.async_discovered_service_info",
|
||||
|
||||
@@ -1241,7 +1241,7 @@ async def test_sleepy_device(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
async def test_sleepy_device_restore_state(hass: HomeAssistant) -> None:
|
||||
"""Test sleepy device does not go to unavailable after 60 minutes and restores state."""
|
||||
"""Test sleepy device does not go unavailable after 60 min and restores state."""
|
||||
start_monotonic = time.monotonic()
|
||||
|
||||
entry = MockConfigEntry(
|
||||
|
||||
@@ -147,9 +147,9 @@ async def test_if_fires_on_state_change(
|
||||
hass.states.async_set(entry.entity_id, "2021-01-01T23:59:59+00:00")
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 1
|
||||
assert (
|
||||
service_calls[0].data["some"]
|
||||
== f"to - device - {entry.entity_id} - unknown - 2021-01-01T23:59:59+00:00 - None - 0"
|
||||
assert service_calls[0].data["some"] == (
|
||||
f"to - device - {entry.entity_id}"
|
||||
" - unknown - 2021-01-01T23:59:59+00:00 - None - 0"
|
||||
)
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ async def test_if_fires_on_state_change_legacy(
|
||||
hass.states.async_set(entry.entity_id, "2021-01-01T23:59:59+00:00")
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 1
|
||||
assert (
|
||||
service_calls[0].data["some"]
|
||||
== f"to - device - {entry.entity_id} - unknown - 2021-01-01T23:59:59+00:00 - None - 0"
|
||||
assert service_calls[0].data["some"] == (
|
||||
f"to - device - {entry.entity_id}"
|
||||
" - unknown - 2021-01-01T23:59:59+00:00 - None - 0"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user