|
2 | 2 |
|
3 | 3 | from collections.abc import Callable |
4 | 4 | import dataclasses |
| 5 | +from typing import Any |
5 | 6 | from unittest import mock |
6 | 7 |
|
7 | 8 | from aiohomekit.controller import TransportType |
|
11 | 12 | from aiohomekit.testing import FakeController |
12 | 13 | import pytest |
13 | 14 |
|
| 15 | +from homeassistant.components.climate import ATTR_CURRENT_TEMPERATURE |
14 | 16 | from homeassistant.components.homekit_controller.const import ( |
15 | 17 | DEBOUNCE_COOLDOWN, |
16 | 18 | DOMAIN, |
@@ -439,3 +441,88 @@ def _create_accessory(accessory: Accessory) -> Service: |
439 | 441 | await time_changed(hass, DEBOUNCE_COOLDOWN) |
440 | 442 | await hass.async_block_till_done() |
441 | 443 | assert len(mock_get_characteristics.call_args_list[0][0][0]) > 1 |
| 444 | + |
| 445 | + |
| 446 | +async def test_poll_all_on_startup_refreshes_stale_values( |
| 447 | + hass: HomeAssistant, hass_storage: dict[str, Any] |
| 448 | +) -> None: |
| 449 | + """Test that entities get fresh values on startup instead of stale stored values.""" |
| 450 | + # Load actual Ecobee accessory fixture |
| 451 | + accessories = await setup_accessories_from_file(hass, "ecobee3.json") |
| 452 | + |
| 453 | + # Pre-populate storage with the accessories data (already has stale values) |
| 454 | + hass_storage["homekit_controller-entity-map"] = { |
| 455 | + "version": 1, |
| 456 | + "minor_version": 1, |
| 457 | + "key": "homekit_controller-entity-map", |
| 458 | + "data": { |
| 459 | + "pairings": { |
| 460 | + "00:00:00:00:00:00": { |
| 461 | + "config_num": 1, |
| 462 | + "accessories": [ |
| 463 | + a.to_accessory_and_service_list() for a in accessories |
| 464 | + ], |
| 465 | + } |
| 466 | + } |
| 467 | + }, |
| 468 | + } |
| 469 | + |
| 470 | + # Track what gets polled during setup |
| 471 | + polled_chars: list[tuple[int, int]] = [] |
| 472 | + |
| 473 | + # Set up the test accessories |
| 474 | + fake_controller = await setup_platform(hass) |
| 475 | + |
| 476 | + # Mock get_characteristics to track polling and return fresh temperature |
| 477 | + async def mock_get_characteristics( |
| 478 | + chars: set[tuple[int, int]], **kwargs: Any |
| 479 | + ) -> dict[tuple[int, int], dict[str, Any]]: |
| 480 | + """Return fresh temperature value when polled.""" |
| 481 | + polled_chars.extend(chars) |
| 482 | + # Return fresh values for all characteristics |
| 483 | + result: dict[tuple[int, int], dict[str, Any]] = {} |
| 484 | + for aid, iid in chars: |
| 485 | + # Find the characteristic and return appropriate value |
| 486 | + for accessory in accessories: |
| 487 | + if accessory.aid != aid: |
| 488 | + continue |
| 489 | + for service in accessory.services: |
| 490 | + for char in service.characteristics: |
| 491 | + if char.iid != iid: |
| 492 | + continue |
| 493 | + # Return fresh temperature instead of stale fixture value |
| 494 | + if char.type == CharacteristicsTypes.TEMPERATURE_CURRENT: |
| 495 | + result[(aid, iid)] = {"value": 22.5} # Fresh value |
| 496 | + else: |
| 497 | + result[(aid, iid)] = {"value": char.value} |
| 498 | + break |
| 499 | + return result |
| 500 | + |
| 501 | + # Add the paired device with our mock |
| 502 | + await fake_controller.add_paired_device(accessories, "00:00:00:00:00:00") |
| 503 | + config_entry = MockConfigEntry( |
| 504 | + version=1, |
| 505 | + domain="homekit_controller", |
| 506 | + entry_id="TestData", |
| 507 | + data={"AccessoryPairingID": "00:00:00:00:00:00"}, |
| 508 | + title="test", |
| 509 | + ) |
| 510 | + config_entry.add_to_hass(hass) |
| 511 | + |
| 512 | + # Get the pairing and patch its get_characteristics |
| 513 | + pairing = fake_controller.pairings["00:00:00:00:00:00"] |
| 514 | + |
| 515 | + with mock.patch.object(pairing, "get_characteristics", mock_get_characteristics): |
| 516 | + # Set up the config entry (this should trigger poll_all=True) |
| 517 | + await hass.config_entries.async_setup(config_entry.entry_id) |
| 518 | + await hass.async_block_till_done() |
| 519 | + |
| 520 | + # Verify that polling happened during setup (poll_all=True was used) |
| 521 | + assert ( |
| 522 | + len(polled_chars) == 79 |
| 523 | + ) # The Ecobee fixture has exactly 79 readable characteristics |
| 524 | + |
| 525 | + # Check that the climate entity has the fresh temperature (22.5°C) not the stale fixture value (21.8°C) |
| 526 | + state = hass.states.get("climate.homew") |
| 527 | + assert state is not None |
| 528 | + assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 22.5 |
0 commit comments