diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 26888a930e33c1..1737143afb7b34 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1347,7 +1347,7 @@ jobs: pattern: coverage-* - name: Upload coverage to Codecov if: needs.info.outputs.test_full_suite == 'true' - uses: codecov/codecov-action@v5.5.0 + uses: codecov/codecov-action@v5.5.1 with: fail_ci_if_error: true flags: full-suite @@ -1498,7 +1498,7 @@ jobs: pattern: coverage-* - name: Upload coverage to Codecov if: needs.info.outputs.test_full_suite == 'false' - uses: codecov/codecov-action@v5.5.0 + uses: codecov/codecov-action@v5.5.1 with: fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/detect-duplicate-issues.yml b/.github/workflows/detect-duplicate-issues.yml index 7d2bb78cbffe1f..1997f1c02b0c63 100644 --- a/.github/workflows/detect-duplicate-issues.yml +++ b/.github/workflows/detect-duplicate-issues.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Check if integration label was added and extract details id: extract - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8 with: script: | // Debug: Log the event payload @@ -113,7 +113,7 @@ jobs: - name: Fetch similar issues id: fetch_similar if: steps.extract.outputs.should_continue == 'true' - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8 env: INTEGRATION_LABELS: ${{ steps.extract.outputs.integration_labels }} CURRENT_NUMBER: ${{ steps.extract.outputs.current_number }} @@ -280,7 +280,7 @@ jobs: - name: Post duplicate detection results id: post_results if: steps.extract.outputs.should_continue == 'true' && steps.fetch_similar.outputs.has_similar == 'true' - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8 env: AI_RESPONSE: ${{ steps.ai_detection.outputs.response }} SIMILAR_ISSUES: ${{ steps.fetch_similar.outputs.similar_issues }} diff --git a/.github/workflows/detect-non-english-issues.yml b/.github/workflows/detect-non-english-issues.yml index 69718fd4421d07..d18726c8c793ba 100644 --- a/.github/workflows/detect-non-english-issues.yml +++ b/.github/workflows/detect-non-english-issues.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Check issue language id: detect_language - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8 env: ISSUE_NUMBER: ${{ github.event.issue.number }} ISSUE_TITLE: ${{ github.event.issue.title }} @@ -90,7 +90,7 @@ jobs: - name: Process non-English issues if: steps.detect_language.outputs.should_continue == 'true' - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8 env: AI_RESPONSE: ${{ steps.ai_language_detection.outputs.response }} ISSUE_NUMBER: ${{ steps.detect_language.outputs.issue_number }} diff --git a/.github/workflows/restrict-task-creation.yml b/.github/workflows/restrict-task-creation.yml index 36d9688f50afb9..beb14a80bed6a3 100644 --- a/.github/workflows/restrict-task-creation.yml +++ b/.github/workflows/restrict-task-creation.yml @@ -12,7 +12,7 @@ jobs: if: github.event.issue.type.name == 'Task' steps: - name: Check if user is authorized - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: script: | const issueAuthor = context.payload.issue.user.login; diff --git a/homeassistant/components/androidtv_remote/strings.json b/homeassistant/components/androidtv_remote/strings.json index d0eb1d0dca4cb4..b1a220e2a32ca1 100644 --- a/homeassistant/components/androidtv_remote/strings.json +++ b/homeassistant/components/androidtv_remote/strings.json @@ -22,7 +22,7 @@ }, "zeroconf_confirm": { "title": "Discovered Android TV", - "description": "Do you want to add the Android TV ({name}) to Home Assistant? It will turn on and a pairing code will be displayed on it that you will need to enter in the next screen." + "description": "Do you want to add the Android TV ({name}) to Home Assistant? It will turn on and a pairing code will be displayed on it that you will need to enter in the next screen." }, "pair": { "description": "Enter the pairing code displayed on the Android TV ({name}).", diff --git a/homeassistant/components/esphome/manifest.json b/homeassistant/components/esphome/manifest.json index 8dd198d1da1fff..05da3dacbc46ae 100644 --- a/homeassistant/components/esphome/manifest.json +++ b/homeassistant/components/esphome/manifest.json @@ -17,7 +17,7 @@ "mqtt": ["esphome/discover/#"], "quality_scale": "platinum", "requirements": [ - "aioesphomeapi==39.0.1", + "aioesphomeapi==40.0.1", "esphome-dashboard-api==1.3.0", "bleak-esphome==3.2.0" ], diff --git a/homeassistant/components/intent/__init__.py b/homeassistant/components/intent/__init__.py index 72853276ab3aa2..17ec8602d9834d 100644 --- a/homeassistant/components/intent/__init__.py +++ b/homeassistant/components/intent/__init__.py @@ -615,7 +615,7 @@ async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response intent_result = await intent.async_handle( hass, DOMAIN, intent_name, slots, "", self.context(request) ) - except intent.IntentHandleError as err: + except (intent.IntentHandleError, intent.MatchFailedError) as err: intent_result = intent.IntentResponse(language=language) intent_result.async_set_speech(str(err)) diff --git a/homeassistant/components/ohme/coordinator.py b/homeassistant/components/ohme/coordinator.py index 864b03e9a7c108..d9e009ed1f10d9 100644 --- a/homeassistant/components/ohme/coordinator.py +++ b/homeassistant/components/ohme/coordinator.py @@ -10,7 +10,7 @@ from ohme import ApiException, OhmeApiClient from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import DOMAIN @@ -83,6 +83,21 @@ class OhmeAdvancedSettingsCoordinator(OhmeBaseCoordinator): coordinator_name = "Advanced Settings" + def __init__( + self, hass: HomeAssistant, config_entry: OhmeConfigEntry, client: OhmeApiClient + ) -> None: + """Initialise coordinator.""" + super().__init__(hass, config_entry, client) + + @callback + def _dummy_listener() -> None: + pass + + # This coordinator is used by the API library to determine whether the + # charger is online and available. It is therefore required even if no + # entities are using it. + self.async_add_listener(_dummy_listener) + async def _internal_update_data(self) -> None: """Fetch data from API endpoint.""" await self.client.async_get_advanced_settings() diff --git a/homeassistant/components/sia/strings.json b/homeassistant/components/sia/strings.json index df2e11b56599de..00b610e8dc8881 100644 --- a/homeassistant/components/sia/strings.json +++ b/homeassistant/components/sia/strings.json @@ -11,7 +11,7 @@ "zones": "Number of zones for the account", "additional_account": "Additional accounts" }, - "title": "Create a connection for SIA-based alarm systems." + "title": "Create a connection for SIA-based alarm systems" }, "additional_account": { "data": { @@ -21,7 +21,7 @@ "zones": "[%key:component::sia::config::step::user::data::zones%]", "additional_account": "[%key:component::sia::config::step::user::data::additional_account%]" }, - "title": "Add another account to the current port." + "title": "Add another account to the current port" } }, "abort": { @@ -45,7 +45,7 @@ "zones": "[%key:component::sia::config::step::user::data::zones%]" }, "description": "Set the options for account: {account}", - "title": "Options for the SIA Setup." + "title": "Options for the SIA setup" } } } diff --git a/homeassistant/components/systemmonitor/sensor.py b/homeassistant/components/systemmonitor/sensor.py index e70bccf0833ad3..31e6b0f6572b29 100644 --- a/homeassistant/components/systemmonitor/sensor.py +++ b/homeassistant/components/systemmonitor/sensor.py @@ -54,6 +54,13 @@ SIGNAL_SYSTEMMONITOR_UPDATE = "systemmonitor_update" +SENSORS_NO_ARG = ("load_", "memory_", "processor_use", "swap_", "last_boot") +SENSORS_WITH_ARG = { + "disk_": "disk_arguments", + "ipv": "network_arguments", + **dict.fromkeys(NET_IO_TYPES, "network_arguments"), +} + @lru_cache def get_cpu_icon() -> Literal["mdi:cpu-64-bit", "mdi:cpu-32-bit"]: @@ -422,105 +429,27 @@ def get_arguments() -> dict[str, Any]: startup_arguments["cpu_temperature"] = cpu_temperature _LOGGER.debug("Setup from options %s", entry.options) - for _type, sensor_description in SENSOR_TYPES.items(): - if _type.startswith("disk_"): - for argument in startup_arguments["disk_arguments"]: - is_enabled = check_legacy_resource( - f"{_type}_{argument}", legacy_resources - ) - if (_add := slugify(f"{_type}_{argument}")) not in loaded_resources: - loaded_resources.add(_add) - entities.append( - SystemMonitorSensor( - coordinator, - sensor_description, - entry.entry_id, - argument, - is_enabled, - ) - ) - continue - - if _type.startswith("ipv"): - for argument in startup_arguments["network_arguments"]: - is_enabled = check_legacy_resource( - f"{_type}_{argument}", legacy_resources - ) - loaded_resources.add(slugify(f"{_type}_{argument}")) - entities.append( - SystemMonitorSensor( - coordinator, - sensor_description, - entry.entry_id, - argument, - is_enabled, - ) - ) - continue - - if _type == "last_boot": - argument = "" - is_enabled = check_legacy_resource(f"{_type}_{argument}", legacy_resources) - loaded_resources.add(slugify(f"{_type}_{argument}")) - entities.append( - SystemMonitorSensor( - coordinator, - sensor_description, - entry.entry_id, - argument, - is_enabled, - ) - ) - continue - - if _type.startswith("load_"): - argument = "" - is_enabled = check_legacy_resource(f"{_type}_{argument}", legacy_resources) - loaded_resources.add(slugify(f"{_type}_{argument}")) - entities.append( - SystemMonitorSensor( - coordinator, - sensor_description, - entry.entry_id, - argument, - is_enabled, - ) - ) - continue - - if _type.startswith("memory_"): - argument = "" - is_enabled = check_legacy_resource(f"{_type}_{argument}", legacy_resources) - loaded_resources.add(slugify(f"{_type}_{argument}")) - entities.append( - SystemMonitorSensor( - coordinator, - sensor_description, - entry.entry_id, - argument, - is_enabled, - ) - ) - - if _type in NET_IO_TYPES: - for argument in startup_arguments["network_arguments"]: - is_enabled = check_legacy_resource( - f"{_type}_{argument}", legacy_resources - ) - loaded_resources.add(slugify(f"{_type}_{argument}")) - entities.append( - SystemMonitorSensor( - coordinator, - sensor_description, - entry.entry_id, - argument, - is_enabled, + for sensor_type, sensor_argument in SENSORS_WITH_ARG.items(): + if _type.startswith(sensor_type): + for argument in startup_arguments[sensor_argument]: + is_enabled = check_legacy_resource( + f"{_type}_{argument}", legacy_resources ) - ) - continue + if (_add := slugify(f"{_type}_{argument}")) not in loaded_resources: + loaded_resources.add(_add) + entities.append( + SystemMonitorSensor( + coordinator, + sensor_description, + entry.entry_id, + argument, + is_enabled, + ) + ) + continue - if _type == "processor_use": + if _type.startswith(SENSORS_NO_ARG): argument = "" is_enabled = check_legacy_resource(f"{_type}_{argument}", legacy_resources) loaded_resources.add(slugify(f"{_type}_{argument}")) @@ -553,20 +482,6 @@ def get_arguments() -> dict[str, Any]: ) continue - if _type.startswith("swap_"): - argument = "" - is_enabled = check_legacy_resource(f"{_type}_{argument}", legacy_resources) - loaded_resources.add(slugify(f"{_type}_{argument}")) - entities.append( - SystemMonitorSensor( - coordinator, - sensor_description, - entry.entry_id, - argument, - is_enabled, - ) - ) - # Ensure legacy imported disk_* resources are loaded if they are not part # of mount points automatically discovered for resource in legacy_resources: diff --git a/homeassistant/components/tuya/__init__.py b/homeassistant/components/tuya/__init__.py index 0a5a71ffc3a090..a01f3da1ba58da 100644 --- a/homeassistant/components/tuya/__init__.py +++ b/homeassistant/components/tuya/__init__.py @@ -157,9 +157,7 @@ def __init__( self.hass = hass self.manager = manager - # pylint disable can be removed when issue fixed in library - # https://github.com/tuya/tuya-device-sharing-sdk/pull/35 - def update_device( # pylint: disable=arguments-renamed + def update_device( self, device: CustomerDevice, updated_status_properties: list[str] | None = None, diff --git a/homeassistant/components/tuya/manifest.json b/homeassistant/components/tuya/manifest.json index b130cb4c0e290b..522a09bf121cc6 100644 --- a/homeassistant/components/tuya/manifest.json +++ b/homeassistant/components/tuya/manifest.json @@ -43,5 +43,5 @@ "integration_type": "hub", "iot_class": "cloud_push", "loggers": ["tuya_iot"], - "requirements": ["tuya-device-sharing-sdk==0.2.3"] + "requirements": ["tuya-device-sharing-sdk==0.2.4"] } diff --git a/requirements_all.txt b/requirements_all.txt index fcce1a87dbf909..65d5e1f483ee2f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -247,7 +247,7 @@ aioelectricitymaps==1.1.1 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==39.0.1 +aioesphomeapi==40.0.1 # homeassistant.components.flo aioflo==2021.11.0 @@ -2991,7 +2991,7 @@ ttls==1.8.3 ttn_client==1.2.0 # homeassistant.components.tuya -tuya-device-sharing-sdk==0.2.3 +tuya-device-sharing-sdk==0.2.4 # homeassistant.components.twentemilieu twentemilieu==2.2.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d9adddc1969438..82766490811076 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -235,7 +235,7 @@ aioelectricitymaps==1.1.1 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==39.0.1 +aioesphomeapi==40.0.1 # homeassistant.components.flo aioflo==2021.11.0 @@ -2465,7 +2465,7 @@ ttls==1.8.3 ttn_client==1.2.0 # homeassistant.components.tuya -tuya-device-sharing-sdk==0.2.3 +tuya-device-sharing-sdk==0.2.4 # homeassistant.components.twentemilieu twentemilieu==2.2.1 diff --git a/tests/components/intent/test_init.py b/tests/components/intent/test_init.py index 3779930e360a8e..1993ebe46e40b0 100644 --- a/tests/components/intent/test_init.py +++ b/tests/components/intent/test_init.py @@ -73,6 +73,32 @@ async def async_handle(self, intent_obj): } +async def test_http_handle_intent_match_failure( + hass: HomeAssistant, hass_client: ClientSessionGenerator, hass_admin_user: MockUser +) -> None: + """Test handle intent match failure via HTTP API.""" + + assert await async_setup_component(hass, "intent", {}) + + hass.states.async_set( + "cover.garage_door_1", "closed", {ATTR_FRIENDLY_NAME: "Garage Door"} + ) + hass.states.async_set( + "cover.garage_door_2", "closed", {ATTR_FRIENDLY_NAME: "Garage Door"} + ) + async_mock_service(hass, "cover", SERVICE_OPEN_COVER) + + client = await hass_client() + resp = await client.post( + "/api/intent/handle", + json={"name": "HassTurnOn", "data": {"name": "Garage Door"}}, + ) + assert resp.status == 200 + data = await resp.json() + + assert "DUPLICATE_NAME" in data["speech"]["plain"]["speech"] + + async def test_cover_intents_loading(hass: HomeAssistant) -> None: """Test Cover Intents Loading.""" assert await async_setup_component(hass, "intent", {})