diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3cad6a4e53241..e5b4a6614e6f8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -263,7 +263,7 @@ jobs: check-latest: true - name: Restore base Python virtual environment id: cache-venv - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv key: >- @@ -279,7 +279,7 @@ jobs: uv pip install "$(cat requirements_test.txt | grep pre-commit)" - name: Restore pre-commit environment from cache id: cache-precommit - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.PRE_COMMIT_CACHE }} lookup-only: true @@ -309,7 +309,7 @@ jobs: check-latest: true - name: Restore base Python virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -318,7 +318,7 @@ jobs: needs.info.outputs.pre-commit_cache_key }} - name: Restore pre-commit environment from cache id: cache-precommit - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.PRE_COMMIT_CACHE }} fail-on-cache-miss: true @@ -349,7 +349,7 @@ jobs: check-latest: true - name: Restore base Python virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -358,7 +358,7 @@ jobs: needs.info.outputs.pre-commit_cache_key }} - name: Restore pre-commit environment from cache id: cache-precommit - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.PRE_COMMIT_CACHE }} fail-on-cache-miss: true @@ -389,7 +389,7 @@ jobs: check-latest: true - name: Restore base Python virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -398,7 +398,7 @@ jobs: needs.info.outputs.pre-commit_cache_key }} - name: Restore pre-commit environment from cache id: cache-precommit - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.PRE_COMMIT_CACHE }} fail-on-cache-miss: true @@ -505,7 +505,7 @@ jobs: env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT - name: Restore base Python virtual environment id: cache-venv - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv key: >- @@ -513,7 +513,7 @@ jobs: needs.info.outputs.python_cache_key }} - name: Restore uv wheel cache if: steps.cache-venv.outputs.cache-hit != 'true' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ${{ env.UV_CACHE_DIR }} key: >- @@ -525,7 +525,7 @@ jobs: env.HA_SHORT_VERSION }}- - name: Check if apt cache exists id: cache-apt-check - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: lookup-only: ${{ steps.cache-venv.outputs.cache-hit == 'true' }} path: | @@ -570,7 +570,7 @@ jobs: fi - name: Save apt cache if: steps.cache-apt-check.outputs.cache-hit != 'true' - uses: actions/cache/save@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ${{ env.APT_CACHE_DIR }} @@ -622,7 +622,7 @@ jobs: - base steps: - name: Restore apt cache - uses: actions/cache/restore@v4.2.4 + uses: actions/cache/restore@v4.3.0 with: path: | ${{ env.APT_CACHE_DIR }} @@ -651,7 +651,7 @@ jobs: check-latest: true - name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -684,7 +684,7 @@ jobs: check-latest: true - name: Restore base Python virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -741,7 +741,7 @@ jobs: check-latest: true - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -784,7 +784,7 @@ jobs: check-latest: true - name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -831,7 +831,7 @@ jobs: check-latest: true - name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -883,7 +883,7 @@ jobs: env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT - name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -891,7 +891,7 @@ jobs: ${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-${{ needs.info.outputs.python_cache_key }} - name: Restore mypy cache - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: .mypy_cache key: >- @@ -935,7 +935,7 @@ jobs: name: Split tests for full run steps: - name: Restore apt cache - uses: actions/cache/restore@v4.2.4 + uses: actions/cache/restore@v4.3.0 with: path: | ${{ env.APT_CACHE_DIR }} @@ -967,7 +967,7 @@ jobs: check-latest: true - name: Restore base Python virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -1009,7 +1009,7 @@ jobs: Run tests Python ${{ matrix.python-version }} (${{ matrix.group }}) steps: - name: Restore apt cache - uses: actions/cache/restore@v4.2.4 + uses: actions/cache/restore@v4.3.0 with: path: | ${{ env.APT_CACHE_DIR }} @@ -1042,7 +1042,7 @@ jobs: check-latest: true - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -1156,7 +1156,7 @@ jobs: Run ${{ matrix.mariadb-group }} tests Python ${{ matrix.python-version }} steps: - name: Restore apt cache - uses: actions/cache/restore@v4.2.4 + uses: actions/cache/restore@v4.3.0 with: path: | ${{ env.APT_CACHE_DIR }} @@ -1189,7 +1189,7 @@ jobs: check-latest: true - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -1310,7 +1310,7 @@ jobs: Run ${{ matrix.postgresql-group }} tests Python ${{ matrix.python-version }} steps: - name: Restore apt cache - uses: actions/cache/restore@v4.2.4 + uses: actions/cache/restore@v4.3.0 with: path: | ${{ env.APT_CACHE_DIR }} @@ -1345,7 +1345,7 @@ jobs: check-latest: true - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true @@ -1485,7 +1485,7 @@ jobs: Run tests Python ${{ matrix.python-version }} (${{ matrix.group }}) steps: - name: Restore apt cache - uses: actions/cache/restore@v4.2.4 + uses: actions/cache/restore@v4.3.0 with: path: | ${{ env.APT_CACHE_DIR }} @@ -1518,7 +1518,7 @@ jobs: check-latest: true - name: Restore full Python ${{ matrix.python-version }} virtual environment id: cache-venv - uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: venv fail-on-cache-miss: true diff --git a/homeassistant/components/alexa_devices/manifest.json b/homeassistant/components/alexa_devices/manifest.json index 824f735b184aa..437c11e0a4c14 100644 --- a/homeassistant/components/alexa_devices/manifest.json +++ b/homeassistant/components/alexa_devices/manifest.json @@ -7,6 +7,6 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["aioamazondevices"], - "quality_scale": "silver", + "quality_scale": "platinum", "requirements": ["aioamazondevices==6.0.0"] } diff --git a/homeassistant/components/libre_hardware_monitor/manifest.json b/homeassistant/components/libre_hardware_monitor/manifest.json index 66623db1f2d76..322f3f2934f15 100644 --- a/homeassistant/components/libre_hardware_monitor/manifest.json +++ b/homeassistant/components/libre_hardware_monitor/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/libre_hardware_monitor", "iot_class": "local_polling", "quality_scale": "silver", - "requirements": ["librehardwaremonitor-api==1.3.1"] + "requirements": ["librehardwaremonitor-api==1.4.0"] } diff --git a/homeassistant/components/litterrobot/quality_scale.yaml b/homeassistant/components/litterrobot/quality_scale.yaml index 82f01f64d18e3..3b26500da9791 100644 --- a/homeassistant/components/litterrobot/quality_scale.yaml +++ b/homeassistant/components/litterrobot/quality_scale.yaml @@ -28,7 +28,7 @@ rules: docs-configuration-parameters: status: done comment: No options to configure - docs-installation-parameters: todo + docs-installation-parameters: done entity-unavailable: todo integration-owner: done log-when-unavailable: todo diff --git a/homeassistant/components/portainer/binary_sensor.py b/homeassistant/components/portainer/binary_sensor.py index 5545cfc9b9312..543bdeaf335d4 100644 --- a/homeassistant/components/portainer/binary_sensor.py +++ b/homeassistant/components/portainer/binary_sensor.py @@ -131,7 +131,15 @@ def __init__( self.entity_description = entity_description super().__init__(device_info, coordinator, via_device) - self._attr_unique_id = f"{coordinator.config_entry.entry_id}_{device_info.id}_{entity_description.key}" + # Container ID's are ephemeral, so use the container name for the unique ID + # The first one, should always be unique, it's fine if users have aliases + # According to Docker's API docs, the first name is unique + device_identifier = ( + self._device_info.names[0].replace("/", " ").strip() + if self._device_info.names + else None + ) + self._attr_unique_id = f"{coordinator.config_entry.entry_id}_{device_identifier}_{entity_description.key}" @property def available(self) -> bool: diff --git a/homeassistant/components/portainer/entity.py b/homeassistant/components/portainer/entity.py index ecabafc4663f4..5fd53236cd825 100644 --- a/homeassistant/components/portainer/entity.py +++ b/homeassistant/components/portainer/entity.py @@ -60,7 +60,7 @@ def __init__( self._attr_device_info = DeviceInfo( identifiers={ - (DOMAIN, f"{self.coordinator.config_entry.entry_id}_{self.device_id}") + (DOMAIN, f"{self.coordinator.config_entry.entry_id}_{device_name}") }, manufacturer=DEFAULT_NAME, model="Container", diff --git a/homeassistant/components/roborock/coordinator.py b/homeassistant/components/roborock/coordinator.py index 39966273908dd..e36208dfee110 100644 --- a/homeassistant/components/roborock/coordinator.py +++ b/homeassistant/components/roborock/coordinator.py @@ -351,13 +351,9 @@ async def _async_update_data(self) -> DeviceProp: def _set_current_map(self) -> None: if ( self.roborock_device_info.props.status is not None - and self.roborock_device_info.props.status.map_status is not None + and self.roborock_device_info.props.status.current_map is not None ): - # The map status represents the map flag as flag * 4 + 3 - - # so we have to invert that in order to get the map flag that we can use to set the current map. - self.current_map = ( - self.roborock_device_info.props.status.map_status - 3 - ) // 4 + self.current_map = self.roborock_device_info.props.status.current_map async def set_current_map_rooms(self) -> None: """Fetch all of the rooms for the current map and set on RoborockMapInfo.""" @@ -440,7 +436,7 @@ async def refresh_coordinator_map(self) -> None: # If either of these fail, we don't care, and we want to continue. await asyncio.gather(*tasks, return_exceptions=True) - if len(self.maps) != 1: + if len(self.maps) > 1: # Set the map back to the map the user previously had selected so that it # does not change the end user's app. # Only needs to happen when we changed maps above. diff --git a/requirements_all.txt b/requirements_all.txt index 6feb2fe6840cd..3830c097adc31 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1364,7 +1364,7 @@ libpyfoscamcgi==0.0.7 libpyvivotek==0.4.0 # homeassistant.components.libre_hardware_monitor -librehardwaremonitor-api==1.3.1 +librehardwaremonitor-api==1.4.0 # homeassistant.components.mikrotik librouteros==3.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 249f309297cb4..fb508dd12fb23 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1180,7 +1180,7 @@ letpot==0.6.2 libpyfoscamcgi==0.0.7 # homeassistant.components.libre_hardware_monitor -librehardwaremonitor-api==1.3.1 +librehardwaremonitor-api==1.4.0 # homeassistant.components.mikrotik librouteros==3.2.0 diff --git a/tests/components/portainer/snapshots/test_binary_sensor.ambr b/tests/components/portainer/snapshots/test_binary_sensor.ambr index 922b4d6cddf8d..7ec3900e49bbd 100644 --- a/tests/components/portainer/snapshots/test_binary_sensor.ambr +++ b/tests/components/portainer/snapshots/test_binary_sensor.ambr @@ -30,7 +30,7 @@ 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'status', - 'unique_id': 'portainer_test_entry_123_dd19facfb3b3ed4cd362c1e88fc89a53908ad05fb3a4103bca3f9b28292d14bf_status', + 'unique_id': 'portainer_test_entry_123_focused_einstein_status', 'unit_of_measurement': None, }) # --- @@ -79,7 +79,7 @@ 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'status', - 'unique_id': 'portainer_test_entry_123_aa86eacfb3b3ed4cd362c1e88fc89a53908ad05fb3a4103bca3f9b28292d14bf_status', + 'unique_id': 'portainer_test_entry_123_funny_chatelet_status', 'unit_of_measurement': None, }) # --- @@ -177,7 +177,7 @@ 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'status', - 'unique_id': 'portainer_test_entry_123_ee20facfb3b3ed4cd362c1e88fc89a53908ad05fb3a4103bca3f9b28292d14bf_status', + 'unique_id': 'portainer_test_entry_123_practical_morse_status', 'unit_of_measurement': None, }) # --- @@ -226,7 +226,7 @@ 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'status', - 'unique_id': 'portainer_test_entry_123_bb97facfb3b3ed4cd362c1e88fc89a53908ad05fb3a4103bca3f9b28292d14bf_status', + 'unique_id': 'portainer_test_entry_123_serene_banach_status', 'unit_of_measurement': None, }) # --- @@ -275,7 +275,7 @@ 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'status', - 'unique_id': 'portainer_test_entry_123_cc08facfb3b3ed4cd362c1e88fc89a53908ad05fb3a4103bca3f9b28292d14bf_status', + 'unique_id': 'portainer_test_entry_123_stoic_turing_status', 'unit_of_measurement': None, }) # --- diff --git a/tests/components/roborock/test_coordinator.py b/tests/components/roborock/test_coordinator.py index 22efddf5817fb..7da19e9418cbc 100644 --- a/tests/components/roborock/test_coordinator.py +++ b/tests/components/roborock/test_coordinator.py @@ -5,6 +5,7 @@ from unittest.mock import patch import pytest +from roborock import MultiMapsList from roborock.exceptions import RoborockException from vacuum_map_parser_base.config.color import SupportedColor @@ -135,3 +136,30 @@ async def test_dynamic_local_scan_interval( async_fire_time_changed(hass, dt_util.utcnow() + interval) assert hass.states.get("sensor.roborock_s7_maxv_battery").state == "20" + + +async def test_no_maps( + hass: HomeAssistant, + mock_roborock_entry: MockConfigEntry, + bypass_api_fixture: None, +) -> None: + """Test that a device with no maps is handled correctly.""" + prop = copy.deepcopy(PROP) + prop.status.map_status = 252 + with ( + patch( + "homeassistant.components.roborock.coordinator.RoborockLocalClientV1.get_prop", + return_value=prop, + ), + patch( + "homeassistant.components.roborock.coordinator.RoborockMqttClientV1.get_multi_maps_list", + return_value=MultiMapsList( + max_multi_map=1, max_bak_map=1, multi_map_count=0, map_info=[] + ), + ), + patch( + "homeassistant.components.roborock.RoborockMqttClientV1.load_multi_map" + ) as load_map, + ): + await hass.config_entries.async_setup(mock_roborock_entry.entry_id) + assert load_map.call_count == 0