diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cbc343b9d981ba..cc6014b38b04aa 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,11 +24,11 @@ jobs: uses: actions/checkout@v4.2.2 - name: Initialize CodeQL - uses: github/codeql-action/init@v3.29.3 + uses: github/codeql-action/init@v3.29.4 with: languages: python - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3.29.3 + uses: github/codeql-action/analyze@v3.29.4 with: category: "/language:python" diff --git a/homeassistant/components/august/manifest.json b/homeassistant/components/august/manifest.json index 9dc66084a4568c..2368c848eea813 100644 --- a/homeassistant/components/august/manifest.json +++ b/homeassistant/components/august/manifest.json @@ -28,5 +28,5 @@ "documentation": "https://www.home-assistant.io/integrations/august", "iot_class": "cloud_push", "loggers": ["pubnub", "yalexs"], - "requirements": ["yalexs==8.10.0", "yalexs-ble==3.0.0"] + "requirements": ["yalexs==8.10.0", "yalexs-ble==3.1.0"] } diff --git a/homeassistant/components/google_cloud/const.py b/homeassistant/components/google_cloud/const.py index 16b1463f0f31a3..3a0b2bc48329d4 100644 --- a/homeassistant/components/google_cloud/const.py +++ b/homeassistant/components/google_cloud/const.py @@ -186,3 +186,13 @@ "yue-Hant-HK", "zu-ZA", ] + +# This allows us to support HA's standard codes (e.g., zh-CN) while +# sending the correct code to the Google API (e.g., cmn-Hans-CN). +HA_TO_GOOGLE_STT_LANG_MAP = { + "zh-CN": "cmn-Hans-CN", # Chinese (Mandarin, Simplified, China) + "zh-HK": "yue-Hant-HK", # Chinese (Cantonese, Traditional, Hong Kong) + "zh-TW": "cmn-Hant-TW", # Chinese (Mandarin, Traditional, Taiwan) + "he-IL": "iw-IL", # Hebrew (Google uses 'iw' legacy code) + "nb-NO": "no-NO", # Norwegian Bokmål +} diff --git a/homeassistant/components/google_cloud/stt.py b/homeassistant/components/google_cloud/stt.py index 8a548cde8bb3d2..ea438b01cdd1a9 100644 --- a/homeassistant/components/google_cloud/stt.py +++ b/homeassistant/components/google_cloud/stt.py @@ -8,6 +8,7 @@ from google.api_core.exceptions import GoogleAPIError, Unauthenticated from google.api_core.retry import AsyncRetry from google.cloud import speech_v1 +from propcache.api import cached_property from homeassistant.components.stt import ( AudioBitRates, @@ -30,6 +31,7 @@ CONF_STT_MODEL, DEFAULT_STT_MODEL, DOMAIN, + HA_TO_GOOGLE_STT_LANG_MAP, STT_LANGUAGES, ) @@ -68,10 +70,14 @@ def __init__( self._client = client self._model = entry.options.get(CONF_STT_MODEL, DEFAULT_STT_MODEL) - @property + @cached_property def supported_languages(self) -> list[str]: """Return a list of supported languages.""" - return STT_LANGUAGES + # Combine the native Google languages and the standard HA languages. + # A set is used to automatically handle duplicates. + supported = set(STT_LANGUAGES) + supported.update(HA_TO_GOOGLE_STT_LANG_MAP.keys()) + return sorted(supported) @property def supported_formats(self) -> list[AudioFormats]: @@ -102,6 +108,10 @@ async def async_process_audio_stream( self, metadata: SpeechMetadata, stream: AsyncIterable[bytes] ) -> SpeechResult: """Process an audio stream to STT service.""" + language_code = HA_TO_GOOGLE_STT_LANG_MAP.get( + metadata.language, metadata.language + ) + streaming_config = speech_v1.StreamingRecognitionConfig( config=speech_v1.RecognitionConfig( encoding=( @@ -110,7 +120,7 @@ async def async_process_audio_stream( else speech_v1.RecognitionConfig.AudioEncoding.LINEAR16 ), sample_rate_hertz=metadata.sample_rate, - language_code=metadata.language, + language_code=language_code, model=self._model, ) ) diff --git a/homeassistant/components/luftdaten/strings.json b/homeassistant/components/luftdaten/strings.json index ea842f18ebd375..072252cdf21526 100644 --- a/homeassistant/components/luftdaten/strings.json +++ b/homeassistant/components/luftdaten/strings.json @@ -19,7 +19,7 @@ }, "entity": { "sensor": { - "pressure_at_sealevel": { "name": "Pressure at sealevel" } + "pressure_at_sealevel": { "name": "Pressure at sea level" } } } } diff --git a/homeassistant/components/mjpeg/strings.json b/homeassistant/components/mjpeg/strings.json index 0e1e71fd82c6c0..ed53f6bcdc9e90 100644 --- a/homeassistant/components/mjpeg/strings.json +++ b/homeassistant/components/mjpeg/strings.json @@ -6,7 +6,7 @@ "mjpeg_url": "MJPEG URL", "name": "[%key:common::config_flow::data::name%]", "password": "[%key:common::config_flow::data::password%]", - "still_image_url": "Still Image URL", + "still_image_url": "Still image URL", "username": "[%key:common::config_flow::data::username%]", "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]" } diff --git a/homeassistant/components/modbus/strings.json b/homeassistant/components/modbus/strings.json index 7d1578558b0506..0749ba4a2c8158 100644 --- a/homeassistant/components/modbus/strings.json +++ b/homeassistant/components/modbus/strings.json @@ -50,7 +50,7 @@ }, "stop": { "name": "[%key:common::action::stop%]", - "description": "Stops modbus hub.", + "description": "Stops a Modbus hub.", "fields": { "hub": { "name": "[%key:component::modbus::services::write_coil::fields::hub::name%]", @@ -60,7 +60,7 @@ }, "restart": { "name": "[%key:common::action::restart%]", - "description": "Restarts modbus hub (if running stop then start).", + "description": "Restarts a Modbus hub (if running, stops then starts).", "fields": { "hub": { "name": "[%key:component::modbus::services::write_coil::fields::hub::name%]", diff --git a/homeassistant/components/music_assistant/strings.json b/homeassistant/components/music_assistant/strings.json index c41bfa70d4c945..37f0a8e9a855b9 100644 --- a/homeassistant/components/music_assistant/strings.json +++ b/homeassistant/components/music_assistant/strings.json @@ -102,7 +102,7 @@ "description": "The source media player which has the queue you want to transfer. When omitted, the first playing player will be used." }, "auto_play": { - "name": "Auto play", + "name": "Autoplay", "description": "Start playing the queue on the target player. Omit to use the default behavior." } } diff --git a/homeassistant/components/onkyo/manifest.json b/homeassistant/components/onkyo/manifest.json index 07834d4cba1bb1..6102f8f249529c 100644 --- a/homeassistant/components/onkyo/manifest.json +++ b/homeassistant/components/onkyo/manifest.json @@ -8,7 +8,8 @@ "integration_type": "device", "iot_class": "local_push", "loggers": ["aioonkyo"], - "requirements": ["aioonkyo==0.2.0"], + "quality_scale": "bronze", + "requirements": ["aioonkyo==0.3.0"], "ssdp": [ { "manufacturer": "ONKYO", diff --git a/homeassistant/components/rainbird/strings.json b/homeassistant/components/rainbird/strings.json index 6f92b1bdb97da4..ca7dc18b8d8966 100644 --- a/homeassistant/components/rainbird/strings.json +++ b/homeassistant/components/rainbird/strings.json @@ -80,8 +80,8 @@ "description": "Sets how long automatic irrigation is turned off.", "fields": { "config_entry_id": { - "name": "Rainbird Controller Configuration Entry", - "description": "The setting will be adjusted on the specified controller." + "name": "Rain Bird controller", + "description": "The configuration entry of the controller to adjust the setting." }, "duration": { "name": "Duration", diff --git a/homeassistant/components/samsungtv/strings.json b/homeassistant/components/samsungtv/strings.json index 6251e65b2f82e5..aa0e77e0b76d8a 100644 --- a/homeassistant/components/samsungtv/strings.json +++ b/homeassistant/components/samsungtv/strings.json @@ -50,7 +50,7 @@ "already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]", "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "auth_missing": "Home Assistant is not authorized to connect to this Samsung TV. Check your TV's External Device Manager settings to authorize Home Assistant.", - "id_missing": "This Samsung device doesn't have a SerialNumber.", + "id_missing": "This Samsung device doesn't have a serial number to identify it.", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "not_supported": "This Samsung device is currently not supported.", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" diff --git a/homeassistant/components/teslemetry/strings.json b/homeassistant/components/teslemetry/strings.json index 57b6053bb48bc4..646a3898cc7d19 100644 --- a/homeassistant/components/teslemetry/strings.json +++ b/homeassistant/components/teslemetry/strings.json @@ -192,7 +192,7 @@ "name": "European vehicle" }, "right_hand_drive": { - "name": "Right hand drive" + "name": "Right-hand drive" }, "located_at_home": { "name": "Located at home" diff --git a/homeassistant/components/webostv/strings.json b/homeassistant/components/webostv/strings.json index f6d033af632faa..2f0a413754eafc 100644 --- a/homeassistant/components/webostv/strings.json +++ b/homeassistant/components/webostv/strings.json @@ -12,7 +12,7 @@ } }, "pairing": { - "title": "LG webOS TV Pairing", + "title": "LG webOS TV pairing", "description": "Select **Submit** and accept the pairing request on your TV.\n\n![Image](/static/images/config_webos.png)" }, "reauth_confirm": { @@ -37,7 +37,7 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", "reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]", - "wrong_device": "The configured device is not the same found on this Hostname or IP address." + "wrong_device": "The configured device is not the same found at this hostname or IP address." } }, "options": { @@ -70,7 +70,7 @@ "fields": { "entity_id": { "name": "Entity", - "description": "Name(s) of the webostv entities where to run the API method." + "description": "Name(s) of the webOS TV entities where to run the API method." }, "button": { "name": "Button", @@ -92,7 +92,7 @@ }, "payload": { "name": "Payload", - "description": "An optional payload to provide to the endpoint in the format of key value pair(s)." + "description": "An optional payload to provide to the endpoint in the format of key value pairs." } } }, @@ -102,7 +102,7 @@ "fields": { "entity_id": { "name": "Entity", - "description": "Name(s) of the webostv entities to change sound output on." + "description": "Name(s) of the webOS TV entities to change sound output on." }, "sound_output": { "name": "Sound output", @@ -134,7 +134,7 @@ "message": "Unknown trigger platform: {platform}" }, "invalid_entity_id": { - "message": "Entity {entity_id} is not a valid webostv entity." + "message": "Entity {entity_id} is not a valid webOS TV entity." }, "source_not_found": { "message": "Source {source} not found in the sources list for {name}." diff --git a/homeassistant/components/yale/manifest.json b/homeassistant/components/yale/manifest.json index fee5b0b8310d58..5b45628ee64c47 100644 --- a/homeassistant/components/yale/manifest.json +++ b/homeassistant/components/yale/manifest.json @@ -13,5 +13,5 @@ "documentation": "https://www.home-assistant.io/integrations/yale", "iot_class": "cloud_push", "loggers": ["socketio", "engineio", "yalexs"], - "requirements": ["yalexs==8.10.0", "yalexs-ble==3.0.0"] + "requirements": ["yalexs==8.10.0", "yalexs-ble==3.1.0"] } diff --git a/homeassistant/components/yalexs_ble/manifest.json b/homeassistant/components/yalexs_ble/manifest.json index b3021bd908ed35..7a02afbc5d75a5 100644 --- a/homeassistant/components/yalexs_ble/manifest.json +++ b/homeassistant/components/yalexs_ble/manifest.json @@ -12,5 +12,5 @@ "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/yalexs_ble", "iot_class": "local_push", - "requirements": ["yalexs-ble==3.0.0"] + "requirements": ["yalexs-ble==3.1.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index ab474d4a9cef41..e24f1bcd209cc0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -331,7 +331,7 @@ aiontfy==0.5.3 aionut==4.3.4 # homeassistant.components.onkyo -aioonkyo==0.2.0 +aioonkyo==0.3.0 # homeassistant.components.openexchangerates aioopenexchangerates==0.6.8 @@ -3157,7 +3157,7 @@ yalesmartalarmclient==0.4.3 # homeassistant.components.august # homeassistant.components.yale # homeassistant.components.yalexs_ble -yalexs-ble==3.0.0 +yalexs-ble==3.1.0 # homeassistant.components.august # homeassistant.components.yale diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 87a8212d2145d1..dffabce4fbf486 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -313,7 +313,7 @@ aiontfy==0.5.3 aionut==4.3.4 # homeassistant.components.onkyo -aioonkyo==0.2.0 +aioonkyo==0.3.0 # homeassistant.components.openexchangerates aioopenexchangerates==0.6.8 @@ -2607,7 +2607,7 @@ yalesmartalarmclient==0.4.3 # homeassistant.components.august # homeassistant.components.yale # homeassistant.components.yalexs_ble -yalexs-ble==3.0.0 +yalexs-ble==3.1.0 # homeassistant.components.august # homeassistant.components.yale diff --git a/script/hassfest/quality_scale.py b/script/hassfest/quality_scale.py index 3008c6303ff11b..04812e9aefa443 100644 --- a/script/hassfest/quality_scale.py +++ b/script/hassfest/quality_scale.py @@ -1777,7 +1777,6 @@ class Rule: "ombi", "omnilogic", "oncue", - "onkyo", "ondilo_ico", "onewire", "onvif", diff --git a/tests/components/luftdaten/test_sensor.py b/tests/components/luftdaten/test_sensor.py index f2cf12b3fda6c8..bbabc486355b57 100644 --- a/tests/components/luftdaten/test_sensor.py +++ b/tests/components/luftdaten/test_sensor.py @@ -72,16 +72,16 @@ async def test_luftdaten_sensors( assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfPressure.PA assert ATTR_ICON not in state.attributes - entry = entity_registry.async_get("sensor.sensor_12345_pressure_at_sealevel") + entry = entity_registry.async_get("sensor.sensor_12345_pressure_at_sea_level") assert entry assert entry.device_id assert entry.unique_id == "12345_pressure_at_sealevel" - state = hass.states.get("sensor.sensor_12345_pressure_at_sealevel") + state = hass.states.get("sensor.sensor_12345_pressure_at_sea_level") assert state assert state.state == "103102.13" assert ( - state.attributes.get(ATTR_FRIENDLY_NAME) == "Sensor 12345 Pressure at sealevel" + state.attributes.get(ATTR_FRIENDLY_NAME) == "Sensor 12345 Pressure at sea level" ) assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.PRESSURE assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT diff --git a/tests/components/webostv/test_trigger.py b/tests/components/webostv/test_trigger.py index c7decafff73880..646b8f8034aec1 100644 --- a/tests/components/webostv/test_trigger.py +++ b/tests/components/webostv/test_trigger.py @@ -182,4 +182,4 @@ async def test_trigger_invalid_entity_id( }, ) - assert f"Entity {invalid_entity} is not a valid {DOMAIN} entity" in caplog.text + assert f"Entity {invalid_entity} is not a valid webOS TV entity" in caplog.text diff --git a/tests/components/yalexs_ble/test_config_flow.py b/tests/components/yalexs_ble/test_config_flow.py index 1b0df05db2cab4..c272036097dfa1 100644 --- a/tests/components/yalexs_ble/test_config_flow.py +++ b/tests/components/yalexs_ble/test_config_flow.py @@ -37,7 +37,7 @@ def _get_mock_push_lock(): mock_push_lock.wait_for_first_update = AsyncMock() mock_push_lock.stop = AsyncMock() mock_push_lock.lock_state = LockState( - LockStatus.UNLOCKED, DoorStatus.CLOSED, None, None + LockStatus.UNLOCKED, DoorStatus.CLOSED, None, None, None, None ) mock_push_lock.lock_status = LockStatus.UNLOCKED mock_push_lock.door_status = DoorStatus.CLOSED