From 12da814470b7b4bb13b4d18b098aa4938c8a34ac Mon Sep 17 00:00:00 2001 From: Jc2k Date: Wed, 28 Oct 2020 23:06:01 +0000 Subject: [PATCH 01/43] Bump aiohomekit to 0.2.54 (#42532) --- homeassistant/components/homekit_controller/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json index 1fb4c05c595d8..efe842bad0f23 100644 --- a/homeassistant/components/homekit_controller/manifest.json +++ b/homeassistant/components/homekit_controller/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/homekit_controller", "requirements": [ - "aiohomekit==0.2.53" + "aiohomekit==0.2.54" ], "zeroconf": [ "_hap._tcp.local." diff --git a/requirements_all.txt b/requirements_all.txt index 5712448318fc2..a9de43462b5df 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -178,7 +178,7 @@ aioguardian==1.0.1 aioharmony==0.2.6 # homeassistant.components.homekit_controller -aiohomekit==0.2.53 +aiohomekit==0.2.54 # homeassistant.components.emulated_hue # homeassistant.components.http diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3c231493be9fc..24275ad8585c6 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -109,7 +109,7 @@ aioguardian==1.0.1 aioharmony==0.2.6 # homeassistant.components.homekit_controller -aiohomekit==0.2.53 +aiohomekit==0.2.54 # homeassistant.components.emulated_hue # homeassistant.components.http From 31518937c0b2e61ae7ed64844ed61668729c61c5 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Wed, 28 Oct 2020 17:52:15 -0600 Subject: [PATCH 02/43] Cleanup RainMachine (#42544) --- homeassistant/components/rainmachine/__init__.py | 10 ++++++++-- tests/components/rainmachine/test_config_flow.py | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py index ccabc0bc55efa..7faac5f2f6007 100644 --- a/homeassistant/components/rainmachine/__init__.py +++ b/homeassistant/components/rainmachine/__init__.py @@ -44,6 +44,8 @@ CONF_SECONDS = "seconds" CONF_ZONE_ID = "zone_id" +DATA_LISTENER = "listener" + DEFAULT_ATTRIBUTION = "Data provided by Green Electronics LLC" DEFAULT_ICON = "mdi:water" DEFAULT_SCAN_INTERVAL = timedelta(seconds=60) @@ -77,7 +79,7 @@ async def async_setup(hass, config): """Set up the RainMachine component.""" - hass.data[DOMAIN] = {DATA_CLIENT: {}} + hass.data[DOMAIN] = {DATA_CLIENT: {}, DATA_LISTENER: {}} return True @@ -213,7 +215,9 @@ async def unpause_watering(call): ]: hass.services.async_register(DOMAIN, service, method, schema=schema) - config_entry.add_update_listener(async_reload_entry) + hass.data[DOMAIN][DATA_LISTENER] = config_entry.add_update_listener( + async_reload_entry + ) return True @@ -221,6 +225,8 @@ async def unpause_watering(call): async def async_unload_entry(hass, config_entry): """Unload an OpenUV config entry.""" hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id) + cancel_listener = hass.data[DOMAIN][DATA_LISTENER].pop(config_entry.entry_id) + cancel_listener() tasks = [ hass.config_entries.async_forward_entry_unload(config_entry, component) diff --git a/tests/components/rainmachine/test_config_flow.py b/tests/components/rainmachine/test_config_flow.py index 1bfd412c3c700..7fb30d0043d82 100644 --- a/tests/components/rainmachine/test_config_flow.py +++ b/tests/components/rainmachine/test_config_flow.py @@ -71,6 +71,7 @@ async def test_options_flow(hass): with patch( "homeassistant.components.rainmachine.async_setup_entry", return_value=True ): + await hass.config_entries.async_setup(config_entry.entry_id) result = await hass.config_entries.options.async_init(config_entry.entry_id) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM From 026e0063fee53b7f875e6519433ca4ffc99bf248 Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Thu, 29 Oct 2020 00:09:16 +0000 Subject: [PATCH 03/43] [ci skip] Translation update --- .../advantage_air/translations/zh-Hans.json | 3 ++ .../airly/translations/zh-Hans.json | 17 +++++++ .../arcam_fmj/translations/zh-Hans.json | 7 +++ .../components/axis/translations/zh-Hans.json | 4 ++ .../azure_devops/translations/zh-Hans.json | 8 ++++ .../binary_sensor/translations/zh-Hans.json | 6 +++ .../braviatv/translations/zh-Hans.json | 5 +++ .../cloudflare/translations/zh-Hans.json | 20 +++++++++ .../cover/translations/zh-Hans.json | 4 +- .../components/dexcom/translations/cs.json | 1 + .../components/dexcom/translations/en.json | 1 + .../components/dexcom/translations/et.json | 1 + .../components/dexcom/translations/no.json | 1 + .../components/dexcom/translations/ru.json | 1 + .../dexcom/translations/zh-Hant.json | 1 + .../ecobee/translations/zh-Hans.json | 11 +++++ .../fritzbox/translations/zh-Hans.json | 3 +- .../glances/translations/zh-Hans.json | 5 +++ .../components/heos/translations/zh-Hans.json | 7 +++ .../components/homekit/translations/cs.json | 1 + .../iaqualink/translations/zh-Hans.json | 4 ++ .../components/life360/translations/cs.json | 3 ++ .../components/life360/translations/en.json | 3 ++ .../components/life360/translations/et.json | 3 ++ .../components/life360/translations/no.json | 3 ++ .../components/life360/translations/ru.json | 3 ++ .../components/lock/translations/zh-Hans.json | 9 ++++ .../logi_circle/translations/zh-Hans.json | 3 ++ .../components/luftdaten/translations/et.json | 8 ++++ .../luftdaten/translations/zh-Hans.json | 1 + .../components/mill/translations/zh-Hans.json | 3 ++ .../neato/translations/zh-Hans.json | 1 + .../components/nest/translations/et.json | 1 + .../onewire/translations/zh-Hans.json | 7 +++ .../onvif/translations/zh-Hans.json | 3 ++ .../opentherm_gw/translations/et.json | 3 +- .../opentherm_gw/translations/zh-Hans.json | 14 ++++++ .../panasonic_viera/translations/zh-Hans.json | 10 +++++ .../components/plex/translations/zh-Hans.json | 10 +++++ .../rainmachine/translations/en.json | 4 +- .../translations/zh-Hans.json | 3 +- .../smappee/translations/zh-Hans.json | 7 +++ .../smarthab/translations/zh-Hans.json | 7 +++ .../solaredge/translations/zh-Hans.json | 11 +++++ .../solarlog/translations/zh-Hans.json | 7 +++ .../tellduslive/translations/zh-Hans.json | 3 +- .../transmission/translations/zh-Hans.json | 7 +++ .../components/tuya/translations/cs.json | 33 ++++++++++++++ .../components/tuya/translations/en.json | 45 ++++++++++--------- .../components/tuya/translations/et.json | 31 +++++++++++++ .../components/tuya/translations/no.json | 36 +++++++++++++++ .../components/tuya/translations/ru.json | 36 +++++++++++++++ .../components/tuya/translations/zh-Hant.json | 36 +++++++++++++++ .../upcloud/translations/zh-Hans.json | 1 + .../vesync/translations/zh-Hans.json | 5 +++ .../xiaomi_miio/translations/zh-Hans.json | 1 + .../components/zha/translations/zh-Hans.json | 19 +++++++- 57 files changed, 463 insertions(+), 28 deletions(-) create mode 100644 homeassistant/components/airly/translations/zh-Hans.json create mode 100644 homeassistant/components/arcam_fmj/translations/zh-Hans.json create mode 100644 homeassistant/components/azure_devops/translations/zh-Hans.json create mode 100644 homeassistant/components/cloudflare/translations/zh-Hans.json create mode 100644 homeassistant/components/ecobee/translations/zh-Hans.json create mode 100644 homeassistant/components/heos/translations/zh-Hans.json create mode 100644 homeassistant/components/luftdaten/translations/et.json create mode 100644 homeassistant/components/onewire/translations/zh-Hans.json create mode 100644 homeassistant/components/opentherm_gw/translations/zh-Hans.json create mode 100644 homeassistant/components/panasonic_viera/translations/zh-Hans.json create mode 100644 homeassistant/components/smappee/translations/zh-Hans.json create mode 100644 homeassistant/components/smarthab/translations/zh-Hans.json create mode 100644 homeassistant/components/solaredge/translations/zh-Hans.json create mode 100644 homeassistant/components/solarlog/translations/zh-Hans.json diff --git a/homeassistant/components/advantage_air/translations/zh-Hans.json b/homeassistant/components/advantage_air/translations/zh-Hans.json index a25ab477c70aa..db79116d5ead5 100644 --- a/homeassistant/components/advantage_air/translations/zh-Hans.json +++ b/homeassistant/components/advantage_air/translations/zh-Hans.json @@ -1,5 +1,8 @@ { "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/airly/translations/zh-Hans.json b/homeassistant/components/airly/translations/zh-Hans.json new file mode 100644 index 0000000000000..3d0d2f111b322 --- /dev/null +++ b/homeassistant/components/airly/translations/zh-Hans.json @@ -0,0 +1,17 @@ +{ + "config": { + "error": { + "auth": "API \u5bc6\u7801\u9519\u8bef" + }, + "step": { + "user": { + "data": { + "api_key": "API \u5bc6\u7801", + "latitude": "\u7eac\u5ea6", + "longitude": "\u7ecf\u5ea6", + "name": "\u540d\u79f0" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/arcam_fmj/translations/zh-Hans.json b/homeassistant/components/arcam_fmj/translations/zh-Hans.json new file mode 100644 index 0000000000000..6e842e66fabfe --- /dev/null +++ b/homeassistant/components/arcam_fmj/translations/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/axis/translations/zh-Hans.json b/homeassistant/components/axis/translations/zh-Hans.json index f7f6c8259ced1..32d738d838dcf 100644 --- a/homeassistant/components/axis/translations/zh-Hans.json +++ b/homeassistant/components/axis/translations/zh-Hans.json @@ -1,5 +1,9 @@ { "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/azure_devops/translations/zh-Hans.json b/homeassistant/components/azure_devops/translations/zh-Hans.json new file mode 100644 index 0000000000000..b0c629646e289 --- /dev/null +++ b/homeassistant/components/azure_devops/translations/zh-Hans.json @@ -0,0 +1,8 @@ +{ + "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/binary_sensor/translations/zh-Hans.json b/homeassistant/components/binary_sensor/translations/zh-Hans.json index b13a3622aca82..fe16bd685ca15 100644 --- a/homeassistant/components/binary_sensor/translations/zh-Hans.json +++ b/homeassistant/components/binary_sensor/translations/zh-Hans.json @@ -25,11 +25,13 @@ "is_not_locked": "{entity_name} \u5df2\u89e3\u9501", "is_not_moist": "{entity_name} \u5e72\u71e5", "is_not_moving": "{entity_name} \u9759\u6b62", + "is_not_occupied": "{entity_name}\u6ca1\u6709\u4eba", "is_not_open": "{entity_name} \u5df2\u5173\u95ed", "is_not_plugged_in": "{entity_name} \u672a\u63d2\u5165", "is_not_powered": "{entity_name} \u672a\u901a\u7535", "is_not_present": "{entity_name} \u4e0d\u5728\u5bb6", "is_not_unsafe": "{entity_name} \u5b89\u5168", + "is_occupied": "{entity_name}\u6709\u4eba", "is_off": "{entity_name} \u5df2\u5173\u95ed", "is_on": "{entity_name} \u5df2\u5f00\u542f", "is_open": "{entity_name} \u5df2\u6253\u5f00", @@ -49,8 +51,12 @@ "gas": "{entity_name} \u5f00\u59cb\u68c0\u6d4b\u5230\u71c3\u6c14\u6cc4\u6f0f", "hot": "{entity_name} \u53d8\u70ed", "light": "{entity_name} \u5f00\u59cb\u68c0\u6d4b\u5230\u5149\u7ebf", + "locked": "{entity_name}\u5df2\u4e0a\u9501", "motion": "{entity_name} \u68c0\u6d4b\u5230\u6709\u4eba", + "moving": "{entity_name}\u5f00\u59cb\u79fb\u52a8", "no_motion": "{entity_name} \u672a\u68c0\u6d4b\u5230\u6709\u4eba", + "not_bat_low": "{entity_name}\u7535\u91cf\u6b63\u5e38", + "not_locked": "{entity_name}\u5df2\u89e3\u9501", "not_opened": "{entity_name}\u5df2\u5173\u95ed", "turned_off": "{entity_name} \u88ab\u5173\u95ed", "turned_on": "{entity_name} \u88ab\u6253\u5f00" diff --git a/homeassistant/components/braviatv/translations/zh-Hans.json b/homeassistant/components/braviatv/translations/zh-Hans.json index c60c3f800efb1..c839a27161471 100644 --- a/homeassistant/components/braviatv/translations/zh-Hans.json +++ b/homeassistant/components/braviatv/translations/zh-Hans.json @@ -1,6 +1,11 @@ { "config": { "step": { + "authorize": { + "data": { + "pin": "PIN \u7801" + } + }, "user": { "description": "\u8bbe\u7f6eSony Bravia\u7535\u89c6\u96c6\u6210\u3002\u5982\u679c\u60a8\u5728\u914d\u7f6e\u65b9\u9762\u9047\u5230\u95ee\u9898\uff0c\u8bf7\u8bbf\u95ee\uff1ahttps://www.home-assistant.io/integrations/braviatv\n\u786e\u4fdd\u7535\u89c6\u5df2\u6253\u5f00\u3002" } diff --git a/homeassistant/components/cloudflare/translations/zh-Hans.json b/homeassistant/components/cloudflare/translations/zh-Hans.json new file mode 100644 index 0000000000000..4b0a696e5fc02 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/zh-Hans.json @@ -0,0 +1,20 @@ +{ + "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" + }, + "step": { + "user": { + "data": { + "api_token": "API \u5bc6\u7801" + } + }, + "zone": { + "data": { + "zone": "\u533a\u57df" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cover/translations/zh-Hans.json b/homeassistant/components/cover/translations/zh-Hans.json index 0ff7340729843..ccc1edd42c56b 100644 --- a/homeassistant/components/cover/translations/zh-Hans.json +++ b/homeassistant/components/cover/translations/zh-Hans.json @@ -1,7 +1,9 @@ { "device_automation": { "condition_type": { - "is_closed": "{entity_name} \u5df2\u5173\u95ed" + "is_closed": "{entity_name} \u5df2\u5173\u95ed", + "is_closing": "{entity_name}\u6b63\u5728\u5173\u95ed", + "is_open": "{entity_name}\u4e3a\u5f00\u653e" }, "trigger_type": { "closed": "{entity_name}\u5df2\u5173\u95ed" diff --git a/homeassistant/components/dexcom/translations/cs.json b/homeassistant/components/dexcom/translations/cs.json index e764b10781b58..aeda0af29e221 100644 --- a/homeassistant/components/dexcom/translations/cs.json +++ b/homeassistant/components/dexcom/translations/cs.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "\u00da\u010det je ji\u017e nastaven", "already_configured_account": "\u00da\u010det je ji\u017e nastaven" }, "error": { diff --git a/homeassistant/components/dexcom/translations/en.json b/homeassistant/components/dexcom/translations/en.json index 92ca2d1185945..33acc0237e49d 100644 --- a/homeassistant/components/dexcom/translations/en.json +++ b/homeassistant/components/dexcom/translations/en.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "Account is already configured", "already_configured_account": "Account is already configured" }, "error": { diff --git a/homeassistant/components/dexcom/translations/et.json b/homeassistant/components/dexcom/translations/et.json index d517cab1362ec..6b42e8ddf0e29 100644 --- a/homeassistant/components/dexcom/translations/et.json +++ b/homeassistant/components/dexcom/translations/et.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "Kasutaja on juba seadistatud", "already_configured_account": "Konto on juba seadistatud" }, "error": { diff --git a/homeassistant/components/dexcom/translations/no.json b/homeassistant/components/dexcom/translations/no.json index 231c93939781b..2c4e341fea61c 100644 --- a/homeassistant/components/dexcom/translations/no.json +++ b/homeassistant/components/dexcom/translations/no.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "Kontoen er allerede konfigurert", "already_configured_account": "Kontoen er allerede konfigurert" }, "error": { diff --git a/homeassistant/components/dexcom/translations/ru.json b/homeassistant/components/dexcom/translations/ru.json index 69b79638100ef..14f91d6c0cf2d 100644 --- a/homeassistant/components/dexcom/translations/ru.json +++ b/homeassistant/components/dexcom/translations/ru.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "\u042d\u0442\u0430 \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant.", "already_configured_account": "\u042d\u0442\u0430 \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant." }, "error": { diff --git a/homeassistant/components/dexcom/translations/zh-Hant.json b/homeassistant/components/dexcom/translations/zh-Hant.json index 656e082f7c4a0..607b2508731ff 100644 --- a/homeassistant/components/dexcom/translations/zh-Hant.json +++ b/homeassistant/components/dexcom/translations/zh-Hant.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "already_configured_account": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "error": { diff --git a/homeassistant/components/ecobee/translations/zh-Hans.json b/homeassistant/components/ecobee/translations/zh-Hans.json new file mode 100644 index 0000000000000..baf8c980cb75f --- /dev/null +++ b/homeassistant/components/ecobee/translations/zh-Hans.json @@ -0,0 +1,11 @@ +{ + "config": { + "step": { + "user": { + "data": { + "api_key": "API \u5bc6\u7801" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/fritzbox/translations/zh-Hans.json b/homeassistant/components/fritzbox/translations/zh-Hans.json index 183c748b2d2ac..863264194abb9 100644 --- a/homeassistant/components/fritzbox/translations/zh-Hans.json +++ b/homeassistant/components/fritzbox/translations/zh-Hans.json @@ -1,7 +1,8 @@ { "config": { "error": { - "auth_failed": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef" + "auth_failed": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef", + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" }, "step": { "confirm": { diff --git a/homeassistant/components/glances/translations/zh-Hans.json b/homeassistant/components/glances/translations/zh-Hans.json index a5f4ff11f09ef..22cb299567299 100644 --- a/homeassistant/components/glances/translations/zh-Hans.json +++ b/homeassistant/components/glances/translations/zh-Hans.json @@ -1,8 +1,13 @@ { "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + }, "step": { "user": { "data": { + "name": "\u540d\u79f0", + "password": "\u5bc6\u7801", "username": "\u7528\u6237\u540d" } } diff --git a/homeassistant/components/heos/translations/zh-Hans.json b/homeassistant/components/heos/translations/zh-Hans.json new file mode 100644 index 0000000000000..2941dfd938301 --- /dev/null +++ b/homeassistant/components/heos/translations/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/homekit/translations/cs.json b/homeassistant/components/homekit/translations/cs.json index d0bb01c988771..04da96947743c 100644 --- a/homeassistant/components/homekit/translations/cs.json +++ b/homeassistant/components/homekit/translations/cs.json @@ -43,6 +43,7 @@ "entities": "Entity", "mode": "Re\u017eim" }, + "description": "Vyberte entity, kter\u00e9 maj\u00ed b\u00fdt vystaveny. V re\u017eimu P\u0159\u00edslu\u0161enstv\u00ed je vystavena pouze jedna entita. V re\u017eimu Zahrnut\u00ed p\u0159emost\u011bn\u00ed budou vystaveny v\u0161echny entity v dom\u00e9n\u011b, pokud nebudou vybr\u00e1ny konkr\u00e9tn\u00ed entity. V re\u017eimu Vylou\u010den\u00ed p\u0159emost\u011bn\u00ed budou vystaveny v\u0161echny entity v dom\u00e9n\u011b krom\u011b vylou\u010den\u00fdch entit.", "title": "Vyberte entity, kter\u00e9 chcete vystavit" }, "init": { diff --git a/homeassistant/components/iaqualink/translations/zh-Hans.json b/homeassistant/components/iaqualink/translations/zh-Hans.json index d13c8a6b46a05..b3f84e17b00c6 100644 --- a/homeassistant/components/iaqualink/translations/zh-Hans.json +++ b/homeassistant/components/iaqualink/translations/zh-Hans.json @@ -1,10 +1,14 @@ { "config": { "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", "connection_failure": "\u65e0\u6cd5\u8fde\u63a5\u5230iAqualink\u3002\u68c0\u67e5\u60a8\u7684\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002" }, "step": { "user": { + "data": { + "password": "\u5bc6\u7801" + }, "description": "\u8bf7\u8f93\u5165\u60a8\u7684iAqualink\u5e10\u6237\u7684\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002" } } diff --git a/homeassistant/components/life360/translations/cs.json b/homeassistant/components/life360/translations/cs.json index f4b2073e09b1c..ba26971636fee 100644 --- a/homeassistant/components/life360/translations/cs.json +++ b/homeassistant/components/life360/translations/cs.json @@ -3,15 +3,18 @@ "abort": { "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje", + "unknown": "Neo\u010dek\u00e1van\u00e1 chyba", "user_already_configured": "\u00da\u010det je ji\u017e nastaven" }, "create_entry": { "default": "Chcete-li nastavit pokro\u010dil\u00e9 mo\u017enosti, pod\u00edvejte se do [dokumentace Life360]({docs_url})." }, "error": { + "already_configured": "\u00da\u010det je ji\u017e nastaven", "invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed", "invalid_credentials": "Neplatn\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje", "invalid_username": "Neplatn\u00e9 u\u017eivatelsk\u00e9 jm\u00e9no", + "unknown": "Neo\u010dek\u00e1van\u00e1 chyba", "user_already_configured": "\u00da\u010det je ji\u017e nastaven" }, "step": { diff --git a/homeassistant/components/life360/translations/en.json b/homeassistant/components/life360/translations/en.json index 1d7b80db4c970..55eb65fb0f738 100644 --- a/homeassistant/components/life360/translations/en.json +++ b/homeassistant/components/life360/translations/en.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "Invalid authentication", "invalid_credentials": "Invalid credentials", + "unknown": "Unexpected error", "user_already_configured": "Account is already configured" }, "create_entry": { "default": "To set advanced options, see [Life360 documentation]({docs_url})." }, "error": { + "already_configured": "Account is already configured", "invalid_auth": "Invalid authentication", "invalid_credentials": "Invalid credentials", "invalid_username": "Invalid username", "unexpected": "Unexpected error communicating with Life360 server", + "unknown": "Unexpected error", "user_already_configured": "Account is already configured" }, "step": { diff --git a/homeassistant/components/life360/translations/et.json b/homeassistant/components/life360/translations/et.json index b621ef129d417..82a541a8f3f00 100644 --- a/homeassistant/components/life360/translations/et.json +++ b/homeassistant/components/life360/translations/et.json @@ -2,12 +2,15 @@ "config": { "abort": { "invalid_auth": "Tuvastamise viga", + "unknown": "Ootamatu t\u00f5rge", "user_already_configured": "Konto on juba seadistatud" }, "error": { + "already_configured": "Kasutaja on juba seadistatud", "invalid_auth": "Tuvastamise viga", "invalid_username": "Vale kasutajanimi", "unexpected": "Ootamatu t\u00f5rge Life360 serveriga suhtlemisel", + "unknown": "Ootamatu t\u00f5rge", "user_already_configured": "Konto on juba seadistatud" }, "step": { diff --git a/homeassistant/components/life360/translations/no.json b/homeassistant/components/life360/translations/no.json index cabf752c48dd4..7c97a83beee52 100644 --- a/homeassistant/components/life360/translations/no.json +++ b/homeassistant/components/life360/translations/no.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "Ugyldig godkjenning", "invalid_credentials": "Ugyldige innloggingsopplysninger", + "unknown": "Uventet feil", "user_already_configured": "Kontoen er allerede konfigurert" }, "create_entry": { "default": "For \u00e5 angi avanserte alternativer, se [Life360 dokumentasjon]({docs_url})." }, "error": { + "already_configured": "Kontoen er allerede konfigurert", "invalid_auth": "Ugyldig godkjenning", "invalid_credentials": "Ugyldige innloggingsopplysninger", "invalid_username": "Ugyldig brukernavn", "unexpected": "Uventet feil under kommunikasjon med Life360-servern", + "unknown": "Uventet feil", "user_already_configured": "Kontoen er allerede konfigurert" }, "step": { diff --git a/homeassistant/components/life360/translations/ru.json b/homeassistant/components/life360/translations/ru.json index f71fce78a8565..d82ac2e2899a5 100644 --- a/homeassistant/components/life360/translations/ru.json +++ b/homeassistant/components/life360/translations/ru.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "invalid_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.", + "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", "user_already_configured": "\u042d\u0442\u0430 \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant." }, "create_entry": { "default": "\u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438]({docs_url}) \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438." }, "error": { + "already_configured": "\u042d\u0442\u0430 \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant.", "invalid_auth": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f.", "invalid_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.", "invalid_username": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d.", "unexpected": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c Life360.", + "unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430.", "user_already_configured": "\u042d\u0442\u0430 \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant." }, "step": { diff --git a/homeassistant/components/lock/translations/zh-Hans.json b/homeassistant/components/lock/translations/zh-Hans.json index 07ab36a2d4ddf..4999c52f8e00c 100644 --- a/homeassistant/components/lock/translations/zh-Hans.json +++ b/homeassistant/components/lock/translations/zh-Hans.json @@ -1,5 +1,14 @@ { "device_automation": { + "action_type": { + "lock": "\u4e0a\u9501{entity_name}", + "open": "\u5f00\u542f{entity_name}", + "unlock": "\u89e3\u9501{entity_name}" + }, + "condition_type": { + "is_locked": "{entity_name}\u5df2\u4e0a\u9501", + "is_unlocked": "{entity_name}\u5df2\u89e3\u9501" + }, "trigger_type": { "locked": "{entity_name} \u88ab\u9501\u5b9a", "unlocked": "{entity_name} \u88ab\u89e3\u9501" diff --git a/homeassistant/components/logi_circle/translations/zh-Hans.json b/homeassistant/components/logi_circle/translations/zh-Hans.json index 2d9770e0a8007..d8d1e7b72d050 100644 --- a/homeassistant/components/logi_circle/translations/zh-Hans.json +++ b/homeassistant/components/logi_circle/translations/zh-Hans.json @@ -1,5 +1,8 @@ { "config": { + "error": { + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/luftdaten/translations/et.json b/homeassistant/components/luftdaten/translations/et.json new file mode 100644 index 0000000000000..2d480b3536a6d --- /dev/null +++ b/homeassistant/components/luftdaten/translations/et.json @@ -0,0 +1,8 @@ +{ + "config": { + "error": { + "already_configured": "Teenus on juba seadistatud", + "cannot_connect": "\u00dchendamine nurjus" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/luftdaten/translations/zh-Hans.json b/homeassistant/components/luftdaten/translations/zh-Hans.json index 02024b18494f7..2422f01b9885f 100644 --- a/homeassistant/components/luftdaten/translations/zh-Hans.json +++ b/homeassistant/components/luftdaten/translations/zh-Hans.json @@ -1,6 +1,7 @@ { "config": { "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", "communication_error": "\u65e0\u6cd5\u4e0e Luftdaten API \u901a\u4fe1", "invalid_sensor": "\u4f20\u611f\u5668\u4e0d\u53ef\u7528\u6216\u65e0\u6548", "sensor_exists": "\u4f20\u611f\u5668\u5df2\u6ce8\u518c" diff --git a/homeassistant/components/mill/translations/zh-Hans.json b/homeassistant/components/mill/translations/zh-Hans.json index a5f4ff11f09ef..79079e6c40868 100644 --- a/homeassistant/components/mill/translations/zh-Hans.json +++ b/homeassistant/components/mill/translations/zh-Hans.json @@ -1,5 +1,8 @@ { "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/neato/translations/zh-Hans.json b/homeassistant/components/neato/translations/zh-Hans.json index a5f4ff11f09ef..b0b26b0226108 100644 --- a/homeassistant/components/neato/translations/zh-Hans.json +++ b/homeassistant/components/neato/translations/zh-Hans.json @@ -3,6 +3,7 @@ "step": { "user": { "data": { + "password": "\u5bc6\u7801", "username": "\u7528\u6237\u540d" } } diff --git a/homeassistant/components/nest/translations/et.json b/homeassistant/components/nest/translations/et.json index c0b61fb494865..e8f1e775b95eb 100644 --- a/homeassistant/components/nest/translations/et.json +++ b/homeassistant/components/nest/translations/et.json @@ -6,6 +6,7 @@ "authorize_url_timeout": "Tuvastamise URL- i loomise ajal\u00f5pp.", "missing_configuration": "Osis pole seadistatud. Vaata dokumentatsiooni.", "no_flows": "Enne tuvastamist pead Nesti konfigureerima. [Palun lugege juhiseid] (https://www.home-assistant.io/components/nest/).", + "no_url_available": "URL pole saadaval. Selle t\u00f5rke kohta teabe saamiseks vaata [spikrijaotis]({docs_url})", "single_instance_allowed": "Juba seadistatud. V\u00f5imalik on ainult \u00fcks seadistamine." }, "create_entry": { diff --git a/homeassistant/components/onewire/translations/zh-Hans.json b/homeassistant/components/onewire/translations/zh-Hans.json new file mode 100644 index 0000000000000..2941dfd938301 --- /dev/null +++ b/homeassistant/components/onewire/translations/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onvif/translations/zh-Hans.json b/homeassistant/components/onvif/translations/zh-Hans.json index b6ad5c30a77bc..0a0b6db3d383c 100644 --- a/homeassistant/components/onvif/translations/zh-Hans.json +++ b/homeassistant/components/onvif/translations/zh-Hans.json @@ -1,5 +1,8 @@ { "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + }, "step": { "auth": { "data": { diff --git a/homeassistant/components/opentherm_gw/translations/et.json b/homeassistant/components/opentherm_gw/translations/et.json index d20d18329613b..d831644c11642 100644 --- a/homeassistant/components/opentherm_gw/translations/et.json +++ b/homeassistant/components/opentherm_gw/translations/et.json @@ -1,7 +1,8 @@ { "config": { "error": { - "already_configured": "L\u00fc\u00fcs on juba m\u00e4\u00e4ratud" + "already_configured": "L\u00fc\u00fcs on juba m\u00e4\u00e4ratud", + "cannot_connect": "\u00dchendamine nurjus" } } } \ No newline at end of file diff --git a/homeassistant/components/opentherm_gw/translations/zh-Hans.json b/homeassistant/components/opentherm_gw/translations/zh-Hans.json new file mode 100644 index 0000000000000..7751b1f2f7d50 --- /dev/null +++ b/homeassistant/components/opentherm_gw/translations/zh-Hans.json @@ -0,0 +1,14 @@ +{ + "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + }, + "step": { + "init": { + "data": { + "name": "\u540d\u79f0" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/panasonic_viera/translations/zh-Hans.json b/homeassistant/components/panasonic_viera/translations/zh-Hans.json new file mode 100644 index 0000000000000..254f6df932756 --- /dev/null +++ b/homeassistant/components/panasonic_viera/translations/zh-Hans.json @@ -0,0 +1,10 @@ +{ + "config": { + "abort": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + }, + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/plex/translations/zh-Hans.json b/homeassistant/components/plex/translations/zh-Hans.json index 614f83e3cc0f0..9cc02584789bc 100644 --- a/homeassistant/components/plex/translations/zh-Hans.json +++ b/homeassistant/components/plex/translations/zh-Hans.json @@ -1,4 +1,14 @@ { + "config": { + "step": { + "select_server": { + "data": { + "server": "\u670d\u52a1\u5668" + }, + "title": "\u9009\u62e9 Plex \u670d\u52a1\u5668" + } + } + }, "options": { "step": { "plex_mp_settings": { diff --git a/homeassistant/components/rainmachine/translations/en.json b/homeassistant/components/rainmachine/translations/en.json index f65463626e46f..bde24d51298e0 100644 --- a/homeassistant/components/rainmachine/translations/en.json +++ b/homeassistant/components/rainmachine/translations/en.json @@ -4,7 +4,9 @@ "already_configured": "Device is already configured" }, "error": { - "invalid_auth": "Invalid authentication" + "identifier_exists": "Account is already configured", + "invalid_auth": "Invalid authentication", + "invalid_credentials": "Invalid credentials" }, "step": { "user": { diff --git a/homeassistant/components/ruckus_unleashed/translations/zh-Hans.json b/homeassistant/components/ruckus_unleashed/translations/zh-Hans.json index b6a239d7b99a5..d5cc919a9ac65 100644 --- a/homeassistant/components/ruckus_unleashed/translations/zh-Hans.json +++ b/homeassistant/components/ruckus_unleashed/translations/zh-Hans.json @@ -1,7 +1,8 @@ { "config": { "error": { - "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" }, "step": { "user": { diff --git a/homeassistant/components/smappee/translations/zh-Hans.json b/homeassistant/components/smappee/translations/zh-Hans.json new file mode 100644 index 0000000000000..6e842e66fabfe --- /dev/null +++ b/homeassistant/components/smappee/translations/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/smarthab/translations/zh-Hans.json b/homeassistant/components/smarthab/translations/zh-Hans.json new file mode 100644 index 0000000000000..f339adebd8682 --- /dev/null +++ b/homeassistant/components/smarthab/translations/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/solaredge/translations/zh-Hans.json b/homeassistant/components/solaredge/translations/zh-Hans.json new file mode 100644 index 0000000000000..baf8c980cb75f --- /dev/null +++ b/homeassistant/components/solaredge/translations/zh-Hans.json @@ -0,0 +1,11 @@ +{ + "config": { + "step": { + "user": { + "data": { + "api_key": "API \u5bc6\u7801" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/solarlog/translations/zh-Hans.json b/homeassistant/components/solarlog/translations/zh-Hans.json new file mode 100644 index 0000000000000..2941dfd938301 --- /dev/null +++ b/homeassistant/components/solarlog/translations/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/tellduslive/translations/zh-Hans.json b/homeassistant/components/tellduslive/translations/zh-Hans.json index c1d4a0c54f52a..ccd58b51751ff 100644 --- a/homeassistant/components/tellduslive/translations/zh-Hans.json +++ b/homeassistant/components/tellduslive/translations/zh-Hans.json @@ -6,7 +6,8 @@ "unknown": "\u53d1\u751f\u672a\u77e5\u7684\u9519\u8bef" }, "error": { - "auth_error": "\u53cc\u91cd\u8ba4\u8bc1\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5\u3002" + "auth_error": "\u53cc\u91cd\u8ba4\u8bc1\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5\u3002", + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548" }, "step": { "auth": { diff --git a/homeassistant/components/transmission/translations/zh-Hans.json b/homeassistant/components/transmission/translations/zh-Hans.json index feebc8ea8a278..98d88a0961fa7 100644 --- a/homeassistant/components/transmission/translations/zh-Hans.json +++ b/homeassistant/components/transmission/translations/zh-Hans.json @@ -2,6 +2,13 @@ "config": { "error": { "wrong_credentials": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef" + }, + "step": { + "user": { + "data": { + "password": "\u5bc6\u7801" + } + } } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/cs.json b/homeassistant/components/tuya/translations/cs.json index 88bfb2e732208..2650e3aeeeb8c 100644 --- a/homeassistant/components/tuya/translations/cs.json +++ b/homeassistant/components/tuya/translations/cs.json @@ -24,5 +24,38 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "V\u00edce vybran\u00fdch za\u0159\u00edzen\u00ed k nastaven\u00ed mus\u00ed b\u00fdt stejn\u00e9ho typu", + "dev_not_config": "Typ za\u0159\u00edzen\u00ed nelze nastavit", + "dev_not_found": "Za\u0159\u00edzen\u00ed nenalezeno" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Rozsah jasu pou\u017e\u00edvan\u00fd za\u0159\u00edzen\u00edm", + "ext_temp_sensor": "Senzor aktu\u00e1ln\u00ed teploty", + "max_kelvin": "Maxim\u00e1ln\u00ed podporovan\u00e1 teplota barev v kelvinech", + "max_temp": "Maxim\u00e1ln\u00ed c\u00edlov\u00e1 teplota (pou\u017eijte min a max = 0 jako v\u00fdchoz\u00ed)", + "min_kelvin": "Maxim\u00e1ln\u00ed podporovan\u00e1 teplota barev v kelvinech", + "min_temp": "Minim\u00e1ln\u00ed c\u00edlov\u00e1 teplota (pou\u017eijte min a max = 0 jako v\u00fdchoz\u00ed)", + "support_color": "Vynutit podporu barev", + "tuya_max_coltemp": "Maxim\u00e1ln\u00ed teplota barev nahl\u00e1\u0161en\u00e1 za\u0159\u00edzen\u00edm", + "unit_of_measurement": "Jednotka teploty pou\u017e\u00edvan\u00e1 za\u0159\u00edzen\u00edm" + }, + "title": "Nastavte za\u0159\u00edzen\u00ed Tuya" + }, + "init": { + "data": { + "discovery_interval": "Interval objevov\u00e1n\u00ed za\u0159\u00edzen\u00ed v sekund\u00e1ch", + "list_devices": "Vyberte za\u0159\u00edzen\u00ed, kter\u00e1 chcete nastavit, nebo ponechte pr\u00e1zdn\u00e9, abyste konfiguraci ulo\u017eili", + "query_device": "Vyberte za\u0159\u00edzen\u00ed, kter\u00e9 bude pou\u017e\u00edvat metodu dotaz\u016f pro rychlej\u0161\u00ed aktualizaci stavu", + "query_interval": "Interval dotazov\u00e1n\u00ed za\u0159\u00edzen\u00ed v sekund\u00e1ch" + }, + "description": "Nenastavujte intervalu dotazov\u00e1n\u00ed p\u0159\u00edli\u0161 n\u00edzk\u00e9 hodnoty, jinak se dotazov\u00e1n\u00ed nezda\u0159\u00ed a bude generovat chybov\u00e9 zpr\u00e1vy do logu", + "title": "Nastavte mo\u017enosti Tuya" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/en.json b/homeassistant/components/tuya/translations/en.json index 9bf1744edd899..5cc09d7e1e39c 100644 --- a/homeassistant/components/tuya/translations/en.json +++ b/homeassistant/components/tuya/translations/en.json @@ -1,11 +1,14 @@ { "config": { "abort": { + "auth_failed": "Invalid authentication", "cannot_connect": "Failed to connect", + "conn_error": "Failed to connect", "invalid_auth": "Invalid authentication", "single_instance_allowed": "Already configured. Only a single configuration possible." }, "error": { + "auth_failed": "Invalid authentication", "invalid_auth": "Invalid authentication" }, "flow_title": "Tuya configuration", @@ -29,32 +32,32 @@ "dev_not_found": "Device not found" }, "step": { - "init": { - "title": "Configure Tuya Options", - "description": "Do not set pollings interval values too low or the calls will fail generating error message in the log", - "data": { - "discovery_interval": "Discovery device polling interval in seconds", - "query_device": "Select device that will use query method for faster status update", - "query_interval": "Query device polling interval in seconds", - "list_devices": "Select the devices to configure or leave empty to save configuration" - } - }, "device": { - "title": "Configure Tuya Device", - "description": "Configure options to adjust displayed information for {device_type} device `{device_name}`", "data": { - "support_color": "Force color support", "brightness_range_mode": "Brightness range used by device", - "min_kelvin": "Min color temperature supported in kelvin", - "max_kelvin": "Max color temperature supported in kelvin", - "tuya_max_coltemp": "Max color temperature reported by device", - "unit_of_measurement": "Temperature unit used by device", - "temp_divider": "Temperature values divider (0 = use default)", "curr_temp_divider": "Current Temperature value divider (0 = use default)", - "min_temp": "Min target temperature (use min and max = 0 for default)", + "ext_temp_sensor": "Sensor for current temperature", + "max_kelvin": "Max color temperature supported in kelvin", "max_temp": "Max target temperature (use min and max = 0 for default)", - "ext_temp_sensor": "Sensor for current temperature" - } + "min_kelvin": "Min color temperature supported in kelvin", + "min_temp": "Min target temperature (use min and max = 0 for default)", + "support_color": "Force color support", + "temp_divider": "Temperature values divider (0 = use default)", + "tuya_max_coltemp": "Max color temperature reported by device", + "unit_of_measurement": "Temperature unit used by device" + }, + "description": "Configure options to adjust displayed information for {device_type} device `{device_name}`", + "title": "Configure Tuya Device" + }, + "init": { + "data": { + "discovery_interval": "Discovery device polling interval in seconds", + "list_devices": "Select the devices to configure or leave empty to save configuration", + "query_device": "Select device that will use query method for faster status update", + "query_interval": "Query device polling interval in seconds" + }, + "description": "Do not set pollings interval values too low or the calls will fail generating error message in the log", + "title": "Configure Tuya Options" } } } diff --git a/homeassistant/components/tuya/translations/et.json b/homeassistant/components/tuya/translations/et.json index c7323e3c1890b..b99cfd93d6ebb 100644 --- a/homeassistant/components/tuya/translations/et.json +++ b/homeassistant/components/tuya/translations/et.json @@ -24,5 +24,36 @@ "title": "" } } + }, + "options": { + "error": { + "dev_multi_type": "Mitu h\u00e4\u00e4lestatavat seadet peavad olema sama t\u00fc\u00fcpi", + "dev_not_config": "Seda t\u00fc\u00fcpi seade pole seadistatav", + "dev_not_found": "Seadet ei leitud" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Seadme kasutatav heledusvahemik", + "curr_temp_divider": "Praeguse temperatuuri v\u00e4\u00e4rtuse eraldaja (0 = kasuta vaikev\u00e4\u00e4rtust)", + "ext_temp_sensor": "Praeguse temperatuuri andur", + "max_kelvin": "Maksimaalne v\u00f5imalik v\u00e4rvitemperatuur (Kelvinites)", + "max_temp": "Maksimaalne sihttemperatuur (vaikimisi kasuta min ja max = 0)", + "min_kelvin": "Minimaalne v\u00f5imalik v\u00e4rvitemperatuur (Kelvinites)", + "min_temp": "Minimaalne sihttemperatuur (vaikimisi kasuta min ja max = 0)", + "support_color": "Luba v\u00e4rvuse juhtimine", + "temp_divider": "Temperatuuri v\u00e4\u00e4rtuse eraldaja (0 = kasuta vaikev\u00e4\u00e4rtust)", + "unit_of_measurement": "Seadme temperatuuri\u00fchik" + }, + "title": "H\u00e4\u00e4lesta Tuya seade" + }, + "init": { + "data": { + "discovery_interval": "Seadme leidmisp\u00e4ringute intervall (sekundites)", + "query_interval": "P\u00e4ringute intervall (sekundites)" + }, + "title": "Tuya suvandite seadistamine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/no.json b/homeassistant/components/tuya/translations/no.json index b2245361e9cb5..ddf69be8af280 100644 --- a/homeassistant/components/tuya/translations/no.json +++ b/homeassistant/components/tuya/translations/no.json @@ -24,5 +24,41 @@ "title": "" } } + }, + "options": { + "error": { + "dev_multi_type": "Flere valgte enheter som skal konfigureres, m\u00e5 v\u00e6re av samme type", + "dev_not_config": "Enhetstype kan ikke konfigureres", + "dev_not_found": "Finner ikke enheten" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Lysstyrkeomr\u00e5de som brukes av enheten", + "curr_temp_divider": "N\u00e5v\u00e6rende temperaturverdi (0 = bruk standard)", + "ext_temp_sensor": "Sensor for gjeldende temperatur", + "max_kelvin": "Maks fargetemperatur st\u00f8ttet i kelvin", + "max_temp": "Maks m\u00e5ltemperatur (bruk min og maks = 0 for standard)", + "min_kelvin": "Min fargetemperatur st\u00f8ttet i kelvin", + "min_temp": "Min m\u00e5ltemperatur (bruk min og maks = 0 for standard)", + "support_color": "Tving fargest\u00f8tte", + "temp_divider": "Deler temperaturverdier (0 = bruk standard)", + "tuya_max_coltemp": "Maks fargetemperatur rapportert av enheten", + "unit_of_measurement": "Temperaturenhet som brukes av enheten" + }, + "description": "Konfigurer alternativer for \u00e5 justere vist informasjon for {device_type} device ` {device_name} `", + "title": "Konfigurere Tuya-enhet" + }, + "init": { + "data": { + "discovery_interval": "Avsp\u00f8rringsintervall for discovery-enheten i l\u00f8pet av sekunder", + "list_devices": "Velg enhetene du vil konfigurere, eller la de v\u00e6re tomme for \u00e5 lagre konfigurasjonen", + "query_device": "Velg enhet som skal bruke sp\u00f8rringsmetode for raskere statusoppdatering", + "query_interval": "Sp\u00f8rringsintervall for intervall i sekunder" + }, + "description": "Ikke angi pollingsintervallverdiene for lave, ellers vil ikke anropene generere feilmelding i loggen", + "title": "Konfigurer Tuya-alternativer" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/ru.json b/homeassistant/components/tuya/translations/ru.json index bdb3ad91c358e..58f8c44084549 100644 --- a/homeassistant/components/tuya/translations/ru.json +++ b/homeassistant/components/tuya/translations/ru.json @@ -24,5 +24,41 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430.", + "dev_not_config": "\u0422\u0438\u043f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f.", + "dev_not_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e." + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "\u0414\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u044f\u0440\u043a\u043e\u0441\u0442\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c", + "curr_temp_divider": "\u0414\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u044b (0 = \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e)", + "ext_temp_sensor": "\u0421\u0435\u043d\u0441\u043e\u0440 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u044b", + "max_kelvin": "\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0430\u044f \u0446\u0432\u0435\u0442\u043e\u0432\u0430\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 (\u0432 \u043a\u0435\u043b\u044c\u0432\u0438\u043d\u0430\u0445)", + "max_temp": "\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0446\u0435\u043b\u0435\u0432\u0430\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 min \u0438 max = 0)", + "min_kelvin": "\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0430\u044f \u0446\u0432\u0435\u0442\u043e\u0432\u0430\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 (\u0432 \u043a\u0435\u043b\u044c\u0432\u0438\u043d\u0430\u0445)", + "min_temp": "\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0446\u0435\u043b\u0435\u0432\u0430\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 min \u0438 max = 0)", + "support_color": "\u041f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0446\u0432\u0435\u0442\u0430", + "temp_divider": "\u0414\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u044b (0 = \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e)", + "tuya_max_coltemp": "\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0446\u0432\u0435\u0442\u043e\u0432\u0430\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430, \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c\u0430\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c", + "unit_of_measurement": "\u0415\u0434\u0438\u043d\u0438\u0446\u0430 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c" + }, + "description": "\u041e\u043f\u0446\u0438\u0438 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f {device_type} \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 `{device_name}`", + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Tuya" + }, + "init": { + "data": { + "discovery_interval": "\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u043f\u0440\u043e\u0441\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 (\u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445)", + "list_devices": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u0443\u0441\u0442\u044b\u043c \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438", + "query_device": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u0443\u0441\u0430", + "query_interval": "\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u043f\u0440\u043e\u0441\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 (\u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445)" + }, + "description": "\u041d\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0439\u0442\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043d\u0438\u0437\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430 \u043e\u043f\u0440\u043e\u0441\u0430, \u0438\u043d\u0430\u0447\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435.", + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Tuya" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/zh-Hant.json b/homeassistant/components/tuya/translations/zh-Hant.json index a667ac76b15b4..591d51c78be6a 100644 --- a/homeassistant/components/tuya/translations/zh-Hant.json +++ b/homeassistant/components/tuya/translations/zh-Hant.json @@ -24,5 +24,41 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "\u591a\u91cd\u9078\u64c7\u8a2d\u5099\u4ee5\u8a2d\u5b9a\u4f7f\u7528\u76f8\u540c\u985e\u578b", + "dev_not_config": "\u8a2d\u5099\u985e\u578b\u7121\u6cd5\u8a2d\u5b9a", + "dev_not_found": "\u8a2d\u5099\u627e\u4e0d\u5230" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "\u8a2d\u5099\u6240\u4f7f\u7528\u4e4b\u4eae\u5ea6\u7bc4\u570d", + "curr_temp_divider": "\u76ee\u524d\u8272\u6eab\u503c\u5206\u914d\u5668\uff080 = \u4f7f\u7528\u9810\u8a2d\uff09", + "ext_temp_sensor": "\u611f\u6e2c\u5668\u76ee\u524d\u8272\u6eab", + "max_kelvin": "Kelvin \u652f\u63f4\u6700\u9ad8\u8272\u6eab", + "max_temp": "\u6700\u9ad8\u76ee\u6a19\u8272\u6eab\uff08\u4f7f\u7528\u6700\u4f4e\u8207\u6700\u9ad8 = 0 \u4f7f\u7528\u9810\u8a2d\uff09", + "min_kelvin": "Kelvin \u652f\u63f4\u6700\u4f4e\u8272\u6eab", + "min_temp": "\u6700\u4f4e\u76ee\u6a19\u8272\u6eab\uff08\u4f7f\u7528\u6700\u4f4e\u8207\u6700\u9ad8 = 0 \u4f7f\u7528\u9810\u8a2d\uff09", + "support_color": "\u5f37\u5236\u8272\u6eab\u652f\u63f4", + "temp_divider": "\u8272\u6eab\u503c\u5206\u914d\u5668\uff080 = \u4f7f\u7528\u9810\u8a2d\uff09", + "tuya_max_coltemp": "\u8a2d\u5099\u56de\u5831\u6700\u9ad8\u8272\u6eab", + "unit_of_measurement": "\u8a2d\u5099\u6240\u4f7f\u7528\u4e4b\u6eab\u5ea6\u55ae\u4f4d" + }, + "description": "\u8a2d\u5b9a\u9078\u9805\u4ee5\u8abf\u6574 {device_type} \u8a2d\u5099 `{device_name}` \u986f\u793a\u8cc7\u8a0a", + "title": "\u8a2d\u5b9a Tuya \u8a2d\u5099" + }, + "init": { + "data": { + "discovery_interval": "\u63a2\u7d22\u8a2d\u5099\u66f4\u65b0\u79d2\u9593\u8ddd", + "list_devices": "\u9078\u64c7\u8a2d\u5099\u4ee5\u8a2d\u5b9a\u3001\u6216\u4fdd\u6301\u7a7a\u767d\u4ee5\u5132\u5b58\u8a2d\u5b9a", + "query_device": "\u9078\u64c7\u8a2d\u5099\u5c07\u4f7f\u7528\u67e5\u8a62\u65b9\u5f0f\u4ee5\u7372\u5f97\u66f4\u5feb\u7684\u72c0\u614b\u66f4\u65b0", + "query_interval": "\u67e5\u8a62\u8a2d\u5099\u66f4\u65b0\u79d2\u9593\u8ddd" + }, + "description": "\u66f4\u65b0\u9593\u8ddd\u4e0d\u8981\u8a2d\u5b9a\u7684\u904e\u4f4e\u3001\u53ef\u80fd\u6703\u5c0e\u81f4\u65bc\u65e5\u8a8c\u4e2d\u7522\u751f\u932f\u8aa4\u8a0a\u606f", + "title": "\u8a2d\u5b9a Tuya \u9078\u9805" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/upcloud/translations/zh-Hans.json b/homeassistant/components/upcloud/translations/zh-Hans.json index 83be90bc29211..bcdb3665eea96 100644 --- a/homeassistant/components/upcloud/translations/zh-Hans.json +++ b/homeassistant/components/upcloud/translations/zh-Hans.json @@ -1,6 +1,7 @@ { "config": { "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", "invalid_auth": "\u65e0\u6548\u7684\u8eab\u4efd\u9a8c\u8bc1" }, "step": { diff --git a/homeassistant/components/vesync/translations/zh-Hans.json b/homeassistant/components/vesync/translations/zh-Hans.json index e256110ffa747..12f841563813c 100644 --- a/homeassistant/components/vesync/translations/zh-Hans.json +++ b/homeassistant/components/vesync/translations/zh-Hans.json @@ -4,10 +4,15 @@ "already_setup": "\u53ea\u5141\u8bb8\u4e00\u4e2aVesync\u5b9e\u4f8b" }, "error": { + "invalid_auth": "\u9a8c\u8bc1\u7801\u65e0\u6548", "invalid_login": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u65e0\u6548" }, "step": { "user": { + "data": { + "password": "\u5bc6\u7801", + "username": "\u7535\u5b50\u90ae\u4ef6" + }, "title": "\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801" } } diff --git a/homeassistant/components/xiaomi_miio/translations/zh-Hans.json b/homeassistant/components/xiaomi_miio/translations/zh-Hans.json index 9a54104116af4..049e58a80e242 100644 --- a/homeassistant/components/xiaomi_miio/translations/zh-Hans.json +++ b/homeassistant/components/xiaomi_miio/translations/zh-Hans.json @@ -5,6 +5,7 @@ "already_in_progress": "\u6b64\u5c0f\u7c73\u8bbe\u5907\u7684\u914d\u7f6e\u6d41\u7a0b\u5df2\u5728\u8fdb\u884c\u4e2d\u3002" }, "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25", "connect_error": "\u8fde\u63a5\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5", "no_device_selected": "\u672a\u9009\u62e9\u8bbe\u5907\uff0c\u8bf7\u9009\u62e9\u4e00\u4e2a\u8bbe\u5907\u3002" }, diff --git a/homeassistant/components/zha/translations/zh-Hans.json b/homeassistant/components/zha/translations/zh-Hans.json index 4df88473d0dee..a594ffe354564 100644 --- a/homeassistant/components/zha/translations/zh-Hans.json +++ b/homeassistant/components/zha/translations/zh-Hans.json @@ -13,11 +13,28 @@ } }, "device_automation": { + "action_type": { + "warn": "\u8b66\u544a" + }, "trigger_subtype": { + "both_buttons": "\u4e24\u4e2a\u6309\u94ae", + "button_1": "\u7b2c\u4e00\u4e2a\u6309\u94ae", + "button_2": "\u7b2c\u4e8c\u4e2a\u6309\u94ae", + "button_3": "\u7b2c\u4e09\u4e2a\u6309\u94ae", + "button_4": "\u7b2c\u56db\u4e2a\u6309\u94ae", + "button_5": "\u7b2c\u4e94\u4e2a\u6309\u94ae", + "button_6": "\u7b2c\u516d\u4e2a\u6309\u94ae", + "dim_down": "\u8c03\u6697", + "dim_up": "\u8c03\u4eae", + "left": "\u5de6", + "open": "\u5f00\u542f", + "right": "\u53f3", "turn_off": "\u5173\u95ed" }, "trigger_type": { - "device_offline": "\u8bbe\u5907\u79bb\u7ebf" + "device_offline": "\u8bbe\u5907\u79bb\u7ebf", + "device_tilted": "\u8bbe\u5907\u540d\u79f0", + "remote_button_short_press": "\"{subtype}\" \u6309\u94ae\u5df2\u6309\u4e0b" } } } \ No newline at end of file From 3fb091c4ea2621f424d0c166668510f1a1808985 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Wed, 28 Oct 2020 18:54:51 -0600 Subject: [PATCH 04/43] Deprecate YAML config for Flu Near You (0.119 removal) (#42535) --- .../components/flunearyou/__init__.py | 31 +------------------ .../components/flunearyou/config_flow.py | 4 --- .../components/flunearyou/test_config_flow.py | 21 +------------ 3 files changed, 2 insertions(+), 54 deletions(-) diff --git a/homeassistant/components/flunearyou/__init__.py b/homeassistant/components/flunearyou/__init__.py index 4dae0b3f7cdf6..053101f7beed2 100644 --- a/homeassistant/components/flunearyou/__init__.py +++ b/homeassistant/components/flunearyou/__init__.py @@ -4,9 +4,7 @@ from pyflunearyou import Client from pyflunearyou.errors import FluNearYouError -import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE from homeassistant.core import callback from homeassistant.helpers import aiohttp_client, config_validation as cv @@ -27,17 +25,7 @@ DEFAULT_SCAN_INTERVAL = timedelta(minutes=30) -CONFIG_SCHEMA = vol.Schema( - { - vol.Optional(DOMAIN): vol.Schema( - { - vol.Optional(CONF_LATITUDE): cv.latitude, - vol.Optional(CONF_LONGITUDE): cv.longitude, - } - ) - }, - extra=vol.ALLOW_EXTRA, -) +CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.119") @callback @@ -59,23 +47,6 @@ def async_get_api_category(sensor_type): async def async_setup(hass, config): """Set up the Flu Near You component.""" hass.data[DOMAIN] = {DATA_CLIENT: {}, DATA_LISTENER: {}} - - if DOMAIN not in config: - return True - - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={ - CONF_LATITUDE: config[DOMAIN].get(CONF_LATITUDE, hass.config.latitude), - CONF_LONGITUDE: config[DOMAIN].get( - CONF_LATITUDE, hass.config.longitude - ), - }, - ) - ) - return True diff --git a/homeassistant/components/flunearyou/config_flow.py b/homeassistant/components/flunearyou/config_flow.py index 9918858fd9328..8bdef58f7e120 100644 --- a/homeassistant/components/flunearyou/config_flow.py +++ b/homeassistant/components/flunearyou/config_flow.py @@ -30,10 +30,6 @@ def data_schema(self): } ) - async def async_step_import(self, import_config): - """Import a config entry from configuration.yaml.""" - return await self.async_step_user(import_config) - async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" if not user_input: diff --git a/tests/components/flunearyou/test_config_flow.py b/tests/components/flunearyou/test_config_flow.py index a43fb7aa52feb..3681768ccdf41 100644 --- a/tests/components/flunearyou/test_config_flow.py +++ b/tests/components/flunearyou/test_config_flow.py @@ -3,7 +3,7 @@ from homeassistant import data_entry_flow from homeassistant.components.flunearyou import DOMAIN -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.config_entries import SOURCE_USER from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE from tests.async_mock import patch @@ -50,25 +50,6 @@ async def test_show_form(hass): assert result["step_id"] == "user" -async def test_step_import(hass): - """Test that the import step works.""" - conf = {CONF_LATITUDE: "51.528308", CONF_LONGITUDE: "-0.3817765"} - - with patch( - "homeassistant.components.flunearyou.async_setup_entry", return_value=True - ), patch("pyflunearyou.cdc.CdcReport.status_by_coordinates"): - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=conf - ) - - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["title"] == "51.528308, -0.3817765" - assert result["data"] == { - CONF_LATITUDE: "51.528308", - CONF_LONGITUDE: "-0.3817765", - } - - async def test_step_user(hass): """Test that the user step works.""" conf = {CONF_LATITUDE: "51.528308", CONF_LONGITUDE: "-0.3817765"} From 2a795c039742c31a72323e382a98e89e0d1fbfa9 Mon Sep 17 00:00:00 2001 From: Jason Hunter Date: Wed, 28 Oct 2020 21:05:16 -0400 Subject: [PATCH 05/43] Add guppy3 memory profile to Profiler integration (#42435) * add guppy memory profile to profiler integration * add output path to notification * create new service for memory profile * address review comments --- homeassistant/components/profiler/__init__.py | 43 ++++++++++++++++++- .../components/profiler/manifest.json | 10 ++--- .../components/profiler/services.yaml | 6 +++ requirements_all.txt | 3 ++ requirements_test_all.txt | 3 ++ tests/components/profiler/test_init.py | 38 +++++++++++++++- 6 files changed, 94 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/profiler/__init__.py b/homeassistant/components/profiler/__init__.py index 518e448d4ecab..b4cca97e1fd6c 100644 --- a/homeassistant/components/profiler/__init__.py +++ b/homeassistant/components/profiler/__init__.py @@ -3,6 +3,7 @@ import cProfile import time +from guppy import hpy from pyprof2calltree import convert import voluptuous as vol @@ -14,6 +15,7 @@ from .const import DOMAIN SERVICE_START = "start" +SERVICE_MEMORY = "memory" CONF_SECONDS = "seconds" @@ -31,6 +33,10 @@ async def _async_run_profile(call: ServiceCall): async with lock: await _async_generate_profile(hass, call) + async def _async_run_memory_profile(call: ServiceCall): + async with lock: + await _async_generate_memory_profile(hass, call) + async_register_admin_service( hass, DOMAIN, @@ -41,6 +47,16 @@ async def _async_run_profile(call: ServiceCall): ), ) + async_register_admin_service( + hass, + DOMAIN, + SERVICE_MEMORY, + _async_run_memory_profile, + schema=vol.Schema( + {vol.Optional(CONF_SECONDS, default=60.0): vol.Coerce(float)} + ), + ) + return True @@ -53,7 +69,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): async def _async_generate_profile(hass: HomeAssistant, call: ServiceCall): start_time = int(time.time() * 1000000) hass.components.persistent_notification.async_create( - "The profile started. This notification will be updated when it is complete.", + "The profile has started. This notification will be updated when it is complete.", title="Profile Started", notification_id=f"profiler_{start_time}", ) @@ -74,7 +90,32 @@ async def _async_generate_profile(hass: HomeAssistant, call: ServiceCall): ) +async def _async_generate_memory_profile(hass: HomeAssistant, call: ServiceCall): + start_time = int(time.time() * 1000000) + hass.components.persistent_notification.async_create( + "The memory profile has started. This notification will be updated when it is complete.", + title="Profile Started", + notification_id=f"memory_profiler_{start_time}", + ) + heap_profiler = hpy() + heap_profiler.setref() + await asyncio.sleep(float(call.data[CONF_SECONDS])) + heap = heap_profiler.heap() + + heap_path = hass.config.path(f"heap_profile.{start_time}.hpy") + await hass.async_add_executor_job(_write_memory_profile, heap, heap_path) + hass.components.persistent_notification.async_create( + f"Wrote heapy memory profile to {heap_path}", + title="Profile Complete", + notification_id=f"memory_profiler_{start_time}", + ) + + def _write_profile(profiler, cprofile_path, callgrind_path): profiler.create_stats() profiler.dump_stats(cprofile_path) convert(profiler.getstats(), callgrind_path) + + +def _write_memory_profile(heap, heap_path): + heap.byrcs.dump(heap_path) diff --git a/homeassistant/components/profiler/manifest.json b/homeassistant/components/profiler/manifest.json index e740a083c7709..c1be2025fb6c3 100644 --- a/homeassistant/components/profiler/manifest.json +++ b/homeassistant/components/profiler/manifest.json @@ -2,12 +2,8 @@ "domain": "profiler", "name": "Profiler", "documentation": "https://www.home-assistant.io/integrations/profiler", - "requirements": [ - "pyprof2calltree==1.4.5" - ], - "codeowners": [ - "@bdraco" - ], + "requirements": ["pyprof2calltree==1.4.5", "guppy3==3.1.0"], + "codeowners": ["@bdraco"], "quality_scale": "internal", "config_flow": true -} \ No newline at end of file +} diff --git a/homeassistant/components/profiler/services.yaml b/homeassistant/components/profiler/services.yaml index 7033e988fc567..e1c1db89688f1 100644 --- a/homeassistant/components/profiler/services.yaml +++ b/homeassistant/components/profiler/services.yaml @@ -4,3 +4,9 @@ start: seconds: description: The number of seconds to run the profiler. example: 60.0 +memory: + description: Start the Memory Profiler + fields: + seconds: + description: The number of seconds to run the memory profiler. + example: 60.0 diff --git a/requirements_all.txt b/requirements_all.txt index a9de43462b5df..3b2b699e19ca8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -716,6 +716,9 @@ growattServer==0.1.1 # homeassistant.components.gstreamer gstreamer-player==1.1.2 +# homeassistant.components.profiler +guppy3==3.1.0 + # homeassistant.components.ffmpeg ha-ffmpeg==2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 24275ad8585c6..2e35de3182e4f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -360,6 +360,9 @@ greeclimate==0.9.0 # homeassistant.components.griddy griddypower==0.1.0 +# homeassistant.components.profiler +guppy3==3.1.0 + # homeassistant.components.ffmpeg ha-ffmpeg==2.0 diff --git a/tests/components/profiler/test_init.py b/tests/components/profiler/test_init.py index 2373e64a59369..d2daa117a43cf 100644 --- a/tests/components/profiler/test_init.py +++ b/tests/components/profiler/test_init.py @@ -2,7 +2,11 @@ import os from homeassistant import setup -from homeassistant.components.profiler import CONF_SECONDS, SERVICE_START +from homeassistant.components.profiler import ( + CONF_SECONDS, + SERVICE_MEMORY, + SERVICE_START, +) from homeassistant.components.profiler.const import DOMAIN from tests.async_mock import patch @@ -39,3 +43,35 @@ def _mock_path(filename): assert await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done() + + +async def test_memory_usage(hass, tmpdir): + """Test we can setup and the service is registered.""" + test_dir = tmpdir.mkdir("profiles") + + await setup.async_setup_component(hass, "persistent_notification", {}) + entry = MockConfigEntry(domain=DOMAIN) + entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert hass.services.has_service(DOMAIN, SERVICE_MEMORY) + + last_filename = None + + def _mock_path(filename): + nonlocal last_filename + last_filename = f"{test_dir}/{filename}" + return last_filename + + with patch("homeassistant.components.profiler.hpy") as mock_hpy, patch.object( + hass.config, "path", _mock_path + ): + await hass.services.async_call(DOMAIN, SERVICE_MEMORY, {CONF_SECONDS: 0.000001}) + await hass.async_block_till_done() + + mock_hpy.assert_called_once() + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done() From a2f2a42e66dc41a848bf81e556f6612b8447de31 Mon Sep 17 00:00:00 2001 From: Michael <35783820+mib1185@users.noreply.github.com> Date: Thu, 29 Oct 2020 09:22:36 +0100 Subject: [PATCH 06/43] Fix adding Virtual DSM system in synology_dsm (#42523) --- .../components/synology_dsm/config_flow.py | 1 - .../synology_dsm/test_config_flow.py | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/synology_dsm/config_flow.py b/homeassistant/components/synology_dsm/config_flow.py index 2267d0b099c37..314bab5480617 100644 --- a/homeassistant/components/synology_dsm/config_flow.py +++ b/homeassistant/components/synology_dsm/config_flow.py @@ -275,7 +275,6 @@ def _login_and_fetch_syno_info(api, otp_code): if ( not api.information.serial or api.utilisation.cpu_user_load is None - or not api.storage.disks_ids or not api.storage.volumes_ids or not api.network.macs ): diff --git a/tests/components/synology_dsm/test_config_flow.py b/tests/components/synology_dsm/test_config_flow.py index 5a1a86ef67305..fd060ce352936 100644 --- a/tests/components/synology_dsm/test_config_flow.py +++ b/tests/components/synology_dsm/test_config_flow.py @@ -81,6 +81,20 @@ def mock_controller_service_2sa(): yield service_mock +@pytest.fixture(name="service_vdsm") +def mock_controller_service_vdsm(): + """Mock a successful service.""" + with patch( + "homeassistant.components.synology_dsm.config_flow.SynologyDSM" + ) as service_mock: + service_mock.return_value.information.serial = SERIAL + service_mock.return_value.utilisation.cpu_user_load = 1 + service_mock.return_value.storage.disks_ids = [] + service_mock.return_value.storage.volumes_ids = ["volume_1"] + service_mock.return_value.network.macs = MACS + yield service_mock + + @pytest.fixture(name="service_failed") def mock_controller_service_failed(): """Mock a failed service.""" @@ -196,6 +210,40 @@ async def test_user_2sa(hass: HomeAssistantType, service_2sa: MagicMock): assert result["data"].get(CONF_VOLUMES) is None +async def test_user_vdsm(hass: HomeAssistantType, service_vdsm: MagicMock): + """Test user config.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=None + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == "user" + + # test with all provided + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={ + CONF_HOST: HOST, + CONF_PORT: PORT, + CONF_SSL: SSL, + CONF_USERNAME: USERNAME, + CONF_PASSWORD: PASSWORD, + }, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["result"].unique_id == SERIAL + assert result["title"] == HOST + assert result["data"][CONF_HOST] == HOST + assert result["data"][CONF_PORT] == PORT + assert result["data"][CONF_SSL] == SSL + assert result["data"][CONF_USERNAME] == USERNAME + assert result["data"][CONF_PASSWORD] == PASSWORD + assert result["data"][CONF_MAC] == MACS + assert result["data"].get("device_token") is None + assert result["data"].get(CONF_DISKS) is None + assert result["data"].get(CONF_VOLUMES) is None + + async def test_import(hass: HomeAssistantType, service: MagicMock): """Test import step.""" # import with minimum setup From 0ba1298f1bca78120b8a22059e22d14dfc787425 Mon Sep 17 00:00:00 2001 From: Chris Talkington Date: Thu, 29 Oct 2020 03:51:22 -0500 Subject: [PATCH 07/43] Remove YAML config for directv (#41961) --- homeassistant/components/directv/__init__.py | 23 ++-------------- .../components/directv/config_flow.py | 6 ----- tests/components/directv/test_config_flow.py | 26 +------------------ tests/components/directv/test_init.py | 11 +------- 4 files changed, 4 insertions(+), 62 deletions(-) diff --git a/homeassistant/components/directv/__init__.py b/homeassistant/components/directv/__init__.py index af27d19cfb0a2..59682178d40fd 100644 --- a/homeassistant/components/directv/__init__.py +++ b/homeassistant/components/directv/__init__.py @@ -4,9 +4,8 @@ from typing import Any, Dict from directv import DIRECTV, DIRECTVError -import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_NAME, CONF_HOST from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady @@ -23,14 +22,7 @@ DOMAIN, ) -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: vol.All( - cv.ensure_list, [vol.Schema({vol.Required(CONF_HOST): cv.string})] - ) - }, - extra=vol.ALLOW_EXTRA, -) +CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.120") PLATFORMS = ["media_player", "remote"] SCAN_INTERVAL = timedelta(seconds=30) @@ -39,17 +31,6 @@ async def async_setup(hass: HomeAssistant, config: Dict) -> bool: """Set up the DirecTV component.""" hass.data.setdefault(DOMAIN, {}) - - if DOMAIN in config: - for entry_config in config[DOMAIN]: - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=entry_config, - ) - ) - return True diff --git a/homeassistant/components/directv/config_flow.py b/homeassistant/components/directv/config_flow.py index d84c3925ac4ce..cae0e62b1bed8 100644 --- a/homeassistant/components/directv/config_flow.py +++ b/homeassistant/components/directv/config_flow.py @@ -47,12 +47,6 @@ def __init__(self): """Set up the instance.""" self.discovery_info = {} - async def async_step_import( - self, user_input: Optional[ConfigType] = None - ) -> Dict[str, Any]: - """Handle a flow initiated by configuration file.""" - return await self.async_step_user(user_input) - async def async_step_user( self, user_input: Optional[ConfigType] = None ) -> Dict[str, Any]: diff --git a/tests/components/directv/test_config_flow.py b/tests/components/directv/test_config_flow.py index df3c606f68706..09b76cfb550e5 100644 --- a/tests/components/directv/test_config_flow.py +++ b/tests/components/directv/test_config_flow.py @@ -3,7 +3,7 @@ from homeassistant.components.directv.const import CONF_RECEIVER_ID, DOMAIN from homeassistant.components.ssdp import ATTR_UPNP_SERIAL -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER +from homeassistant.config_entries import SOURCE_SSDP, SOURCE_USER from homeassistant.const import CONF_HOST, CONF_NAME, CONF_SOURCE from homeassistant.data_entry_flow import ( RESULT_TYPE_ABORT, @@ -213,30 +213,6 @@ async def test_ssdp_confirm_unknown_error( assert result["reason"] == "unknown" -async def test_full_import_flow_implementation( - hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker -) -> None: - """Test the full manual user flow from start to finish.""" - mock_connection(aioclient_mock) - - user_input = MOCK_USER_INPUT.copy() - with patch( - "homeassistant.components.directv.async_setup_entry", return_value=True - ), patch("homeassistant.components.directv.async_setup", return_value=True): - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={CONF_SOURCE: SOURCE_IMPORT}, - data=user_input, - ) - - assert result["type"] == RESULT_TYPE_CREATE_ENTRY - assert result["title"] == HOST - - assert result["data"] - assert result["data"][CONF_HOST] == HOST - assert result["data"][CONF_RECEIVER_ID] == RECEIVER_ID - - async def test_full_user_flow_implementation( hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker ) -> None: diff --git a/tests/components/directv/test_init.py b/tests/components/directv/test_init.py index 0d806d668a042..b56070f0e7eaa 100644 --- a/tests/components/directv/test_init.py +++ b/tests/components/directv/test_init.py @@ -6,22 +6,13 @@ ENTRY_STATE_SETUP_RETRY, ) from homeassistant.helpers.typing import HomeAssistantType -from homeassistant.setup import async_setup_component -from tests.components.directv import MOCK_CONFIG, mock_connection, setup_integration +from tests.components.directv import setup_integration from tests.test_util.aiohttp import AiohttpClientMocker # pylint: disable=redefined-outer-name -async def test_setup( - hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker -) -> None: - """Test the DirecTV setup from configuration.""" - mock_connection(aioclient_mock) - assert await async_setup_component(hass, DOMAIN, MOCK_CONFIG) - - async def test_config_entry_not_ready( hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker ) -> None: From 708423e0f85ad95eb72da48fc6c4b93e44a031e7 Mon Sep 17 00:00:00 2001 From: Chris Talkington Date: Thu, 29 Oct 2020 03:51:48 -0500 Subject: [PATCH 08/43] Remove YAML config for roku (#41960) --- homeassistant/components/roku/__init__.py | 23 ++------------ homeassistant/components/roku/config_flow.py | 6 ---- tests/components/roku/test_config_flow.py | 32 ++------------------ 3 files changed, 4 insertions(+), 57 deletions(-) diff --git a/homeassistant/components/roku/__init__.py b/homeassistant/components/roku/__init__.py index 663823d71b423..739e345a6377c 100644 --- a/homeassistant/components/roku/__init__.py +++ b/homeassistant/components/roku/__init__.py @@ -6,11 +6,10 @@ from rokuecp import Roku, RokuConnectionError, RokuError from rokuecp.models import Device -import voluptuous as vol from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_DOMAIN from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_NAME, CONF_HOST from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv @@ -31,14 +30,7 @@ DOMAIN, ) -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: vol.All( - cv.ensure_list, [vol.Schema({vol.Required(CONF_HOST): cv.string})] - ) - }, - extra=vol.ALLOW_EXTRA, -) +CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.120") PLATFORMS = [MEDIA_PLAYER_DOMAIN, REMOTE_DOMAIN] SCAN_INTERVAL = timedelta(seconds=15) @@ -48,17 +40,6 @@ async def async_setup(hass: HomeAssistantType, config: Dict) -> bool: """Set up the Roku integration.""" hass.data.setdefault(DOMAIN, {}) - - if DOMAIN in config: - for entry_config in config[DOMAIN]: - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=entry_config, - ) - ) - return True diff --git a/homeassistant/components/roku/config_flow.py b/homeassistant/components/roku/config_flow.py index 662e22605c8ef..6e494ce269223 100644 --- a/homeassistant/components/roku/config_flow.py +++ b/homeassistant/components/roku/config_flow.py @@ -61,12 +61,6 @@ def _show_form(self, errors: Optional[Dict] = None) -> Dict[str, Any]: errors=errors or {}, ) - async def async_step_import( - self, user_input: Optional[Dict] = None - ) -> Dict[str, Any]: - """Handle configuration by yaml file.""" - return await self.async_step_user(user_input) - async def async_step_user( self, user_input: Optional[Dict] = None ) -> Dict[str, Any]: diff --git a/tests/components/roku/test_config_flow.py b/tests/components/roku/test_config_flow.py index 0fb77e4613952..a3cda6afa69a8 100644 --- a/tests/components/roku/test_config_flow.py +++ b/tests/components/roku/test_config_flow.py @@ -1,6 +1,6 @@ """Test the Roku config flow.""" from homeassistant.components.roku.const import DOMAIN -from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER +from homeassistant.config_entries import SOURCE_SSDP, SOURCE_USER from homeassistant.const import CONF_HOST, CONF_NAME, CONF_SOURCE from homeassistant.data_entry_flow import ( RESULT_TYPE_ABORT, @@ -30,7 +30,7 @@ async def test_duplicate_error( user_input = {CONF_HOST: HOST} result = await hass.config_entries.flow.async_init( - DOMAIN, context={CONF_SOURCE: SOURCE_IMPORT}, data=user_input + DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input ) assert result["type"] == RESULT_TYPE_ABORT @@ -128,34 +128,6 @@ async def test_form_unknown_error(hass: HomeAssistantType) -> None: assert len(mock_validate_input.mock_calls) == 1 -async def test_import( - hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker -) -> None: - """Test the import step.""" - mock_connection(aioclient_mock) - - user_input = {CONF_HOST: HOST} - with patch( - "homeassistant.components.roku.async_setup", return_value=True - ) as mock_setup, patch( - "homeassistant.components.roku.async_setup_entry", - return_value=True, - ) as mock_setup_entry: - result = await hass.config_entries.flow.async_init( - DOMAIN, context={CONF_SOURCE: SOURCE_IMPORT}, data=user_input - ) - await hass.async_block_till_done() - - assert result["type"] == RESULT_TYPE_CREATE_ENTRY - assert result["title"] == UPNP_FRIENDLY_NAME - - assert result["data"] - assert result["data"][CONF_HOST] == HOST - - assert len(mock_setup.mock_calls) == 1 - assert len(mock_setup_entry.mock_calls) == 1 - - async def test_ssdp_cannot_connect( hass: HomeAssistantType, aioclient_mock: AiohttpClientMocker ) -> None: From 6b29648cfc56424fc9965612f19a5990ef1764f8 Mon Sep 17 00:00:00 2001 From: springstan <46536646+springstan@users.noreply.github.com> Date: Thu, 29 Oct 2020 09:59:15 +0100 Subject: [PATCH 09/43] Use common strings in twilio config flow (#42477) --- homeassistant/components/twilio/strings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/twilio/strings.json b/homeassistant/components/twilio/strings.json index 0480fdae7c890..9717ff15fb55c 100644 --- a/homeassistant/components/twilio/strings.json +++ b/homeassistant/components/twilio/strings.json @@ -3,7 +3,7 @@ "step": { "user": { "title": "Set up the Twilio Webhook", - "description": "Are you sure you want to set up Twilio?" + "description": "[%key:common::config_flow::description::confirm_setup%]" } }, "abort": { From c8f00a7b38c2cf579d374a4f125fab951fb0b07d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 29 Oct 2020 04:06:55 -0500 Subject: [PATCH 10/43] Gather all collection listeners and changes at the same time (#42497) --- homeassistant/helpers/collection.py | 67 +++++++++++++++++++---------- tests/helpers/test_collection.py | 32 +++++++++----- 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/homeassistant/helpers/collection.py b/homeassistant/helpers/collection.py index 9e7c606198754..6733b1d3dbd66 100644 --- a/homeassistant/helpers/collection.py +++ b/homeassistant/helpers/collection.py @@ -1,8 +1,9 @@ """Helper to deal with YAML + storage.""" from abc import ABC, abstractmethod import asyncio +from dataclasses import dataclass import logging -from typing import Any, Awaitable, Callable, Dict, List, Optional, cast +from typing import Any, Awaitable, Callable, Dict, Iterable, List, Optional, cast import voluptuous as vol from voluptuous.humanize import humanize_error @@ -26,6 +27,20 @@ CHANGE_REMOVED = "removed" +@dataclass +class CollectionChangeSet: + """Class to represent a change set. + + change_type: One of CHANGE_* + item_id: The id of the item + item: The item + """ + + change_type: str + item_id: str + item: Any + + ChangeListener = Callable[ [ # Change type @@ -105,11 +120,14 @@ def async_add_listener(self, listener: ChangeListener) -> None: """ self.listeners.append(listener) - async def notify_change(self, change_type: str, item_id: str, item: dict) -> None: + async def notify_changes(self, change_sets: Iterable[CollectionChangeSet]) -> None: """Notify listeners of a change.""" - self.logger.debug("%s %s: %s", change_type, item_id, item) await asyncio.gather( - *[listener(change_type, item_id, item) for listener in self.listeners] + *[ + listener(change_set.change_type, change_set.item_id, change_set.item) + for listener in self.listeners + for change_set in change_sets + ] ) @@ -118,9 +136,10 @@ class YamlCollection(ObservableCollection): async def async_load(self, data: List[dict]) -> None: """Load the YAML collection. Overrides existing data.""" + old_ids = set(self.data) - tasks = [] + change_sets = [] for item in data: item_id = item[CONF_ID] @@ -135,15 +154,15 @@ async def async_load(self, data: List[dict]) -> None: event = CHANGE_ADDED self.data[item_id] = item - tasks.append(self.notify_change(event, item_id, item)) + change_sets.append(CollectionChangeSet(event, item_id, item)) for item_id in old_ids: - tasks.append( - self.notify_change(CHANGE_REMOVED, item_id, self.data.pop(item_id)) + change_sets.append( + CollectionChangeSet(CHANGE_REMOVED, item_id, self.data.pop(item_id)) ) - if tasks: - await asyncio.gather(*tasks) + if change_sets: + await self.notify_changes(change_sets) class StorageCollection(ObservableCollection): @@ -178,9 +197,9 @@ async def async_load(self) -> None: for item in raw_storage["items"]: self.data[item[CONF_ID]] = item - await asyncio.gather( - *[ - self.notify_change(CHANGE_ADDED, item[CONF_ID], item) + await self.notify_changes( + [ + CollectionChangeSet(CHANGE_ADDED, item[CONF_ID], item) for item in raw_storage["items"] ] ) @@ -204,7 +223,9 @@ async def async_create_item(self, data: dict) -> dict: item[CONF_ID] = self.id_manager.generate_id(self._get_suggested_id(item)) self.data[item[CONF_ID]] = item self._async_schedule_save() - await self.notify_change(CHANGE_ADDED, item[CONF_ID], item) + await self.notify_changes( + [CollectionChangeSet(CHANGE_ADDED, item[CONF_ID], item)] + ) return item async def async_update_item(self, item_id: str, updates: dict) -> dict: @@ -222,7 +243,9 @@ async def async_update_item(self, item_id: str, updates: dict) -> dict: self.data[item_id] = updated self._async_schedule_save() - await self.notify_change(CHANGE_UPDATED, item_id, updated) + await self.notify_changes( + [CollectionChangeSet(CHANGE_UPDATED, item_id, updated)] + ) return self.data[item_id] @@ -234,7 +257,7 @@ async def async_delete_item(self, item_id: str) -> None: item = self.data.pop(item_id) self._async_schedule_save() - await self.notify_change(CHANGE_REMOVED, item_id, item) + await self.notify_changes([CollectionChangeSet(CHANGE_REMOVED, item_id, item)]) @callback def _async_schedule_save(self) -> None: @@ -254,9 +277,9 @@ class IDLessCollection(ObservableCollection): async def async_load(self, data: List[dict]) -> None: """Load the collection. Overrides existing data.""" - await asyncio.gather( - *[ - self.notify_change(CHANGE_REMOVED, item_id, item) + await self.notify_changes( + [ + CollectionChangeSet(CHANGE_REMOVED, item_id, item) for item_id, item in list(self.data.items()) ] ) @@ -269,9 +292,9 @@ async def async_load(self, data: List[dict]) -> None: self.data[item_id] = item - await asyncio.gather( - *[ - self.notify_change(CHANGE_ADDED, item_id, item) + await self.notify_changes( + [ + CollectionChangeSet(CHANGE_ADDED, item_id, item) for item_id, item in self.data.items() ] ) diff --git a/tests/helpers/test_collection.py b/tests/helpers/test_collection.py index 11f1534defb10..d5a8526b6da8d 100644 --- a/tests/helpers/test_collection.py +++ b/tests/helpers/test_collection.py @@ -91,7 +91,9 @@ async def test_observable_collection(): assert coll.async_items() == [1] changes = track_changes(coll) - await coll.notify_change("mock_type", "mock_id", {"mock": "item"}) + await coll.notify_changes( + [collection.CollectionChangeSet("mock_type", "mock_id", {"mock": "item"})] + ) assert len(changes) == 1 assert changes[0] == ("mock_type", "mock_id", {"mock": "item"}) @@ -226,25 +228,35 @@ async def test_attach_entity_component_collection(hass): coll = collection.ObservableCollection(_LOGGER) collection.attach_entity_component_collection(ent_comp, coll, MockEntity) - await coll.notify_change( - collection.CHANGE_ADDED, - "mock_id", - {"id": "mock_id", "state": "initial", "name": "Mock 1"}, + await coll.notify_changes( + [ + collection.CollectionChangeSet( + collection.CHANGE_ADDED, + "mock_id", + {"id": "mock_id", "state": "initial", "name": "Mock 1"}, + ) + ], ) assert hass.states.get("test.mock_1").name == "Mock 1" assert hass.states.get("test.mock_1").state == "initial" - await coll.notify_change( - collection.CHANGE_UPDATED, - "mock_id", - {"id": "mock_id", "state": "second", "name": "Mock 1 updated"}, + await coll.notify_changes( + [ + collection.CollectionChangeSet( + collection.CHANGE_UPDATED, + "mock_id", + {"id": "mock_id", "state": "second", "name": "Mock 1 updated"}, + ) + ], ) assert hass.states.get("test.mock_1").name == "Mock 1 updated" assert hass.states.get("test.mock_1").state == "second" - await coll.notify_change(collection.CHANGE_REMOVED, "mock_id", None) + await coll.notify_changes( + [collection.CollectionChangeSet(collection.CHANGE_REMOVED, "mock_id", None)], + ) assert hass.states.get("test.mock_1") is None From bebbafdabac07ba07d39068599ea75e3889b7add Mon Sep 17 00:00:00 2001 From: cgtobi Date: Thu, 29 Oct 2020 11:50:39 +0100 Subject: [PATCH 11/43] Fix RMV giving wrong data and ignoring given parameters (#42561) --- homeassistant/components/rmvtransport/sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rmvtransport/sensor.py b/homeassistant/components/rmvtransport/sensor.py index 76e75d77a58f6..4a619437d52bf 100644 --- a/homeassistant/components/rmvtransport/sensor.py +++ b/homeassistant/components/rmvtransport/sensor.py @@ -263,10 +263,10 @@ async def async_update(self): if not dest_found: continue - elif self._lines and journey["number"] not in self._lines: + if self._lines and journey["number"] not in self._lines: continue - elif journey["minutes"] < self._time_offset: + if journey["minutes"] < self._time_offset: continue for attr in ["direction", "departure_time", "product", "minutes"]: From 1215100f9afa595d4bc6ced94758c927fd4f6b06 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 29 Oct 2020 20:09:41 +0100 Subject: [PATCH 12/43] Fix MQTT template light (#42598) --- homeassistant/components/mqtt/light/schema_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/mqtt/light/schema_template.py b/homeassistant/components/mqtt/light/schema_template.py index 44a87f2af2c84..faf987881b988 100644 --- a/homeassistant/components/mqtt/light/schema_template.py +++ b/homeassistant/components/mqtt/light/schema_template.py @@ -252,7 +252,7 @@ def state_received(msg): except ValueError: _LOGGER.warning("Invalid color value received") - if self._templates[CONF_COLOR_TEMP_TEMPLATE] is not None: + if self._templates[CONF_WHITE_VALUE_TEMPLATE] is not None: try: self._white_value = int( self._templates[ From 7027b01a29c428b0e60a7c1f1922e925746798f0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 29 Oct 2020 22:34:06 +0100 Subject: [PATCH 13/43] Fix broken time trigger test (#42606) --- tests/components/config/test_core.py | 35 ++++++++++--------- tests/components/hassio/test_init.py | 3 +- .../homeassistant/triggers/test_time.py | 1 - 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/tests/components/config/test_core.py b/tests/components/config/test_core.py index 1f379727b442c..72e655dbb66d7 100644 --- a/tests/components/config/test_core.py +++ b/tests/components/config/test_core.py @@ -61,22 +61,23 @@ async def test_websocket_core_update(hass, client): assert hass.config.external_url != "https://www.example.com" assert hass.config.internal_url != "http://example.com" - await client.send_json( - { - "id": 5, - "type": "config/core/update", - "latitude": 60, - "longitude": 50, - "elevation": 25, - "location_name": "Huis", - CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, - "time_zone": "America/New_York", - "external_url": "https://www.example.com", - "internal_url": "http://example.local", - } - ) + with patch("homeassistant.util.dt.set_default_time_zone") as mock_set_tz: + await client.send_json( + { + "id": 5, + "type": "config/core/update", + "latitude": 60, + "longitude": 50, + "elevation": 25, + "location_name": "Huis", + CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, + "time_zone": "America/New_York", + "external_url": "https://www.example.com", + "internal_url": "http://example.local", + } + ) - msg = await client.receive_json() + msg = await client.receive_json() assert msg["id"] == 5 assert msg["type"] == TYPE_RESULT @@ -86,11 +87,11 @@ async def test_websocket_core_update(hass, client): assert hass.config.elevation == 25 assert hass.config.location_name == "Huis" assert hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL - assert hass.config.time_zone.zone == "America/New_York" assert hass.config.external_url == "https://www.example.com" assert hass.config.internal_url == "http://example.local" - dt_util.set_default_time_zone(ORIG_TIME_ZONE) + assert len(mock_set_tz.mock_calls) == 1 + assert mock_set_tz.mock_calls[0][1][0].zone == "America/New_York" async def test_websocket_core_update_not_admin(hass, hass_ws_client, hass_admin_user): diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index 56792295fec3e..62b4a4adbd267 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -186,7 +186,8 @@ async def test_setup_core_push_timezone(hass, aioclient_mock): assert aioclient_mock.call_count == 7 assert aioclient_mock.mock_calls[2][2]["timezone"] == "testzone" - await hass.config.async_update(time_zone="America/New_York") + with patch("homeassistant.util.dt.set_default_time_zone"): + await hass.config.async_update(time_zone="America/New_York") await hass.async_block_till_done() assert aioclient_mock.mock_calls[-1][2]["timezone"] == "America/New_York" diff --git a/tests/components/homeassistant/triggers/test_time.py b/tests/components/homeassistant/triggers/test_time.py index db10e8366291b..91fd57beed320 100644 --- a/tests/components/homeassistant/triggers/test_time.py +++ b/tests/components/homeassistant/triggers/test_time.py @@ -74,7 +74,6 @@ async def test_if_fires_using_at_input_datetime(hass, calls, has_date, has_time) "input_datetime", {"input_datetime": {"trigger": {"has_date": has_date, "has_time": has_time}}}, ) - now = dt_util.now() trigger_dt = now.replace( From a396f8f76fe9f4f70e999158135cc74cff1c264f Mon Sep 17 00:00:00 2001 From: Nikolai Date: Fri, 30 Oct 2020 01:55:25 +0300 Subject: [PATCH 14/43] Add telegram_sent event (#41159) Co-authored-by: Heine Furubotten --- .../components/telegram_bot/__init__.py | 18 +++++++++++++++++- .../components/telegram_bot/services.yaml | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/telegram_bot/__init__.py b/homeassistant/components/telegram_bot/__init__.py index 60e33414b1e74..af00c2cb6d0e4 100644 --- a/homeassistant/components/telegram_bot/__init__.py +++ b/homeassistant/components/telegram_bot/__init__.py @@ -67,6 +67,7 @@ ATTR_USERNAME = "username" ATTR_VERIFY_SSL = "verify_ssl" ATTR_TIMEOUT = "timeout" +ATTR_MESSAGE_TAG = "message_tag" CONF_ALLOWED_CHAT_IDS = "allowed_chat_ids" CONF_PROXY_URL = "proxy_url" @@ -91,6 +92,7 @@ EVENT_TELEGRAM_CALLBACK = "telegram_callback" EVENT_TELEGRAM_COMMAND = "telegram_command" EVENT_TELEGRAM_TEXT = "telegram_text" +EVENT_TELEGRAM_SENT = "telegram_sent" PARSER_HTML = "html" PARSER_MD = "markdown" @@ -136,6 +138,7 @@ vol.Optional(ATTR_KEYBOARD): vol.All(cv.ensure_list, [cv.string]), vol.Optional(ATTR_KEYBOARD_INLINE): cv.ensure_list, vol.Optional(ATTR_TIMEOUT): cv.positive_int, + vol.Optional(ATTR_MESSAGE_TAG): cv.string, }, extra=vol.ALLOW_EXTRA, ) @@ -508,6 +511,7 @@ def _make_row_inline_keyboard(row_keyboard): ATTR_REPLY_TO_MSGID: None, ATTR_REPLYMARKUP: None, ATTR_TIMEOUT: None, + ATTR_MESSAGE_TAG: None, } if data is not None: if ATTR_PARSER in data: @@ -522,6 +526,8 @@ def _make_row_inline_keyboard(row_keyboard): params[ATTR_DISABLE_WEB_PREV] = data[ATTR_DISABLE_WEB_PREV] if ATTR_REPLY_TO_MSGID in data: params[ATTR_REPLY_TO_MSGID] = data[ATTR_REPLY_TO_MSGID] + if ATTR_MESSAGE_TAG in data: + params[ATTR_MESSAGE_TAG] = data[ATTR_MESSAGE_TAG] # Keyboards: if ATTR_KEYBOARD in data: keys = data.get(ATTR_KEYBOARD) @@ -548,12 +554,22 @@ def _send_msg(self, func_send, msg_error, *args_msg, **kwargs_msg): out = func_send(*args_msg, **kwargs_msg) if not isinstance(out, bool) and hasattr(out, ATTR_MESSAGEID): chat_id = out.chat_id - self._last_message_id[chat_id] = out[ATTR_MESSAGEID] + message_id = out[ATTR_MESSAGEID] + self._last_message_id[chat_id] = message_id _LOGGER.debug( "Last message ID: %s (from chat_id %s)", self._last_message_id, chat_id, ) + + event_data = { + ATTR_CHAT_ID: chat_id, + ATTR_MESSAGEID: message_id, + } + message_tag = kwargs_msg.get(ATTR_MESSAGE_TAG) + if message_tag is not None: + event_data[ATTR_MESSAGE_TAG] = message_tag + self.hass.bus.async_fire(EVENT_TELEGRAM_SENT, event_data) elif not isinstance(out, bool): _LOGGER.warning( "Update last message: out_type:%s, out=%s", type(out), out diff --git a/homeassistant/components/telegram_bot/services.yaml b/homeassistant/components/telegram_bot/services.yaml index a87bfdf3af6b9..8a66d2cab3a28 100644 --- a/homeassistant/components/telegram_bot/services.yaml +++ b/homeassistant/components/telegram_bot/services.yaml @@ -30,6 +30,9 @@ send_message: inline_keyboard: description: List of rows of commands, comma-separated, to make a custom inline keyboard with buttons with associated callback data. example: '["/button1, /button2", "/button3"] or ["Text button1:/button1, Text button2:/button2", "Text button3:/button3"] or [[["Text button1", "/button1"], ["Text button2", "/button2"]], [["Text button3", "/button3"]]]' + message_tag: + description: 'Tag for sent message. In telegram_sent event data: {{trigger.event.data.message_tag}}' + example: "msg_to_edit" send_photo: description: Send a photo. @@ -67,6 +70,9 @@ send_photo: inline_keyboard: description: List of rows of commands, comma-separated, to make a custom inline keyboard with buttons with associated callback data. example: '["/button1, /button2", "/button3"] or [[["Text button1", "/button1"], ["Text button2", "/button2"]], [["Text button3", "/button3"]]]' + message_tag: + description: 'Tag for sent message. In telegram_sent event data: {{trigger.event.data.message_tag}}' + example: "msg_to_edit" send_sticker: description: Send a sticker. @@ -101,6 +107,9 @@ send_sticker: inline_keyboard: description: List of rows of commands, comma-separated, to make a custom inline keyboard with buttons with associated callback data. example: '["/button1, /button2", "/button3"] or [[["Text button1", "/button1"], ["Text button2", "/button2"]], [["Text button3", "/button3"]]]' + message_tag: + description: 'Tag for sent message. In telegram_sent event data: {{trigger.event.data.message_tag}}' + example: "msg_to_edit" send_video: description: Send a video. @@ -138,6 +147,9 @@ send_video: inline_keyboard: description: List of rows of commands, comma-separated, to make a custom inline keyboard with buttons with associated callback data. example: '["/button1, /button2", "/button3"] or [[["Text button1", "/button1"], ["Text button2", "/button2"]], [["Text button3", "/button3"]]]' + message_tag: + description: 'Tag for sent message. In telegram_sent event data: {{trigger.event.data.message_tag}}' + example: "msg_to_edit" send_document: description: Send a document. @@ -175,6 +187,9 @@ send_document: inline_keyboard: description: List of rows of commands, comma-separated, to make a custom inline keyboard with buttons with associated callback data. example: '["/button1, /button2", "/button3"] or [[["Text button1", "/button1"], ["Text button2", "/button2"]], [["Text button3", "/button3"]]]' + message_tag: + description: 'Tag for sent message. In telegram_sent event data: {{trigger.event.data.message_tag}}' + example: "msg_to_edit" send_location: description: Send a location. @@ -200,6 +215,9 @@ send_location: inline_keyboard: description: List of rows of commands, comma-separated, to make a custom inline keyboard with buttons with associated callback data. example: '["/button1, /button2", "/button3"] or [[["Text button1", "/button1"], ["Text button2", "/button2"]], [["Text button3", "/button3"]]]' + message_tag: + description: 'Tag for sent message. In telegram_sent event data: {{trigger.event.data.message_tag}}' + example: "msg_to_edit" edit_message: description: Edit a previously sent message. From 8eb89cdb4651603f615a10315fd611580d58cd05 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 29 Oct 2020 18:05:55 -0500 Subject: [PATCH 15/43] Fix flapping event template test (#42614) --- tests/helpers/test_event.py | 109 +++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/tests/helpers/test_event.py b/tests/helpers/test_event.py index 8add5cc1cf3a1..64c5d79469b12 100644 --- a/tests/helpers/test_event.py +++ b/tests/helpers/test_event.py @@ -2123,68 +2123,73 @@ def specific_run_callback(event, updates): async def test_track_template_with_time_that_leaves_scope(hass): """Test tracking template with time.""" + now = dt_util.utcnow() + test_time = datetime(now.year + 1, 5, 24, 11, 59, 1, 500000, tzinfo=dt_util.UTC) + + with patch("homeassistant.util.dt.utcnow", return_value=test_time): + hass.states.async_set("binary_sensor.washing_machine", "on") + specific_runs = [] + template_complex = Template( + """ + {% if states.binary_sensor.washing_machine.state == "on" %} + {{ now() }} + {% else %} + {{ states.binary_sensor.washing_machine.last_updated }} + {% endif %} + """, + hass, + ) - hass.states.async_set("binary_sensor.washing_machine", "on") - specific_runs = [] - template_complex = Template( - """ - {% if states.binary_sensor.washing_machine.state == "on" %} - {{ now() }} - {% else %} - {{ states.binary_sensor.washing_machine.last_updated }} - {% endif %} - """, - hass, - ) + def specific_run_callback(event, updates): + specific_runs.append(updates.pop().result) - def specific_run_callback(event, updates): - specific_runs.append(updates.pop().result) + info = async_track_template_result( + hass, [TrackTemplate(template_complex, None)], specific_run_callback + ) + await hass.async_block_till_done() - info = async_track_template_result( - hass, [TrackTemplate(template_complex, None)], specific_run_callback - ) - await hass.async_block_till_done() + assert info.listeners == { + "all": False, + "domains": set(), + "entities": {"binary_sensor.washing_machine"}, + "time": True, + } - assert info.listeners == { - "all": False, - "domains": set(), - "entities": {"binary_sensor.washing_machine"}, - "time": True, - } + hass.states.async_set("binary_sensor.washing_machine", "off") + await hass.async_block_till_done() - hass.states.async_set("binary_sensor.washing_machine", "off") - await hass.async_block_till_done() + assert info.listeners == { + "all": False, + "domains": set(), + "entities": {"binary_sensor.washing_machine"}, + "time": False, + } - assert info.listeners == { - "all": False, - "domains": set(), - "entities": {"binary_sensor.washing_machine"}, - "time": False, - } + hass.states.async_set("binary_sensor.washing_machine", "on") + await hass.async_block_till_done() - hass.states.async_set("binary_sensor.washing_machine", "on") - await hass.async_block_till_done() + assert info.listeners == { + "all": False, + "domains": set(), + "entities": {"binary_sensor.washing_machine"}, + "time": True, + } - assert info.listeners == { - "all": False, - "domains": set(), - "entities": {"binary_sensor.washing_machine"}, - "time": True, - } + # Verify we do not update before the minute rolls over + callback_count_before_time_change = len(specific_runs) + async_fire_time_changed(hass, test_time) + await hass.async_block_till_done() + assert len(specific_runs) == callback_count_before_time_change - # Verify we do not update before the minute rolls over - callback_count_before_time_change = len(specific_runs) - test_time = dt_util.utcnow().replace(second=1) - async_fire_time_changed(hass, test_time) - await hass.async_block_till_done() - async_fire_time_changed(hass, test_time + timedelta(seconds=58)) - await hass.async_block_till_done() - assert len(specific_runs) == callback_count_before_time_change + async_fire_time_changed(hass, test_time + timedelta(seconds=58)) + await hass.async_block_till_done() + assert len(specific_runs) == callback_count_before_time_change - # Verify we do update on the next change of minute - async_fire_time_changed(hass, test_time + timedelta(seconds=59)) - await hass.async_block_till_done() - assert len(specific_runs) == callback_count_before_time_change + 1 + # Verify we do update on the next change of minute + async_fire_time_changed(hass, test_time + timedelta(seconds=59)) + + await hass.async_block_till_done() + assert len(specific_runs) == callback_count_before_time_change + 1 info.async_remove() From 7f1683c731c3d222394863f637d953ca6dc6fe46 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 29 Oct 2020 18:06:08 -0500 Subject: [PATCH 16/43] Remove legacy template extract_entities (#42601) --- homeassistant/helpers/template.py | 66 +------ tests/helpers/test_template.py | 298 +----------------------------- 2 files changed, 2 insertions(+), 362 deletions(-) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index d6c89f28e6e8d..cd286b15dc743 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -11,7 +11,7 @@ from operator import attrgetter import random import re -from typing import Any, Dict, Generator, Iterable, List, Optional, Type, Union +from typing import Any, Dict, Generator, Iterable, Optional, Type, Union from urllib.parse import urlencode as urllib_urlencode import weakref @@ -27,13 +27,11 @@ ATTR_LONGITUDE, ATTR_UNIT_OF_MEASUREMENT, LENGTH_METERS, - MATCH_ALL, STATE_UNKNOWN, ) from homeassistant.core import State, callback, split_entity_id, valid_entity_id from homeassistant.exceptions import TemplateError from homeassistant.helpers import config_validation as cv, location as loc_helper -from homeassistant.helpers.frame import report from homeassistant.helpers.typing import HomeAssistantType, TemplateVarsType from homeassistant.loader import bind_hass from homeassistant.util import convert, dt as dt_util, location as loc_util @@ -184,59 +182,6 @@ def __str__(self) -> str: RESULT_WRAPPERS[tuple] = TupleWrapper -def extract_entities( - hass: HomeAssistantType, - template: Optional[str], - variables: TemplateVarsType = None, -) -> Union[str, List[str]]: - """Extract all entities for state_changed listener from template string.""" - - report( - "called template.extract_entities. Please use event.async_track_template_result instead as it can accurately handle watching entities" - ) - - if template is None or not is_template_string(template): - return [] - - if _RE_NONE_ENTITIES.search(template): - return MATCH_ALL - - extraction_final = [] - - for result in _RE_GET_ENTITIES.finditer(template): - if ( - result.group("entity_id") == "trigger.entity_id" - and variables - and "trigger" in variables - and "entity_id" in variables["trigger"] - ): - extraction_final.append(variables["trigger"]["entity_id"]) - elif result.group("entity_id"): - if result.group("func") == "expand": - for entity in expand(hass, result.group("entity_id")): - extraction_final.append(entity.entity_id) - - extraction_final.append(result.group("entity_id")) - elif result.group("domain_inner") or result.group("domain_outer"): - extraction_final.extend( - hass.states.async_entity_ids( - result.group("domain_inner") or result.group("domain_outer") - ) - ) - - if ( - variables - and result.group("variable") in variables - and isinstance(variables[result.group("variable")], str) - and valid_entity_id(variables[result.group("variable")]) - ): - extraction_final.append(variables[result.group("variable")]) - - if extraction_final: - return list(set(extraction_final)) - return MATCH_ALL - - def _true(arg: Any) -> bool: return True @@ -370,15 +315,6 @@ def ensure_valid(self): except jinja2.TemplateError as err: raise TemplateError(err) from err - def extract_entities( - self, variables: TemplateVarsType = None - ) -> Union[str, List[str]]: - """Extract all entities for state_changed listener.""" - if self.is_static: - return [] - - return extract_entities(self.hass, self.template, variables) - def render( self, variables: TemplateVarsType = None, diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index e3eafda52f1ad..fe2f23c00332c 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -13,7 +13,6 @@ ATTR_UNIT_OF_MEASUREMENT, LENGTH_METERS, MASS_GRAMS, - MATCH_ALL, PRESSURE_PA, TEMP_CELSIUS, VOLUME_LITERS, @@ -24,14 +23,7 @@ import homeassistant.util.dt as dt_util from homeassistant.util.unit_system import UnitSystem -from tests.async_mock import Mock, patch - - -@pytest.fixture() -def allow_extract_entities(): - """Allow extract entities.""" - with patch("homeassistant.helpers.template.report"): - yield +from tests.async_mock import patch def _set_up_units(hass): @@ -1870,48 +1862,6 @@ def test_closest_function_no_location_states(hass): ) -def test_extract_entities_none_exclude_stuff(hass, allow_extract_entities): - """Test extract entities function with none or exclude stuff.""" - assert template.extract_entities(hass, None) == [] - - assert template.extract_entities(hass, "mdi:water") == [] - - assert ( - template.extract_entities( - hass, - "{{ closest(states.zone.far_away, states.test_domain.xxx).entity_id }}", - ) - == MATCH_ALL - ) - - assert ( - template.extract_entities( - hass, '{{ distance("123", states.test_object_2.user) }}' - ) - == MATCH_ALL - ) - - -def test_extract_entities_no_match_entities(hass, allow_extract_entities): - """Test extract entities function with none entities stuff.""" - assert ( - template.extract_entities( - hass, "{{ value_json.tst | timestamp_custom('%Y' True) }}" - ) - == MATCH_ALL - ) - - info = render_to_info( - hass, - """ -{% for state in states.sensor %} -{{ state.entity_id }}={{ state.state }},d -{% endfor %} - """, - ) - assert_result_info(info, "", domains=["sensor"]) - - def test_generate_filter_iterators(hass): """Test extract entities function with none entities stuff.""" info = render_to_info( @@ -2030,252 +1980,6 @@ async def test_async_render_to_info_in_conditional(hass): assert_result_info(info, "oink", ["sensor.xyz", "sensor.pig"], []) -async def test_extract_entities_match_entities(hass, allow_extract_entities): - """Test extract entities function with entities stuff.""" - assert ( - template.extract_entities( - hass, - """ -{% if is_state('device_tracker.phone_1', 'home') %} -Ha, Hercules is home! -{% else %} -Hercules is at {{ states('device_tracker.phone_1') }}. -{% endif %} - """, - ) - == ["device_tracker.phone_1"] - ) - - assert ( - template.extract_entities( - hass, - """ -{{ as_timestamp(states.binary_sensor.garage_door.last_changed) }} - """, - ) - == ["binary_sensor.garage_door"] - ) - - assert ( - template.extract_entities( - hass, - """ -{{ states("binary_sensor.garage_door") }} - """, - ) - == ["binary_sensor.garage_door"] - ) - - hass.states.async_set("device_tracker.phone_2", "not_home", {"battery": 20}) - - assert ( - template.extract_entities( - hass, - """ -{{ is_state_attr('device_tracker.phone_2', 'battery', 40) }} - """, - ) - == ["device_tracker.phone_2"] - ) - - assert sorted(["device_tracker.phone_1", "device_tracker.phone_2"]) == sorted( - template.extract_entities( - hass, - """ -{% if is_state('device_tracker.phone_1', 'home') %} -Ha, Hercules is home! -{% elif states.device_tracker.phone_2.attributes.battery < 40 %} -Hercules you power goes done!. -{% endif %} - """, - ) - ) - - assert sorted(["sensor.pick_humidity", "sensor.pick_temperature"]) == sorted( - template.extract_entities( - hass, - """ -{{ -states.sensor.pick_temperature.state ~ "°C (" ~ -states.sensor.pick_humidity.state ~ " %" -}} - """, - ) - ) - - assert sorted( - ["sensor.luftfeuchtigkeit_mean", "input_number.luftfeuchtigkeit"] - ) == sorted( - template.extract_entities( - hass, - "{% if (states('sensor.luftfeuchtigkeit_mean') | int)" - " > (states('input_number.luftfeuchtigkeit') | int +1.5)" - " %}true{% endif %}", - ) - ) - - assert await async_setup_component(hass, "group", {}) - await hass.async_block_till_done() - await group.Group.async_create_group(hass, "empty group", []) - - assert ["group.empty_group"] == template.extract_entities( - hass, "{{ expand('group.empty_group') | list | length }}" - ) - - hass.states.async_set("test_domain.object", "exists") - await group.Group.async_create_group(hass, "expand group", ["test_domain.object"]) - - assert sorted(["group.expand_group", "test_domain.object"]) == sorted( - template.extract_entities( - hass, "{{ expand('group.expand_group') | list | length }}" - ) - ) - assert ["test_domain.entity"] == template.Template( - '{{ is_state("test_domain.entity", "on") }}', hass - ).extract_entities() - - # No expand, extract finds the group - assert template.extract_entities(hass, "{{ states('group.empty_group') }}") == [ - "group.empty_group" - ] - - -def test_extract_entities_with_variables(hass, allow_extract_entities): - """Test extract entities function with variables and entities stuff.""" - hass.states.async_set("input_boolean.switch", "on") - assert ["input_boolean.switch"] == template.extract_entities( - hass, "{{ is_state('input_boolean.switch', 'off') }}", {} - ) - - assert ["input_boolean.switch"] == template.extract_entities( - hass, - "{{ is_state(trigger.entity_id, 'off') }}", - {"trigger": {"entity_id": "input_boolean.switch"}}, - ) - - assert MATCH_ALL == template.extract_entities( - hass, "{{ is_state(data, 'off') }}", {"data": "no_state"} - ) - - assert ["input_boolean.switch"] == template.extract_entities( - hass, "{{ is_state(data, 'off') }}", {"data": "input_boolean.switch"} - ) - - assert ["input_boolean.switch"] == template.extract_entities( - hass, - "{{ is_state(trigger.entity_id, 'off') }}", - {"trigger": {"entity_id": "input_boolean.switch"}}, - ) - - hass.states.async_set("media_player.livingroom", "off") - assert {"media_player.livingroom"} == extract_entities( - hass, - "{{ is_state('media_player.' ~ where , 'playing') }}", - {"where": "livingroom"}, - ) - - -def test_extract_entities_domain_states_inner(hass, allow_extract_entities): - """Test extract entities function by domain.""" - hass.states.async_set("light.switch", "on") - hass.states.async_set("light.switch2", "on") - hass.states.async_set("light.switch3", "off") - - assert ( - set( - template.extract_entities( - hass, - "{{ states['light'] | selectattr('state','eq','on') | list | count > 0 }}", - {}, - ) - ) - == {"light.switch", "light.switch2", "light.switch3"} - ) - - -def test_extract_entities_domain_states_outer(hass, allow_extract_entities): - """Test extract entities function by domain.""" - hass.states.async_set("light.switch", "on") - hass.states.async_set("light.switch2", "on") - hass.states.async_set("light.switch3", "off") - - assert ( - set( - template.extract_entities( - hass, - "{{ states.light | selectattr('state','eq','off') | list | count > 0 }}", - {}, - ) - ) - == {"light.switch", "light.switch2", "light.switch3"} - ) - - -def test_extract_entities_domain_states_outer_with_group(hass, allow_extract_entities): - """Test extract entities function by domain.""" - hass.states.async_set("light.switch", "on") - hass.states.async_set("light.switch2", "on") - hass.states.async_set("light.switch3", "off") - hass.states.async_set("switch.pool_light", "off") - hass.states.async_set("group.lights", "off", {"entity_id": ["switch.pool_light"]}) - - assert ( - set( - template.extract_entities( - hass, - "{{ states.light | selectattr('entity_id', 'in', state_attr('group.lights', 'entity_id')) }}", - {}, - ) - ) - == {"light.switch", "light.switch2", "light.switch3", "group.lights"} - ) - - -def test_extract_entities_blocked_from_core_code(hass): - """Test extract entities is blocked from core code.""" - with pytest.raises(RuntimeError): - template.extract_entities( - hass, - "{{ states.light }}", - {}, - ) - - -def test_extract_entities_warns_and_logs_from_an_integration(hass, caplog): - """Test extract entities works from a custom_components with a log message.""" - - correct_frame = Mock( - filename="/config/custom_components/burncpu/light.py", - lineno="23", - line="self.light.is_on", - ) - with patch( - "homeassistant.helpers.frame.extract_stack", - return_value=[ - Mock( - filename="/home/dev/homeassistant/core.py", - lineno="23", - line="do_something()", - ), - correct_frame, - Mock( - filename="/home/dev/mdns/lights.py", - lineno="2", - line="something()", - ), - ], - ): - template.extract_entities( - hass, - "{{ states.light }}", - {}, - ) - - assert "custom_components/burncpu/light.py" in caplog.text - assert "23" in caplog.text - assert "self.light.is_on" in caplog.text - - def test_jinja_namespace(hass): """Test Jinja's namespace command can be used.""" test_template = template.Template( From 153f05afde793176e779e4214427d0f3883bf475 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 30 Oct 2020 00:13:49 +0100 Subject: [PATCH 17/43] Bump hatasmota to 0.0.25 (#42605) --- .../components/tasmota/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/tasmota/test_sensor.py | 91 +++++++++++-------- 4 files changed, 56 insertions(+), 41 deletions(-) diff --git a/homeassistant/components/tasmota/manifest.json b/homeassistant/components/tasmota/manifest.json index 991e38e6a95bf..b087e13ece0cf 100644 --- a/homeassistant/components/tasmota/manifest.json +++ b/homeassistant/components/tasmota/manifest.json @@ -3,7 +3,7 @@ "name": "Tasmota (beta)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tasmota", - "requirements": ["hatasmota==0.0.24"], + "requirements": ["hatasmota==0.0.25"], "dependencies": ["mqtt"], "mqtt": ["tasmota/discovery/#"], "codeowners": ["@emontnemery"] diff --git a/requirements_all.txt b/requirements_all.txt index 3b2b699e19ca8..8aa213c15d989 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -738,7 +738,7 @@ hass-nabucasa==0.37.1 hass_splunk==0.1.1 # homeassistant.components.tasmota -hatasmota==0.0.24 +hatasmota==0.0.25 # homeassistant.components.jewish_calendar hdate==0.9.12 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2e35de3182e4f..c214a487b676c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -373,7 +373,7 @@ hangups==0.4.11 hass-nabucasa==0.37.1 # homeassistant.components.tasmota -hatasmota==0.0.24 +hatasmota==0.0.25 # homeassistant.components.jewish_calendar hdate==0.9.12 diff --git a/tests/components/tasmota/test_sensor.py b/tests/components/tasmota/test_sensor.py index ab8498ed04cfe..e5d55b75a3ade 100644 --- a/tests/components/tasmota/test_sensor.py +++ b/tests/components/tasmota/test_sensor.py @@ -105,12 +105,12 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("sensor.dht11_temperature") + state = hass.states.get("sensor.tasmota_dht11_temperature") assert state.state == "unavailable" assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") - state = hass.states.get("sensor.dht11_temperature") + state = hass.states.get("sensor.tasmota_dht11_temperature") assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) @@ -118,7 +118,7 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): async_fire_mqtt_message( hass, "tasmota_49A3BC/tele/SENSOR", '{"DHT11":{"Temperature":20.5}}' ) - state = hass.states.get("sensor.dht11_temperature") + state = hass.states.get("sensor.tasmota_dht11_temperature") assert state.state == "20.5" # Test polled state update @@ -127,7 +127,7 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota): "tasmota_49A3BC/stat/STATUS8", '{"StatusSNS":{"DHT11":{"Temperature":20.0}}}', ) - state = hass.states.get("sensor.dht11_temperature") + state = hass.states.get("sensor.tasmota_dht11_temperature") assert state.state == "20.0" @@ -150,12 +150,12 @@ async def test_nested_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("sensor.tx23_speed_act") + state = hass.states.get("sensor.tasmota_tx23_speed_act") assert state.state == "unavailable" assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") - state = hass.states.get("sensor.tx23_speed_act") + state = hass.states.get("sensor.tasmota_tx23_speed_act") assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) @@ -163,7 +163,7 @@ async def test_nested_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): async_fire_mqtt_message( hass, "tasmota_49A3BC/tele/SENSOR", '{"TX23":{"Speed":{"Act":"12.3"}}}' ) - state = hass.states.get("sensor.tx23_speed_act") + state = hass.states.get("sensor.tasmota_tx23_speed_act") assert state.state == "12.3" # Test polled state update @@ -172,7 +172,7 @@ async def test_nested_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): "tasmota_49A3BC/stat/STATUS8", '{"StatusSNS":{"TX23":{"Speed":{"Act":"23.4"}}}}', ) - state = hass.states.get("sensor.tx23_speed_act") + state = hass.states.get("sensor.tasmota_tx23_speed_act") assert state.state == "23.4" @@ -195,12 +195,12 @@ async def test_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("sensor.energy_totaltariff_1") + state = hass.states.get("sensor.tasmota_energy_totaltariff_1") assert state.state == "unavailable" assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") - state = hass.states.get("sensor.energy_totaltariff_1") + state = hass.states.get("sensor.tasmota_energy_totaltariff_1") assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) @@ -208,7 +208,7 @@ async def test_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): async_fire_mqtt_message( hass, "tasmota_49A3BC/tele/SENSOR", '{"ENERGY":{"TotalTariff":[1.2,3.4]}}' ) - state = hass.states.get("sensor.energy_totaltariff_1") + state = hass.states.get("sensor.tasmota_energy_totaltariff_1") assert state.state == "3.4" # Test polled state update @@ -217,7 +217,7 @@ async def test_indexed_sensor_state_via_mqtt(hass, mqtt_mock, setup_tasmota): "tasmota_49A3BC/stat/STATUS8", '{"StatusSNS":{"ENERGY":{"TotalTariff":[5.6,7.8]}}}', ) - state = hass.states.get("sensor.energy_totaltariff_1") + state = hass.states.get("sensor.tasmota_energy_totaltariff_1") assert state.state == "7.8" @@ -297,15 +297,15 @@ async def test_attributes(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("sensor.dht11_temperature") + state = hass.states.get("sensor.tasmota_dht11_temperature") assert state.attributes.get("device_class") == "temperature" - assert state.attributes.get("friendly_name") == "DHT11 Temperature" + assert state.attributes.get("friendly_name") == "Tasmota DHT11 Temperature" assert state.attributes.get("icon") is None assert state.attributes.get("unit_of_measurement") == "C" - state = hass.states.get("sensor.beer_CarbonDioxide") + state = hass.states.get("sensor.tasmota_beer_CarbonDioxide") assert state.attributes.get("device_class") is None - assert state.attributes.get("friendly_name") == "Beer CarbonDioxide" + assert state.attributes.get("friendly_name") == "Tasmota Beer CarbonDioxide" assert state.attributes.get("icon") == "mdi:molecule-co2" assert state.attributes.get("unit_of_measurement") == "ppm" @@ -329,15 +329,15 @@ async def test_nested_sensor_attributes(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("sensor.tx23_speed_act") + state = hass.states.get("sensor.tasmota_tx23_speed_act") assert state.attributes.get("device_class") is None - assert state.attributes.get("friendly_name") == "TX23 Speed Act" + assert state.attributes.get("friendly_name") == "Tasmota TX23 Speed Act" assert state.attributes.get("icon") is None assert state.attributes.get("unit_of_measurement") == "km/h" - state = hass.states.get("sensor.tx23_dir_avg") + state = hass.states.get("sensor.tasmota_tx23_dir_avg") assert state.attributes.get("device_class") is None - assert state.attributes.get("friendly_name") == "TX23 Dir Avg" + assert state.attributes.get("friendly_name") == "Tasmota TX23 Dir Avg" assert state.attributes.get("icon") is None assert state.attributes.get("unit_of_measurement") == " " @@ -367,15 +367,15 @@ async def test_indexed_sensor_attributes(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("sensor.dummy1_temperature_0") + state = hass.states.get("sensor.tasmota_dummy1_temperature_0") assert state.attributes.get("device_class") == "temperature" - assert state.attributes.get("friendly_name") == "Dummy1 Temperature 0" + assert state.attributes.get("friendly_name") == "Tasmota Dummy1 Temperature 0" assert state.attributes.get("icon") is None assert state.attributes.get("unit_of_measurement") == "C" - state = hass.states.get("sensor.dummy2_carbondioxide_1") + state = hass.states.get("sensor.tasmota_dummy2_carbondioxide_1") assert state.attributes.get("device_class") is None - assert state.attributes.get("friendly_name") == "Dummy2 CarbonDioxide 1" + assert state.attributes.get("friendly_name") == "Tasmota Dummy2 CarbonDioxide 1" assert state.attributes.get("icon") == "mdi:molecule-co2" assert state.attributes.get("unit_of_measurement") == "ppm" @@ -396,15 +396,15 @@ async def test_enable_status_sensor(hass, mqtt_mock, setup_tasmota): await hass.async_block_till_done() await hass.async_block_till_done() - state = hass.states.get("sensor.tasmota_status") + state = hass.states.get("sensor.tasmota_signal") assert state is None - entry = entity_reg.async_get("sensor.tasmota_status") + entry = entity_reg.async_get("sensor.tasmota_signal") assert entry.disabled assert entry.disabled_by == "integration" # Enable the status sensor updated_entry = entity_reg.async_update_entity( - "sensor.tasmota_status", disabled_by=None + "sensor.tasmota_signal", disabled_by=None ) assert updated_entry != entry assert updated_entry.disabled is False @@ -428,12 +428,12 @@ async def test_enable_status_sensor(hass, mqtt_mock, setup_tasmota): ) await hass.async_block_till_done() - state = hass.states.get("sensor.tasmota_status") + state = hass.states.get("sensor.tasmota_signal") assert state.state == "unavailable" assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online") - state = hass.states.get("sensor.tasmota_status") + state = hass.states.get("sensor.tasmota_signal") assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) @@ -451,7 +451,7 @@ async def test_availability_when_connection_lost( sensor.DOMAIN, config, sensor_config, - "dht11_temperature", + "tasmota_dht11_temperature", ) @@ -460,7 +460,12 @@ async def test_availability(hass, mqtt_mock, setup_tasmota): config = copy.deepcopy(DEFAULT_CONFIG) sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG) await help_test_availability( - hass, mqtt_mock, sensor.DOMAIN, config, sensor_config, "dht11_temperature" + hass, + mqtt_mock, + sensor.DOMAIN, + config, + sensor_config, + "tasmota_dht11_temperature", ) @@ -469,7 +474,12 @@ async def test_availability_discovery_update(hass, mqtt_mock, setup_tasmota): config = copy.deepcopy(DEFAULT_CONFIG) sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG) await help_test_availability_discovery_update( - hass, mqtt_mock, sensor.DOMAIN, config, sensor_config, "dht11_temperature" + hass, + mqtt_mock, + sensor.DOMAIN, + config, + sensor_config, + "tasmota_dht11_temperature", ) @@ -506,8 +516,8 @@ async def test_discovery_removal_sensor(hass, mqtt_mock, caplog, setup_tasmota): config, sensor_config1, {}, - "dht11_temperature", - "DHT11 Temperature", + "tasmota_dht11_temperature", + "Tasmota DHT11 Temperature", ) @@ -528,8 +538,8 @@ async def test_discovery_update_unchanged_sensor( config, discovery_update, sensor_config, - "dht11_temperature", - "DHT11 Temperature", + "tasmota_dht11_temperature", + "Tasmota DHT11 Temperature", ) @@ -559,7 +569,7 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock, setup_tasmota): config, topics, sensor_config, - "dht11_temperature", + "tasmota_dht11_temperature", ) @@ -568,5 +578,10 @@ async def test_entity_id_update_discovery_update(hass, mqtt_mock, setup_tasmota) config = copy.deepcopy(DEFAULT_CONFIG) sensor_config = copy.deepcopy(DEFAULT_SENSOR_CONFIG) await help_test_entity_id_update_discovery_update( - hass, mqtt_mock, sensor.DOMAIN, config, sensor_config, "dht11_temperature" + hass, + mqtt_mock, + sensor.DOMAIN, + config, + sensor_config, + "tasmota_dht11_temperature", ) From 25ac0d2f6e630598da9458bcb77104019dae315b Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 30 Oct 2020 00:14:07 +0100 Subject: [PATCH 18/43] Update frontend to 20201021.4 (#42590) --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index ee27bb08d748b..0957c6fd7765c 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -2,7 +2,7 @@ "domain": "frontend", "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", - "requirements": ["home-assistant-frontend==20201021.3"], + "requirements": ["home-assistant-frontend==20201021.4"], "dependencies": [ "api", "auth", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index c53a35213523a..5a7c5be08829e 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -13,7 +13,7 @@ defusedxml==0.6.0 distro==1.5.0 emoji==0.5.4 hass-nabucasa==0.37.1 -home-assistant-frontend==20201021.3 +home-assistant-frontend==20201021.4 httpx==0.16.1 importlib-metadata==1.6.0;python_version<'3.8' jinja2>=2.11.2 diff --git a/requirements_all.txt b/requirements_all.txt index 8aa213c15d989..6741a31761aa1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -765,7 +765,7 @@ hole==0.5.1 holidays==0.10.3 # homeassistant.components.frontend -home-assistant-frontend==20201021.3 +home-assistant-frontend==20201021.4 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c214a487b676c..20f3b18492e29 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -391,7 +391,7 @@ hole==0.5.1 holidays==0.10.3 # homeassistant.components.frontend -home-assistant-frontend==20201021.3 +home-assistant-frontend==20201021.4 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 From c403534ae1175c3a2c12ca974d7f82f787569fd7 Mon Sep 17 00:00:00 2001 From: Andreas Billmeier Date: Fri, 30 Oct 2020 00:31:54 +0100 Subject: [PATCH 19/43] Fix inexact version of pylacrosse (#42610) * fix inexact version for pylacrosse * https://github.com/hthiery/python-lacrosse/releases * https://pypi.org/project/pylacrosse/#history * Update requirements_all.txt --- homeassistant/components/lacrosse/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/lacrosse/manifest.json b/homeassistant/components/lacrosse/manifest.json index f31d4b9fea5ea..a6517a2768b44 100644 --- a/homeassistant/components/lacrosse/manifest.json +++ b/homeassistant/components/lacrosse/manifest.json @@ -2,6 +2,6 @@ "domain": "lacrosse", "name": "LaCrosse", "documentation": "https://www.home-assistant.io/integrations/lacrosse", - "requirements": ["pylacrosse==0.4.0"], + "requirements": ["pylacrosse==0.4"], "codeowners": [] } diff --git a/requirements_all.txt b/requirements_all.txt index 6741a31761aa1..b4339b6c3587d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1470,7 +1470,7 @@ pykodi==0.2.1 pykwb==0.0.8 # homeassistant.components.lacrosse -pylacrosse==0.4.0 +pylacrosse==0.4 # homeassistant.components.lastfm pylast==3.3.0 From 3a11e2c4616337d5f963f9d487299c7eae8ea3f1 Mon Sep 17 00:00:00 2001 From: Clifford Roche Date: Thu, 29 Oct 2020 19:49:13 -0400 Subject: [PATCH 20/43] Update greeclimate to 0.9.2 (#42616) Fixes issue with erroneous await in UDP recv queue --- homeassistant/components/gree/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/gree/manifest.json b/homeassistant/components/gree/manifest.json index ea04eb12f5140..c5fb412f1d153 100644 --- a/homeassistant/components/gree/manifest.json +++ b/homeassistant/components/gree/manifest.json @@ -3,6 +3,6 @@ "name": "Gree Climate", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/gree", - "requirements": ["greeclimate==0.9.0"], + "requirements": ["greeclimate==0.9.2"], "codeowners": ["@cmroche"] } diff --git a/requirements_all.txt b/requirements_all.txt index b4339b6c3587d..f713ef221c3de 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -699,7 +699,7 @@ gpiozero==1.5.1 gps3==0.33.3 # homeassistant.components.gree -greeclimate==0.9.0 +greeclimate==0.9.2 # homeassistant.components.greeneye_monitor greeneye_monitor==2.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 20f3b18492e29..3c1ecc048e3f0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -355,7 +355,7 @@ google-cloud-pubsub==0.39.1 google-nest-sdm==0.1.9 # homeassistant.components.gree -greeclimate==0.9.0 +greeclimate==0.9.2 # homeassistant.components.griddy griddypower==0.1.0 From b9d04b9304447ac4b3519a085b9fc565740de46a Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Fri, 30 Oct 2020 00:02:45 +0000 Subject: [PATCH 21/43] [ci skip] Translation update --- .../advantage_air/translations/fr.json | 22 +++++++++ .../components/agent_dvr/translations/fr.json | 1 + .../components/airvisual/translations/fr.json | 9 +++- .../alarmdecoder/translations/fr.json | 1 + .../components/almond/translations/fr.json | 3 +- .../ambiclimate/translations/fr.json | 2 + .../components/arcam_fmj/translations/fr.json | 1 + .../components/atag/translations/fr.json | 1 + .../components/august/translations/fr.json | 3 +- .../components/awair/translations/fr.json | 2 + .../components/axis/translations/fr.json | 4 +- .../azure_devops/translations/fr.json | 2 + .../components/braviatv/translations/fr.json | 3 ++ .../components/broadlink/translations/fr.json | 1 + .../cloudflare/translations/fr.json | 35 ++++++++++++++ .../components/cover/translations/ru.json | 4 +- .../components/daikin/translations/fr.json | 6 ++- .../components/deconz/translations/fr.json | 1 + .../components/deconz/translations/ru.json | 20 ++++---- .../components/denonavr/translations/fr.json | 1 + .../components/dexcom/translations/ca.json | 1 + .../components/dexcom/translations/es.json | 1 + .../components/dexcom/translations/fr.json | 1 + .../components/dexcom/translations/pl.json | 1 + .../components/ecobee/translations/fr.json | 3 +- .../emulated_roku/translations/fr.json | 1 + .../components/esphome/translations/fr.json | 1 + .../flunearyou/translations/fr.json | 3 +- .../forked_daapd/translations/fr.json | 1 + .../components/fritzbox/translations/fr.json | 4 +- .../geonetnz_volcano/translations/fr.json | 3 ++ .../components/goalzero/translations/fr.json | 5 +- .../components/gpslogger/translations/cs.json | 2 +- .../components/gree/translations/fr.json | 14 ++++++ .../components/heos/translations/fr.json | 4 +- .../components/homekit/translations/fr.json | 11 ++++- .../homematicip_cloud/translations/cs.json | 2 +- .../components/hue/translations/ru.json | 16 +++---- .../components/iaqualink/translations/fr.json | 4 +- .../components/icloud/translations/fr.json | 10 +++- .../components/ipp/translations/fr.json | 2 + .../components/life360/translations/ca.json | 3 ++ .../components/life360/translations/es.json | 3 ++ .../components/life360/translations/fr.json | 5 ++ .../components/life360/translations/pl.json | 3 ++ .../life360/translations/zh-Hant.json | 3 ++ .../components/locative/translations/cs.json | 2 +- .../logi_circle/translations/fr.json | 6 ++- .../components/luftdaten/translations/es.json | 2 + .../components/luftdaten/translations/fr.json | 2 + .../components/mill/translations/fr.json | 1 + .../components/mqtt/translations/ru.json | 10 ++-- .../components/nest/translations/cs.json | 2 +- .../components/nest/translations/es.json | 1 + .../components/nest/translations/fr.json | 12 ++++- .../nightscout/translations/fr.json | 4 +- .../components/notion/translations/fr.json | 1 + .../components/omnilogic/translations/fr.json | 12 ++++- .../components/onewire/translations/es.json | 24 ++++++++++ .../components/onewire/translations/fr.json | 26 ++++++++++ .../components/onvif/translations/fr.json | 1 + .../opentherm_gw/translations/es.json | 1 + .../opentherm_gw/translations/fr.json | 1 + .../ovo_energy/translations/fr.json | 4 +- .../panasonic_viera/translations/fr.json | 2 + .../components/plex/translations/fr.json | 1 + .../components/plugwise/translations/fr.json | 10 ++++ .../components/poolsense/translations/fr.json | 2 +- .../components/profiler/translations/fr.json | 12 +++++ .../components/ps4/translations/fr.json | 2 + .../rainmachine/translations/ca.json | 10 ++++ .../rainmachine/translations/cs.json | 7 +++ .../rainmachine/translations/es.json | 10 ++++ .../rainmachine/translations/fr.json | 11 +++++ .../rainmachine/translations/no.json | 10 ++++ .../rainmachine/translations/pl.json | 10 ++++ .../rainmachine/translations/ru.json | 10 ++++ .../rainmachine/translations/zh-Hant.json | 10 ++++ .../components/rfxtrx/translations/fr.json | 47 ++++++++++++++++++- .../ruckus_unleashed/translations/fr.json | 22 +++++++++ .../components/samsungtv/translations/fr.json | 1 + .../components/sharkiq/translations/fr.json | 1 + .../components/shelly/translations/fr.json | 6 ++- .../simplisafe/translations/fr.json | 1 + .../components/smappee/translations/fr.json | 1 + .../components/smarthab/translations/fr.json | 2 + .../components/sonarr/translations/fr.json | 2 + .../components/starline/translations/cs.json | 2 +- .../synology_dsm/translations/fr.json | 2 + .../components/tasmota/translations/fr.json | 22 +++++++++ .../tellduslive/translations/fr.json | 3 +- .../components/tesla/translations/fr.json | 4 ++ .../components/tibber/translations/fr.json | 1 + .../components/tile/translations/fr.json | 1 + .../transmission/translations/fr.json | 1 + .../components/tuya/translations/ca.json | 36 ++++++++++++++ .../components/tuya/translations/es.json | 33 +++++++++++++ .../components/tuya/translations/fr.json | 41 +++++++++++++++- .../components/tuya/translations/pl.json | 36 ++++++++++++++ .../twentemilieu/translations/fr.json | 4 +- .../components/twilio/translations/ca.json | 2 +- .../components/twilio/translations/cs.json | 2 +- .../components/twilio/translations/en.json | 2 +- .../components/twilio/translations/no.json | 2 +- .../components/twilio/translations/ru.json | 2 +- .../twilio/translations/zh-Hant.json | 2 +- .../components/upb/translations/fr.json | 3 +- .../components/upcloud/translations/fr.json | 25 ++++++++++ .../components/velbus/translations/fr.json | 1 + .../components/vesync/translations/fr.json | 4 +- .../water_heater/translations/fr.json | 8 ++++ .../components/withings/translations/fr.json | 2 + .../components/xbox/translations/fr.json | 18 +++++++ .../xiaomi_miio/translations/fr.json | 1 + .../components/zha/translations/ru.json | 22 ++++----- .../components/zwave/translations/fr.json | 3 +- 116 files changed, 740 insertions(+), 76 deletions(-) create mode 100644 homeassistant/components/advantage_air/translations/fr.json create mode 100644 homeassistant/components/cloudflare/translations/fr.json create mode 100644 homeassistant/components/gree/translations/fr.json create mode 100644 homeassistant/components/onewire/translations/es.json create mode 100644 homeassistant/components/onewire/translations/fr.json create mode 100644 homeassistant/components/profiler/translations/fr.json create mode 100644 homeassistant/components/ruckus_unleashed/translations/fr.json create mode 100644 homeassistant/components/tasmota/translations/fr.json create mode 100644 homeassistant/components/upcloud/translations/fr.json create mode 100644 homeassistant/components/water_heater/translations/fr.json create mode 100644 homeassistant/components/xbox/translations/fr.json diff --git a/homeassistant/components/advantage_air/translations/fr.json b/homeassistant/components/advantage_air/translations/fr.json new file mode 100644 index 0000000000000..c55a7c8f21a70 --- /dev/null +++ b/homeassistant/components/advantage_air/translations/fr.json @@ -0,0 +1,22 @@ +{ + "config": { + "abort": { + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + }, + "error": { + "cannot_connect": "\u00c9chec de connexion" + }, + "flow_title": "Configuration d\u2019Advantage Air", + "step": { + "user": { + "data": { + "ip_address": "Adresse IP", + "port": "Port" + }, + "description": "Connectez-vous \u00e0 l'API de votre tablette murale Advantage Air.", + "title": "Connecter" + } + } + }, + "title": "Advantage Air" +} \ No newline at end of file diff --git a/homeassistant/components/agent_dvr/translations/fr.json b/homeassistant/components/agent_dvr/translations/fr.json index a16ad59afee4a..dc08270affb5a 100644 --- a/homeassistant/components/agent_dvr/translations/fr.json +++ b/homeassistant/components/agent_dvr/translations/fr.json @@ -5,6 +5,7 @@ }, "error": { "already_in_progress": "La configuration de l'appareil est d\u00e9j\u00e0 en cours.", + "cannot_connect": "\u00c9chec de connexion", "device_unavailable": "L'appareil n'est pas disponible" }, "step": { diff --git a/homeassistant/components/airvisual/translations/fr.json b/homeassistant/components/airvisual/translations/fr.json index 55247360306fe..4174dab6550bf 100644 --- a/homeassistant/components/airvisual/translations/fr.json +++ b/homeassistant/components/airvisual/translations/fr.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "Cette cl\u00e9 API est d\u00e9j\u00e0 utilis\u00e9e." + "already_configured": "Cette cl\u00e9 API est d\u00e9j\u00e0 utilis\u00e9e.", + "reauth_successful": "La r\u00e9-authentification a r\u00e9ussi" }, "error": { "cannot_connect": "\u00c9chec de connexion", @@ -27,6 +28,12 @@ "description": "Surveillez une unit\u00e9 AirVisual personnelle. Le mot de passe peut \u00eatre r\u00e9cup\u00e9r\u00e9 dans l'interface utilisateur de l'unit\u00e9.", "title": "Configurer un AirVisual Node/Pro" }, + "reauth_confirm": { + "data": { + "api_key": "Cl\u00e9 d'API" + }, + "title": "R\u00e9-authentifier AirVisual" + }, "user": { "data": { "cloud_api": "Localisation g\u00e9ographique", diff --git a/homeassistant/components/alarmdecoder/translations/fr.json b/homeassistant/components/alarmdecoder/translations/fr.json index c48cf00cdede4..4ffe12e69ee17 100644 --- a/homeassistant/components/alarmdecoder/translations/fr.json +++ b/homeassistant/components/alarmdecoder/translations/fr.json @@ -7,6 +7,7 @@ "default": "Connexion r\u00e9ussie \u00e0 AlarmDecoder." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "service_unavailable": "\u00c9chec de connexion" }, "step": { diff --git a/homeassistant/components/almond/translations/fr.json b/homeassistant/components/almond/translations/fr.json index 7b7f4bff1e4be..b19745ddc7251 100644 --- a/homeassistant/components/almond/translations/fr.json +++ b/homeassistant/components/almond/translations/fr.json @@ -4,7 +4,8 @@ "already_setup": "Vous ne pouvez configurer qu'un seul compte Almond", "cannot_connect": "Impossible de se connecter au serveur Almond", "missing_configuration": "Veuillez consulter la documentation pour savoir comment configurer Almond.", - "no_url_available": "Aucune URL disponible. Pour plus d'informations sur cette erreur, [consultez la section d'aide] ( {docs_url} )" + "no_url_available": "Aucune URL disponible. Pour plus d'informations sur cette erreur, [consultez la section d'aide] ( {docs_url} )", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "step": { "hassio_confirm": { diff --git a/homeassistant/components/ambiclimate/translations/fr.json b/homeassistant/components/ambiclimate/translations/fr.json index 879a02d38d00c..ea2cafe8525be 100644 --- a/homeassistant/components/ambiclimate/translations/fr.json +++ b/homeassistant/components/ambiclimate/translations/fr.json @@ -2,8 +2,10 @@ "config": { "abort": { "access_token": "Erreur inconnue lors de la g\u00e9n\u00e9ration d'un jeton d'acc\u00e8s.", + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "already_configured_account": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "already_setup": "Le compte Ambiclimate est configur\u00e9.", + "missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation.", "no_config": "Vous devez configurer Ambiclimate avant de pouvoir vous authentifier aupr\u00e8s de celui-ci. [Veuillez lire les instructions] (https://www.home-assistant.io/components/ambiclimate/).", "oauth2_missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation." }, diff --git a/homeassistant/components/arcam_fmj/translations/fr.json b/homeassistant/components/arcam_fmj/translations/fr.json index 6e191c204d813..f42c04241805f 100644 --- a/homeassistant/components/arcam_fmj/translations/fr.json +++ b/homeassistant/components/arcam_fmj/translations/fr.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "L'appareil \u00e9tait d\u00e9j\u00e0 configur\u00e9.", "already_in_progress": "Le flux de configuration de l'appareil est d\u00e9j\u00e0 en cours.", + "cannot_connect": "\u00c9chec de connexion", "unable_to_connect": "Impossible de se connecter au p\u00e9riph\u00e9rique." }, "error": { diff --git a/homeassistant/components/atag/translations/fr.json b/homeassistant/components/atag/translations/fr.json index 6652d1508a706..7790585bff145 100644 --- a/homeassistant/components/atag/translations/fr.json +++ b/homeassistant/components/atag/translations/fr.json @@ -4,6 +4,7 @@ "already_configured": "Un seul appareil Atag peut \u00eatre ajout\u00e9 \u00e0 Home Assistant" }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_error": "Impossible de se connecter, veuillez r\u00e9essayer", "unauthorized": "Pairage refus\u00e9, v\u00e9rifiez la demande d'authentification de l'appareil" }, diff --git a/homeassistant/components/august/translations/fr.json b/homeassistant/components/august/translations/fr.json index 752b7dc371265..82568b681fdf4 100644 --- a/homeassistant/components/august/translations/fr.json +++ b/homeassistant/components/august/translations/fr.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "Le compte est d\u00e9j\u00e0 configur\u00e9" + "already_configured": "Le compte est d\u00e9j\u00e0 configur\u00e9", + "reauth_successful": "La r\u00e9-authentification a r\u00e9ussi" }, "error": { "cannot_connect": "Impossible de se connecter, veuillez r\u00e9essayer", diff --git a/homeassistant/components/awair/translations/fr.json b/homeassistant/components/awair/translations/fr.json index e5d7a277b77f5..158da30f86a4d 100644 --- a/homeassistant/components/awair/translations/fr.json +++ b/homeassistant/components/awair/translations/fr.json @@ -3,10 +3,12 @@ "abort": { "already_configured": "Le compte est d\u00e9j\u00e0 configur\u00e9", "no_devices": "Pas d'appareil trouv\u00e9 sur le r\u00e9seau", + "no_devices_found": "Aucun appareil trouv\u00e9 sur le r\u00e9seau", "reauth_successful": "Jeton d'acc\u00e8s mis \u00e0 jour avec succ\u00e8s" }, "error": { "auth": "Jeton d'acc\u00e8s invalide", + "invalid_access_token": "Jeton d'acc\u00e8s non valide", "unknown": "Erreur d'API Awair inconnue." }, "step": { diff --git a/homeassistant/components/axis/translations/fr.json b/homeassistant/components/axis/translations/fr.json index 7ffa3d9dbcf2a..9398ef1932605 100644 --- a/homeassistant/components/axis/translations/fr.json +++ b/homeassistant/components/axis/translations/fr.json @@ -9,8 +9,10 @@ "error": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", "already_in_progress": "Le flux de configuration de l'appareil est d\u00e9j\u00e0 en cours.", + "cannot_connect": "\u00c9chec de connexion", "device_unavailable": "L'appareil n'est pas disponible", - "faulty_credentials": "Mauvaises informations d'identification de l'utilisateur" + "faulty_credentials": "Mauvaises informations d'identification de l'utilisateur", + "invalid_auth": "Authentification invalide" }, "flow_title": "Appareil Axis: {name} ( {host} )", "step": { diff --git a/homeassistant/components/azure_devops/translations/fr.json b/homeassistant/components/azure_devops/translations/fr.json index 528c76767ea89..5811fd38632f0 100644 --- a/homeassistant/components/azure_devops/translations/fr.json +++ b/homeassistant/components/azure_devops/translations/fr.json @@ -6,7 +6,9 @@ }, "error": { "authorization_error": "Erreur d'autorisation. V\u00e9rifiez que vous avez acc\u00e8s au projet et que vous disposez des informations d'identification correctes.", + "cannot_connect": "\u00c9chec de connexion", "connection_error": "Impossible de se connecter \u00e0 Azure DevOps.", + "invalid_auth": "Authentification invalide", "project_error": "Impossible d'obtenir les informations sur le projet." }, "flow_title": "Azure DevOps: {project_url}", diff --git a/homeassistant/components/braviatv/translations/fr.json b/homeassistant/components/braviatv/translations/fr.json index b0bb45d965475..68988b1fbfeb9 100644 --- a/homeassistant/components/braviatv/translations/fr.json +++ b/homeassistant/components/braviatv/translations/fr.json @@ -11,6 +11,9 @@ }, "step": { "authorize": { + "data": { + "pin": "Code PIN" + }, "description": "Saisissez le code PIN affich\u00e9 sur le t\u00e9l\u00e9viseur Sony Bravia. \n\nSi le code PIN n'est pas affich\u00e9, vous devez d\u00e9senregistrer Home Assistant de votre t\u00e9l\u00e9viseur, allez dans: Param\u00e8tres - > R\u00e9seau - > Param\u00e8tres de l'appareil distant - > Annuler l'enregistrement de l'appareil distant.", "title": "Autoriser Sony Bravia TV" }, diff --git a/homeassistant/components/broadlink/translations/fr.json b/homeassistant/components/broadlink/translations/fr.json index bb3af76ff95c5..1d80059fb7a14 100644 --- a/homeassistant/components/broadlink/translations/fr.json +++ b/homeassistant/components/broadlink/translations/fr.json @@ -10,6 +10,7 @@ }, "error": { "cannot_connect": "\u00c9chec de connexion", + "invalid_host": "Nom d'h\u00f4te ou adresse IP non valide", "unknown": "Erreur inattendue" }, "flow_title": "{name} ( {model} \u00e0 {host} )", diff --git a/homeassistant/components/cloudflare/translations/fr.json b/homeassistant/components/cloudflare/translations/fr.json new file mode 100644 index 0000000000000..be6d4c3e2b3b6 --- /dev/null +++ b/homeassistant/components/cloudflare/translations/fr.json @@ -0,0 +1,35 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible.", + "unknown": "Erreur inattendue" + }, + "error": { + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide", + "invalid_zone": "Zone invalide" + }, + "flow_title": "Cloudflare: {name}", + "step": { + "records": { + "data": { + "records": "Enregistrements" + }, + "title": "Choisissez les enregistrements \u00e0 mettre \u00e0 jour" + }, + "user": { + "data": { + "api_token": "Jeton d'API" + }, + "description": "Cette int\u00e9gration n\u00e9cessite un jeton API cr\u00e9\u00e9 avec les autorisations Zone: Zone: Lecture et Zone: DNS: Modifiez pour toutes les zones de votre compte.", + "title": "Connectez-vous \u00e0 Cloudflare" + }, + "zone": { + "data": { + "zone": "Zone" + }, + "title": "Choisissez la zone \u00e0 mettre \u00e0 jour" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cover/translations/ru.json b/homeassistant/components/cover/translations/ru.json index 21bbe7e2c4dbf..e23296940b7ce 100644 --- a/homeassistant/components/cover/translations/ru.json +++ b/homeassistant/components/cover/translations/ru.json @@ -15,7 +15,7 @@ "is_open": "{entity_name} \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438", "is_opening": "{entity_name} \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f", "is_position": "{entity_name} \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438", - "is_tilt_position": "{entity_name} \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043d\u0430\u043a\u043b\u043e\u043d\u0430" + "is_tilt_position": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \"{entity_name}\" \u0438\u043c\u0435\u0435\u0442 \u043d\u0430\u043a\u043b\u043e\u043d \u043b\u0430\u043c\u0435\u043b\u0435\u0439" }, "trigger_type": { "closed": "{entity_name} \u0437\u0430\u043a\u0440\u044b\u0442\u043e", @@ -23,7 +23,7 @@ "opened": "{entity_name} \u043e\u0442\u043a\u0440\u044b\u0442\u043e", "opening": "{entity_name} \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f", "position": "{entity_name} \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435", - "tilt_position": "{entity_name} \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u043d\u0430\u043a\u043b\u043e\u043d" + "tilt_position": "{entity_name} \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u043d\u0430\u043a\u043b\u043e\u043d \u043b\u0430\u043c\u0435\u043b\u0435\u0439" } }, "state": { diff --git a/homeassistant/components/daikin/translations/fr.json b/homeassistant/components/daikin/translations/fr.json index 75f3260a86cb5..955c33d741a4e 100644 --- a/homeassistant/components/daikin/translations/fr.json +++ b/homeassistant/components/daikin/translations/fr.json @@ -5,13 +5,17 @@ "cannot_connect": "\u00c9chec de connexion" }, "error": { + "cannot_connect": "\u00c9chec de connexion", "device_fail": "Erreur inattendue", "device_timeout": "Echec de la connexion", - "forbidden": "Authentification invalide" + "forbidden": "Authentification invalide", + "invalid_auth": "Authentification invalide", + "unknown": "Erreur inattendue" }, "step": { "user": { "data": { + "api_key": "Cl\u00e9 d'API", "host": "Nom d'h\u00f4te ou adresse IP", "key": "Cl\u00e9 d'authentification (utilis\u00e9e uniquement par les appareils BRP072C/Zena)", "password": "Mot de passe de l'appareil (utilis\u00e9 uniquement par les appareils SKYFi)" diff --git a/homeassistant/components/deconz/translations/fr.json b/homeassistant/components/deconz/translations/fr.json index 2704951db5cd9..860c921615771 100644 --- a/homeassistant/components/deconz/translations/fr.json +++ b/homeassistant/components/deconz/translations/fr.json @@ -67,6 +67,7 @@ "remote_button_quadruple_press": "Quadruple clic sur le bouton \" {subtype} \"", "remote_button_quintuple_press": "Quintuple clic sur le bouton \" {subtype} \"", "remote_button_rotated": "Bouton \"{subtype}\" tourn\u00e9", + "remote_button_rotated_fast": "Bouton pivot\u00e9 rapidement \" {subtype} \"", "remote_button_rotation_stopped": "La rotation du bouton \" {subtype} \" s'est arr\u00eat\u00e9e", "remote_button_short_press": "Bouton \"{subtype}\" appuy\u00e9", "remote_button_short_release": "Bouton \"{subtype}\" rel\u00e2ch\u00e9", diff --git a/homeassistant/components/deconz/translations/ru.json b/homeassistant/components/deconz/translations/ru.json index 92cb2deb27c07..d4086d1cb9d97 100644 --- a/homeassistant/components/deconz/translations/ru.json +++ b/homeassistant/components/deconz/translations/ru.json @@ -61,17 +61,17 @@ }, "trigger_type": { "remote_awakened": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u043b\u0438", - "remote_button_double_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430", - "remote_button_long_press": "{subtype} \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e \u043d\u0430\u0436\u0430\u0442\u0430", - "remote_button_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", - "remote_button_quadruple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430", - "remote_button_quintuple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437", - "remote_button_rotated": "{subtype} \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f", - "remote_button_rotated_fast": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f", - "remote_button_rotation_stopped": "{subtype} \u043f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u043b\u0430 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435", + "remote_button_double_press": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430", + "remote_button_long_press": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u0434\u043e\u043b\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0430", + "remote_button_long_release": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "remote_button_quadruple_press": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430", + "remote_button_quintuple_press": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437", + "remote_button_rotated": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0430", + "remote_button_rotated_fast": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0430 \u0431\u044b\u0441\u0442\u0440\u043e", + "remote_button_rotation_stopped": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u043b\u0430 \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435", "remote_button_short_press": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430", - "remote_button_short_release": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430", - "remote_button_triple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0442\u0440\u0438 \u0440\u0430\u0437\u0430", + "remote_button_short_release": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "remote_button_triple_press": "\u041a\u043d\u043e\u043f\u043a\u0430 \"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u0442\u0440\u0438 \u0440\u0430\u0437\u0430", "remote_double_tap": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c {subtype} \u043f\u043e\u0441\u0442\u0443\u0447\u0430\u043b\u0438 \u0434\u0432\u0430\u0436\u0434\u044b", "remote_double_tap_any_side": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u043f\u043e\u0441\u0442\u0443\u0447\u0430\u043b\u0438 \u0434\u0432\u0430\u0436\u0434\u044b", "remote_falling": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u043c \u043f\u0430\u0434\u0435\u043d\u0438\u0438", diff --git a/homeassistant/components/denonavr/translations/fr.json b/homeassistant/components/denonavr/translations/fr.json index 09c7abf93ac5a..956c3be8a1822 100644 --- a/homeassistant/components/denonavr/translations/fr.json +++ b/homeassistant/components/denonavr/translations/fr.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Appareil d\u00e9j\u00e0 configur\u00e9", "already_in_progress": "Le flux de configuration pour ce Denon AVR est d\u00e9j\u00e0 en cours", + "cannot_connect": "\u00c9chec de la connexion, veuillez r\u00e9essayer, d\u00e9brancher l'alimentation secteur et les c\u00e2bles ethernet et les reconnecter peut aider", "connection_error": "\u00c9chec de la connexion, veuillez r\u00e9essayer, d\u00e9brancher l'alimentation secteur et les c\u00e2bles ethernet et les reconnecter peut aider", "not_denonavr_manufacturer": "Ce n'est pas un r\u00e9cepteur r\u00e9seau Denon AVR, le fabricant d\u00e9couvert ne correspondait pas", "not_denonavr_missing": "Ce n'est pas un r\u00e9cepteur r\u00e9seau Denon AVR, les informations d\u00e9couvertes ne sont pas compl\u00e8tes" diff --git a/homeassistant/components/dexcom/translations/ca.json b/homeassistant/components/dexcom/translations/ca.json index b92d6b7ab06e5..8a3eb225dc817 100644 --- a/homeassistant/components/dexcom/translations/ca.json +++ b/homeassistant/components/dexcom/translations/ca.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "El compte ja ha estat configurat", "already_configured_account": "El compte ja ha estat configurat" }, "error": { diff --git a/homeassistant/components/dexcom/translations/es.json b/homeassistant/components/dexcom/translations/es.json index 95f80f558b3d2..cc6b353483c17 100644 --- a/homeassistant/components/dexcom/translations/es.json +++ b/homeassistant/components/dexcom/translations/es.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "La cuenta ya ha sido configurada", "already_configured_account": "La cuenta ya ha sido configurada" }, "error": { diff --git a/homeassistant/components/dexcom/translations/fr.json b/homeassistant/components/dexcom/translations/fr.json index 5ad342c22ffc9..ceadd74922d36 100644 --- a/homeassistant/components/dexcom/translations/fr.json +++ b/homeassistant/components/dexcom/translations/fr.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "already_configured_account": "Le compte est d\u00e9j\u00e0 configur\u00e9" }, "error": { diff --git a/homeassistant/components/dexcom/translations/pl.json b/homeassistant/components/dexcom/translations/pl.json index 28203376a3971..361a9eaacbb02 100644 --- a/homeassistant/components/dexcom/translations/pl.json +++ b/homeassistant/components/dexcom/translations/pl.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "Konto jest ju\u017c skonfigurowane", "already_configured_account": "Konto jest ju\u017c skonfigurowane" }, "error": { diff --git a/homeassistant/components/ecobee/translations/fr.json b/homeassistant/components/ecobee/translations/fr.json index 46e56ce8a16a4..51e09317df60b 100644 --- a/homeassistant/components/ecobee/translations/fr.json +++ b/homeassistant/components/ecobee/translations/fr.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "one_instance_only": "Cette int\u00e9gration ne prend actuellement en charge qu'une seule instance ecobee." + "one_instance_only": "Cette int\u00e9gration ne prend actuellement en charge qu'une seule instance ecobee.", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { "pin_request_failed": "Erreur lors de la demande du code PIN \u00e0 ecobee; veuillez v\u00e9rifier que la cl\u00e9 API est correcte.", diff --git a/homeassistant/components/emulated_roku/translations/fr.json b/homeassistant/components/emulated_roku/translations/fr.json index 56abe3465d93f..6edd795d8bedd 100644 --- a/homeassistant/components/emulated_roku/translations/fr.json +++ b/homeassistant/components/emulated_roku/translations/fr.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", "name_exists": "Ce nom est d\u00e9j\u00e0 utilis\u00e9" }, "step": { diff --git a/homeassistant/components/esphome/translations/fr.json b/homeassistant/components/esphome/translations/fr.json index 1a63d8083d724..d36a1e796d0d6 100644 --- a/homeassistant/components/esphome/translations/fr.json +++ b/homeassistant/components/esphome/translations/fr.json @@ -6,6 +6,7 @@ }, "error": { "connection_error": "Impossible de se connecter \u00e0 ESP. Assurez-vous que votre fichier YAML contient une ligne 'api:'.", + "invalid_auth": "Authentification invalide", "invalid_password": "Mot de passe invalide !", "resolve_error": "Impossible de r\u00e9soudre l'adresse de l'ESP. Si cette erreur persiste, veuillez d\u00e9finir une adresse IP statique: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, diff --git a/homeassistant/components/flunearyou/translations/fr.json b/homeassistant/components/flunearyou/translations/fr.json index 50300be55e12e..7388eb1a9c9f6 100644 --- a/homeassistant/components/flunearyou/translations/fr.json +++ b/homeassistant/components/flunearyou/translations/fr.json @@ -4,7 +4,8 @@ "already_configured": "Coordonn\u00e9es d\u00e9j\u00e0 enregistr\u00e9es" }, "error": { - "general_error": "Une erreur inconnue est survenue." + "general_error": "Une erreur inconnue est survenue.", + "unknown": "Erreur inattendue" }, "step": { "user": { diff --git a/homeassistant/components/forked_daapd/translations/fr.json b/homeassistant/components/forked_daapd/translations/fr.json index 03214f960accc..2e20c75d33f1e 100644 --- a/homeassistant/components/forked_daapd/translations/fr.json +++ b/homeassistant/components/forked_daapd/translations/fr.json @@ -5,6 +5,7 @@ "not_forked_daapd": "Le p\u00e9riph\u00e9rique n'est pas un serveur forked-daapd." }, "error": { + "forbidden": "Impossible de se connecter. Veuillez v\u00e9rifier vos autorisations r\u00e9seau forked-daapd.", "unknown_error": "Erreur inconnue", "websocket_not_enabled": "le socket web du serveur forked-daapd n'est pas activ\u00e9.", "wrong_host_or_port": "Impossible de se connecter. Veuillez v\u00e9rifier l'h\u00f4te et le port.", diff --git a/homeassistant/components/fritzbox/translations/fr.json b/homeassistant/components/fritzbox/translations/fr.json index 3bd90697596bf..ff2625b42c4a8 100644 --- a/homeassistant/components/fritzbox/translations/fr.json +++ b/homeassistant/components/fritzbox/translations/fr.json @@ -3,11 +3,13 @@ "abort": { "already_configured": "Cette AVM FRITZ!Box est d\u00e9j\u00e0 configur\u00e9e.", "already_in_progress": "Une configuration d'AVM FRITZ!Box est d\u00e9j\u00e0 en cours.", + "no_devices_found": "Aucun appareil trouv\u00e9 sur le r\u00e9seau", "not_found": "Aucune AVM FRITZ!Box support\u00e9e trouv\u00e9e sur le r\u00e9seau.", "not_supported": "Connect\u00e9 \u00e0 AVM FRITZ! Box mais impossible de contr\u00f4ler les appareils Smart Home." }, "error": { - "auth_failed": "Le nom d'utilisateur et/ou le mot de passe sont incorrects." + "auth_failed": "Le nom d'utilisateur et/ou le mot de passe sont incorrects.", + "invalid_auth": "Authentification invalide" }, "flow_title": "AVM FRITZ!Box : {name}", "step": { diff --git a/homeassistant/components/geonetnz_volcano/translations/fr.json b/homeassistant/components/geonetnz_volcano/translations/fr.json index 2692768910c8c..3f44e0f538033 100644 --- a/homeassistant/components/geonetnz_volcano/translations/fr.json +++ b/homeassistant/components/geonetnz_volcano/translations/fr.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "L'emplacement est d\u00e9j\u00e0 configur\u00e9" + }, "error": { "identifier_exists": "Emplacement d\u00e9j\u00e0 enregistr\u00e9" }, diff --git a/homeassistant/components/goalzero/translations/fr.json b/homeassistant/components/goalzero/translations/fr.json index a155e8370d103..5c4b7a01580ba 100644 --- a/homeassistant/components/goalzero/translations/fr.json +++ b/homeassistant/components/goalzero/translations/fr.json @@ -5,6 +5,7 @@ }, "error": { "cannot_connect": "\u00c9chec de connexion", + "invalid_host": "Nom d'h\u00f4te ou adresse IP non valide", "unknown": "Erreur inconnue" }, "step": { @@ -12,7 +13,9 @@ "data": { "host": "H\u00f4te", "name": "Nom" - } + }, + "description": "Tout d'abord, vous devez t\u00e9l\u00e9charger l'application Goal Zero: https://www.goalzero.com/product-features/yeti-app/\n\n Suivez les instructions pour connecter votre Yeti \u00e0 votre r\u00e9seau Wifi. Ensuite, r\u00e9cup\u00e9rez l'adresse IP de votre routeur. DHCP doit \u00eatre configur\u00e9 dans les param\u00e8tres de votre routeur pour le p\u00e9riph\u00e9rique afin de garantir que l'adresse IP de l'h\u00f4te ne change pas. Reportez-vous au manuel d'utilisation de votre routeur.", + "title": "Goal Zero Yeti" } } } diff --git a/homeassistant/components/gpslogger/translations/cs.json b/homeassistant/components/gpslogger/translations/cs.json index 33cc75fda4687..4db9f18c5bfdd 100644 --- a/homeassistant/components/gpslogger/translations/cs.json +++ b/homeassistant/components/gpslogger/translations/cs.json @@ -6,7 +6,7 @@ "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "create_entry": { - "default": "Chcete-li odeslat ud\u00e1losti do aplikace Home Assistant, budete muset nastavit funkci Webhook v n\u00e1stroji GPSLogger. \n\n Vypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: ` {webhook_url} ' \n - Metoda: POST \n\n Dal\u0161\u00ed podrobnosti naleznete v [dokumentaci] ( {docs_url} )." + "default": "Chcete-li odeslat ud\u00e1losti do aplikace Home Assistant, budete muset nastavit funkci Webhook v n\u00e1stroji GPSLogger. \n\nVypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: \"{webhook_url}\"\n - Metoda: POST \n\nDal\u0161\u00ed podrobnosti naleznete v [dokumentaci]({docs_url})." }, "step": { "user": { diff --git a/homeassistant/components/gree/translations/fr.json b/homeassistant/components/gree/translations/fr.json new file mode 100644 index 0000000000000..a21b0cb462a09 --- /dev/null +++ b/homeassistant/components/gree/translations/fr.json @@ -0,0 +1,14 @@ +{ + "config": { + "abort": { + "no_devices_found": "Aucun appareil trouv\u00e9 sur le r\u00e9seau", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + }, + "step": { + "confirm": { + "description": "Voulez-vous commencer la configuration ?" + } + } + }, + "title": "Gree Climate" +} \ No newline at end of file diff --git a/homeassistant/components/heos/translations/fr.json b/homeassistant/components/heos/translations/fr.json index 39cb39e33f5a2..9962a3f7a8598 100644 --- a/homeassistant/components/heos/translations/fr.json +++ b/homeassistant/components/heos/translations/fr.json @@ -1,9 +1,11 @@ { "config": { "abort": { - "already_setup": "Vous ne pouvez configurer qu'une seule connexion Heos, car celle-ci supportera tous les p\u00e9riph\u00e9riques du r\u00e9seau." + "already_setup": "Vous ne pouvez configurer qu'une seule connexion Heos, car celle-ci supportera tous les p\u00e9riph\u00e9riques du r\u00e9seau.", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_failure": "Impossible de se connecter \u00e0 l'h\u00f4te sp\u00e9cifi\u00e9." }, "step": { diff --git a/homeassistant/components/homekit/translations/fr.json b/homeassistant/components/homekit/translations/fr.json index 4bac36a846728..d12660769b5d5 100644 --- a/homeassistant/components/homekit/translations/fr.json +++ b/homeassistant/components/homekit/translations/fr.json @@ -42,9 +42,18 @@ "description": "Choisissez les entit\u00e9s que vous ne souhaitez PAS voir reli\u00e9es.", "title": "Exclure les entit\u00e9s des domaines s\u00e9lectionn\u00e9s de la passerelle" }, + "include_exclude": { + "data": { + "entities": "Entit\u00e9s", + "mode": "Mode" + }, + "description": "Choisissez les entit\u00e9s \u00e0 exposer. En mode accessoire, une seule entit\u00e9 est expos\u00e9e. En mode d'inclusion de pont, toutes les entit\u00e9s du domaine seront expos\u00e9es \u00e0 moins que des entit\u00e9s sp\u00e9cifiques ne soient s\u00e9lectionn\u00e9es. En mode d'exclusion de pont, toutes les entit\u00e9s du domaine seront expos\u00e9es \u00e0 l'exception des entit\u00e9s exclues.", + "title": "S\u00e9lectionnez les entit\u00e9s \u00e0 exposer" + }, "init": { "data": { - "include_domains": "Domaine \u00e0 inclure" + "include_domains": "Domaine \u00e0 inclure", + "mode": "Mode" }, "description": "Les entit\u00e9s des \u00abdomaines \u00e0 inclure\u00bb seront pont\u00e9es vers HomeKit. Vous pourrez s\u00e9lectionner les entit\u00e9s \u00e0 exclure de cette liste sur l'\u00e9cran suivant.", "title": "S\u00e9lectionnez les domaines \u00e0 relier." diff --git a/homeassistant/components/homematicip_cloud/translations/cs.json b/homeassistant/components/homematicip_cloud/translations/cs.json index 4fd386ba37a36..e71b5593ea662 100644 --- a/homeassistant/components/homematicip_cloud/translations/cs.json +++ b/homeassistant/components/homematicip_cloud/translations/cs.json @@ -22,7 +22,7 @@ "title": "Vyberte p\u0159\u00edstupov\u00fd bod HomematicIP" }, "link": { - "description": "Stiskn\u011bte modr\u00e9 tla\u010d\u00edtko na p\u0159\u00edstupov\u00e9m bodu a tla\u010d\u00edtko pro registraci HomematicIP s dom\u00e1c\u00edm asistentem. \n\n ! [Um\u00edst\u011bn\u00ed tla\u010d\u00edtka na za\u0159\u00edzen\u00ed] (/static/images/config_flows/config_homematicip_cloud.png)", + "description": "Stiskn\u011bte modr\u00e9 tla\u010d\u00edtko na p\u0159\u00edstupov\u00e9m bodu a tla\u010d\u00edtko pro registraci HomematicIP s dom\u00e1c\u00edm asistentem. \n\n ![Um\u00edst\u011bn\u00ed tla\u010d\u00edtka na za\u0159\u00edzen\u00ed](/static/images/config_flows/config_homematicip_cloud.png)", "title": "P\u0159ipojit se k p\u0159\u00edstupov\u00e9mu bodu" } } diff --git a/homeassistant/components/hue/translations/ru.json b/homeassistant/components/hue/translations/ru.json index 12313583030c5..81cbe6a385f74 100644 --- a/homeassistant/components/hue/translations/ru.json +++ b/homeassistant/components/hue/translations/ru.json @@ -39,19 +39,19 @@ "button_2": "\u0412\u0442\u043e\u0440\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", "button_3": "\u0422\u0440\u0435\u0442\u044c\u044f \u043a\u043d\u043e\u043f\u043a\u0430", "button_4": "\u0427\u0435\u0442\u0432\u0435\u0440\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", - "dim_down": "\u042f\u0440\u043a\u043e\u0441\u0442\u044c \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442\u0441\u044f", - "dim_up": "\u042f\u0440\u043a\u043e\u0441\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "dim_down": "\u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u044f\u0440\u043a\u043e\u0441\u0442\u044c", + "dim_up": "\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u044f\u0440\u043a\u043e\u0441\u0442\u044c", "double_buttons_1_3": "\u041f\u0435\u0440\u0432\u0430\u044f \u0438 \u0442\u0440\u0435\u0442\u044c\u044f \u043a\u043d\u043e\u043f\u043a\u0438", "double_buttons_2_4": "\u0412\u0442\u043e\u0440\u0430\u044f \u0438 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0438", - "turn_off": "\u0412\u044b\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f", - "turn_on": "\u0412\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f" + "turn_off": "\u0412\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c", + "turn_on": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c" }, "trigger_type": { - "remote_button_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "remote_button_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", "remote_button_short_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430", - "remote_button_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430", - "remote_double_button_long_press": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u044b \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", - "remote_double_button_short_press": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u044b" + "remote_button_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "remote_double_button_long_press": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u044b \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "remote_double_button_short_press": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u044b \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f" } }, "options": { diff --git a/homeassistant/components/iaqualink/translations/fr.json b/homeassistant/components/iaqualink/translations/fr.json index 47ed27fb33918..cd4968e871145 100644 --- a/homeassistant/components/iaqualink/translations/fr.json +++ b/homeassistant/components/iaqualink/translations/fr.json @@ -1,9 +1,11 @@ { "config": { "abort": { - "already_setup": "Vous ne pouvez configurer qu'une seule connexion iAqualink." + "already_setup": "Vous ne pouvez configurer qu'une seule connexion iAqualink.", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_failure": "Impossible de se connecter \u00e0 iAqualink. V\u00e9rifiez votre nom d'utilisateur et votre mot de passe." }, "step": { diff --git a/homeassistant/components/icloud/translations/fr.json b/homeassistant/components/icloud/translations/fr.json index 000696d5b7d2f..6ffb3090b8719 100644 --- a/homeassistant/components/icloud/translations/fr.json +++ b/homeassistant/components/icloud/translations/fr.json @@ -2,7 +2,8 @@ "config": { "abort": { "already_configured": "Compte d\u00e9j\u00e0 configur\u00e9", - "no_device": "Aucun de vos appareils n'a activ\u00e9 \"Find my iPhone\"" + "no_device": "Aucun de vos appareils n'a activ\u00e9 \"Find my iPhone\"", + "reauth_successful": "La r\u00e9-authentification a r\u00e9ussi" }, "error": { "invalid_auth": "Authentification invalide", @@ -11,6 +12,13 @@ "validate_verification_code": "Impossible de v\u00e9rifier votre code de v\u00e9rification, choisissez un appareil de confiance et recommencez la v\u00e9rification" }, "step": { + "reauth": { + "data": { + "password": "Mot de passe" + }, + "description": "Votre mot de passe pr\u00e9c\u00e9demment saisi pour {username} ne fonctionne plus. Mettez \u00e0 jour votre mot de passe pour continuer \u00e0 utiliser cette int\u00e9gration.", + "title": "R\u00e9-authentifier l'int\u00e9gration" + }, "trusted_device": { "data": { "trusted_device": "Appareil de confiance" diff --git a/homeassistant/components/ipp/translations/fr.json b/homeassistant/components/ipp/translations/fr.json index be2166ad433c2..48263f0b30abb 100644 --- a/homeassistant/components/ipp/translations/fr.json +++ b/homeassistant/components/ipp/translations/fr.json @@ -2,6 +2,7 @@ "config": { "abort": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", + "cannot_connect": "\u00c9chec de connexion", "connection_error": "\u00c9chec de connexion", "connection_upgrade": "Impossible de se connecter \u00e0 l'imprimante parce qu'une mise \u00e0 niveau de la connexion est n\u00e9cessaire.", "ipp_error": "Erreur IPP rencontr\u00e9e.", @@ -10,6 +11,7 @@ "unique_id_required": "Dispositif ne portant pas l'identification unique requise pour la d\u00e9couverte." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_error": "\u00c9chec de connexion", "connection_upgrade": "Impossible de se connecter \u00e0 l'imprimante. Veuillez r\u00e9essayer avec l'option SSL / TLS coch\u00e9e." }, diff --git a/homeassistant/components/life360/translations/ca.json b/homeassistant/components/life360/translations/ca.json index 5c379e4fecfa4..b0961447bbbd7 100644 --- a/homeassistant/components/life360/translations/ca.json +++ b/homeassistant/components/life360/translations/ca.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "invalid_credentials": "Credencials inv\u00e0lides", + "unknown": "Error inesperat", "user_already_configured": "[%key::common::config_flow::abort::already_configured_account%]" }, "create_entry": { "default": "Per configurar les opcions avan\u00e7ades mira la [documentaci\u00f3 de Life360]({docs_url})." }, "error": { + "already_configured": "El compte ja ha estat configurat", "invalid_auth": "Autenticaci\u00f3 inv\u00e0lida", "invalid_credentials": "Credencials inv\u00e0lides", "invalid_username": "Nom d'usuari incorrecte", "unexpected": "S'ha produ\u00eft un error inesperat en comunicar-se amb el servidor de Life360.", + "unknown": "Error inesperat", "user_already_configured": "[%key::common::config_flow::abort::already_configured_account%]" }, "step": { diff --git a/homeassistant/components/life360/translations/es.json b/homeassistant/components/life360/translations/es.json index 28b4c0737c436..8331f22796c3f 100644 --- a/homeassistant/components/life360/translations/es.json +++ b/homeassistant/components/life360/translations/es.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "Autenticaci\u00f3n inv\u00e1lida", "invalid_credentials": "Credenciales no v\u00e1lidas", + "unknown": "Error inesperado", "user_already_configured": "La cuenta ya est\u00e1 configurada" }, "create_entry": { "default": "Para configurar las opciones avanzadas, consulta la [documentaci\u00f3n de Life360]({docs_url})." }, "error": { + "already_configured": "La cuenta ya ha sido configurada", "invalid_auth": "Autenticaci\u00f3n inv\u00e1lida", "invalid_credentials": "Credenciales no v\u00e1lidas", "invalid_username": "Nombre de usuario no v\u00e1lido", "unexpected": "Error inesperado al comunicarse con el servidor Life360", + "unknown": "Error inesperado", "user_already_configured": "La cuenta ya ha sido configurada" }, "step": { diff --git a/homeassistant/components/life360/translations/fr.json b/homeassistant/components/life360/translations/fr.json index cf004d4c03a04..e757e37fa0b8a 100644 --- a/homeassistant/components/life360/translations/fr.json +++ b/homeassistant/components/life360/translations/fr.json @@ -1,16 +1,21 @@ { "config": { "abort": { + "invalid_auth": "Authentification invalide", "invalid_credentials": "Informations d'identification invalides", + "unknown": "Erreur inattendue", "user_already_configured": "Compte d\u00e9j\u00e0 configur\u00e9" }, "create_entry": { "default": "Pour d\u00e9finir les options avanc\u00e9es, voir [Documentation de Life360]( {docs_url} )." }, "error": { + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "invalid_auth": "Authentification invalide", "invalid_credentials": "Informations d'identification invalides", "invalid_username": "Nom d'utilisateur invalide", "unexpected": "Erreur inattendue lors de la communication avec le serveur Life360", + "unknown": "Erreur inattendue", "user_already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9" }, "step": { diff --git a/homeassistant/components/life360/translations/pl.json b/homeassistant/components/life360/translations/pl.json index 54ca11f2bd414..aef7365a9cf4b 100644 --- a/homeassistant/components/life360/translations/pl.json +++ b/homeassistant/components/life360/translations/pl.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "Niepoprawne uwierzytelnienie", "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", + "unknown": "Nieoczekiwany b\u0142\u0105d", "user_already_configured": "Konto jest ju\u017c skonfigurowane" }, "create_entry": { "default": "Aby skonfigurowa\u0107 zaawansowane ustawienia, zapoznaj si\u0119 z [dokumentacj\u0105 Life360]({docs_url})." }, "error": { + "already_configured": "Konto jest ju\u017c skonfigurowane", "invalid_auth": "Niepoprawne uwierzytelnienie", "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", "invalid_username": "Nieprawid\u0142owa nazwa u\u017cytkownika", "unexpected": "Nieoczekiwany b\u0142\u0105d komunikacji z serwerem Life360", + "unknown": "Nieoczekiwany b\u0142\u0105d", "user_already_configured": "Konto jest ju\u017c skonfigurowane" }, "step": { diff --git a/homeassistant/components/life360/translations/zh-Hant.json b/homeassistant/components/life360/translations/zh-Hant.json index 886710f4788cb..ba4f132dd6f1e 100644 --- a/homeassistant/components/life360/translations/zh-Hant.json +++ b/homeassistant/components/life360/translations/zh-Hant.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "invalid_credentials": "\u6191\u8b49\u7121\u6548", + "unknown": "\u672a\u9810\u671f\u932f\u8aa4", "user_already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "create_entry": { "default": "\u6b32\u8a2d\u5b9a\u9032\u968e\u9078\u9805\uff0c\u8acb\u53c3\u95b1 [Life360 \u6587\u4ef6]({docs_url})\u3002" }, "error": { + "already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548", "invalid_credentials": "\u6191\u8b49\u7121\u6548", "invalid_username": "\u4f7f\u7528\u8005\u540d\u7a31\u7121\u6548", "unexpected": "\u8207 Life360 \u4f3a\u670d\u5668\u901a\u8a0a\u767c\u751f\u672a\u77e5\u932f\u8aa4", + "unknown": "\u672a\u9810\u671f\u932f\u8aa4", "user_already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "step": { diff --git a/homeassistant/components/locative/translations/cs.json b/homeassistant/components/locative/translations/cs.json index 4459aac99c84e..ca188625172a8 100644 --- a/homeassistant/components/locative/translations/cs.json +++ b/homeassistant/components/locative/translations/cs.json @@ -6,7 +6,7 @@ "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, "create_entry": { - "default": "Chcete-li odes\u00edlat um\u00edst\u011bn\u00ed do aplikace Home Assistant, budete muset nastavit funkci Webhook v aplikaci Locative. \n\n Vypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: ` {webhook_url} ' \n - Metoda: POST \n\n Dal\u0161\u00ed podrobnosti naleznete v [dokumentaci] ( {docs_url} )." + "default": "Chcete-li odes\u00edlat um\u00edst\u011bn\u00ed do aplikace Home Assistant, budete muset nastavit funkci Webhook v aplikaci Locative. \n\nVypl\u0148te n\u00e1sleduj\u00edc\u00ed informace: \n\n - URL: \"{webhook_url}\" \n - Metoda: POST \n\nDal\u0161\u00ed podrobnosti naleznete v [dokumentaci]({docs_url})." }, "step": { "user": { diff --git a/homeassistant/components/logi_circle/translations/fr.json b/homeassistant/components/logi_circle/translations/fr.json index 003f44963c90f..ab9e82606b3cd 100644 --- a/homeassistant/components/logi_circle/translations/fr.json +++ b/homeassistant/components/logi_circle/translations/fr.json @@ -1,9 +1,11 @@ { "config": { "abort": { + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "already_setup": "Vous ne pouvez configurer qu'un seul compte Logi Circle.", "external_error": "Une exception est survenue \u00e0 partir d'un autre flux.", "external_setup": "Logi Circle a \u00e9t\u00e9 configur\u00e9 avec succ\u00e8s \u00e0 partir d'un autre flux.", + "missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation.", "no_flows": "Vous devez configurer Logi Circle avant de pouvoir vous authentifier aupr\u00e8s de celui-ci. [Veuillez lire les instructions] (https://www.home-assistant.io/components/logi_circle/)." }, "create_entry": { @@ -12,7 +14,9 @@ "error": { "auth_error": "L'autorisation de l'API a \u00e9chou\u00e9.", "auth_timeout": "L'autorisation a expir\u00e9 lors de la demande du jeton d'acc\u00e8s.", - "follow_link": "Veuillez suivre le lien et vous authentifier avant d'appuyer sur Soumettre." + "authorize_url_timeout": "D\u00e9lai de g\u00e9n\u00e9ration de l'URL d'authentification d\u00e9pass\u00e9.", + "follow_link": "Veuillez suivre le lien et vous authentifier avant d'appuyer sur Soumettre.", + "invalid_auth": "Authentification invalide" }, "step": { "auth": { diff --git a/homeassistant/components/luftdaten/translations/es.json b/homeassistant/components/luftdaten/translations/es.json index 9f8276ff3b868..f7caa10c885e6 100644 --- a/homeassistant/components/luftdaten/translations/es.json +++ b/homeassistant/components/luftdaten/translations/es.json @@ -1,6 +1,8 @@ { "config": { "error": { + "already_configured": "El servicio ya est\u00e1 configurado", + "cannot_connect": "No se pudo conectar", "communication_error": "No se puede comunicar con la API de Luftdaten", "invalid_sensor": "Sensor no disponible o no v\u00e1lido", "sensor_exists": "Sensor ya registrado" diff --git a/homeassistant/components/luftdaten/translations/fr.json b/homeassistant/components/luftdaten/translations/fr.json index 8b3492a042731..f89fe2ffce3c6 100644 --- a/homeassistant/components/luftdaten/translations/fr.json +++ b/homeassistant/components/luftdaten/translations/fr.json @@ -1,6 +1,8 @@ { "config": { "error": { + "already_configured": "Le service est d\u00e9j\u00e0 configur\u00e9", + "cannot_connect": "\u00c9chec de connexion", "communication_error": "Impossible de communiquer avec l'API Luftdaten", "invalid_sensor": "Capteur non disponible ou invalide", "sensor_exists": "Capteur d\u00e9j\u00e0 enregistr\u00e9" diff --git a/homeassistant/components/mill/translations/fr.json b/homeassistant/components/mill/translations/fr.json index 9fa7c48bb68f1..af975d018d8cc 100644 --- a/homeassistant/components/mill/translations/fr.json +++ b/homeassistant/components/mill/translations/fr.json @@ -4,6 +4,7 @@ "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9" }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_error": "\u00c9chec de connexion" }, "step": { diff --git a/homeassistant/components/mqtt/translations/ru.json b/homeassistant/components/mqtt/translations/ru.json index bfac4cadecc9f..e12f97f3802bc 100644 --- a/homeassistant/components/mqtt/translations/ru.json +++ b/homeassistant/components/mqtt/translations/ru.json @@ -34,17 +34,17 @@ "button_4": "\u0427\u0435\u0442\u0432\u0435\u0440\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", "button_5": "\u041f\u044f\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", "button_6": "\u0428\u0435\u0441\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", - "turn_off": "\u0412\u044b\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f", - "turn_on": "\u0412\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f" + "turn_off": "\u0412\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c", + "turn_on": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c" }, "trigger_type": { "button_double_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430", - "button_long_press": "{subtype} \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e \u043d\u0430\u0436\u0430\u0442\u0430", - "button_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "button_long_press": "{subtype} \u0434\u043e\u043b\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0430", + "button_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", "button_quadruple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430", "button_quintuple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437", "button_short_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430", - "button_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430", + "button_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", "button_triple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0442\u0440\u0438 \u0440\u0430\u0437\u0430" } }, diff --git a/homeassistant/components/nest/translations/cs.json b/homeassistant/components/nest/translations/cs.json index 07a7454783493..3c25b804da938 100644 --- a/homeassistant/components/nest/translations/cs.json +++ b/homeassistant/components/nest/translations/cs.json @@ -5,7 +5,7 @@ "authorize_url_fail": "Nezn\u00e1m\u00e1 chyba p\u0159i generov\u00e1n\u00ed autoriza\u010dn\u00ed URL.", "authorize_url_timeout": "\u010casov\u00fd limit autoriza\u010dn\u00edho URL vypr\u0161el", "missing_configuration": "Komponenta nen\u00ed nastavena. Postupujte podle dokumentace.", - "no_flows": "Pot\u0159ebujete nakonfigurovat Nest, abyste se s n\u00edm mohli autentizovat. [P\u0159e\u010dt\u011bte si pros\u00edm pokyny] (https://www.home-assistant.io/components/nest/).", + "no_flows": "Pot\u0159ebujete nakonfigurovat Nest, abyste se s n\u00edm mohli autentizovat. [P\u0159e\u010dt\u011bte si pros\u00edm pokyny](https://www.home-assistant.io/components/nest/).", "no_url_available": "Nen\u00ed k dispozici \u017e\u00e1dn\u00e1 adresa URL. Informace o t\u00e9to chyb\u011b naleznete [v sekci n\u00e1pov\u011bdy]({docs_url})", "single_instance_allowed": "Ji\u017e nastaveno. Je mo\u017en\u00e1 pouze jedin\u00e1 konfigurace." }, diff --git a/homeassistant/components/nest/translations/es.json b/homeassistant/components/nest/translations/es.json index 6f55a9f2084bc..0e5cf56163131 100644 --- a/homeassistant/components/nest/translations/es.json +++ b/homeassistant/components/nest/translations/es.json @@ -6,6 +6,7 @@ "authorize_url_timeout": "Tiempo de espera agotado generando la url de autorizaci\u00f3n.", "missing_configuration": "El componente no est\u00e1 configurado. Consulta la documentaci\u00f3n.", "no_flows": "Debes configurar Nest antes de poder autenticarte con \u00e9l. [Lee las instrucciones](https://www.home-assistant.io/components/nest/).", + "no_url_available": "No hay URL disponible. Para obtener informaci\u00f3n sobre este error, [consulta la secci\u00f3n de ayuda]({docs_url})", "single_instance_allowed": "Ya est\u00e1 configurado. Solo es posible una \u00fanica configuraci\u00f3n." }, "create_entry": { diff --git a/homeassistant/components/nest/translations/fr.json b/homeassistant/components/nest/translations/fr.json index 6308098b9c1f5..cfe7333dec74f 100644 --- a/homeassistant/components/nest/translations/fr.json +++ b/homeassistant/components/nest/translations/fr.json @@ -4,11 +4,18 @@ "already_setup": "Vous ne pouvez configurer qu'un seul compte Nest.", "authorize_url_fail": "Erreur inconnue lors de la g\u00e9n\u00e9ration d'une URL d'autorisation.", "authorize_url_timeout": "D\u00e9lai de g\u00e9n\u00e9ration de l'URL d'authentification d\u00e9pass\u00e9.", - "no_flows": "Vous devez configurer Nest avant de pouvoir vous authentifier avec celui-ci. [Veuillez lire les instructions] (https://www.home-assistant.io/components/nest/)." + "missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation.", + "no_flows": "Vous devez configurer Nest avant de pouvoir vous authentifier avec celui-ci. [Veuillez lire les instructions] (https://www.home-assistant.io/components/nest/).", + "no_url_available": "Aucune URL disponible. Pour plus d'informations sur cette erreur, [consultez la section d'aide] ( {docs_url} )", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + }, + "create_entry": { + "default": "Authentification r\u00e9ussie" }, "error": { "internal_error": "Erreur interne lors de la validation du code", "invalid_code": "Code invalide", + "invalid_pin": "Code PIN invalide", "timeout": "D\u00e9lai de la validation du code expir\u00e9", "unknown": "Erreur inconnue lors de la validation du code" }, @@ -26,6 +33,9 @@ }, "description": "Pour associer votre compte Nest, [autorisez votre compte]({url}). \n\n Apr\u00e8s autorisation, copiez-collez le code PIN fourni ci-dessous.", "title": "Lier un compte Nest" + }, + "pick_implementation": { + "title": "S\u00e9lectionner une m\u00e9thode d'authentification" } } } diff --git a/homeassistant/components/nightscout/translations/fr.json b/homeassistant/components/nightscout/translations/fr.json index 1bcd530d29b52..bec903749065d 100644 --- a/homeassistant/components/nightscout/translations/fr.json +++ b/homeassistant/components/nightscout/translations/fr.json @@ -14,7 +14,9 @@ "data": { "api_key": "Cl\u00e9 d'API", "url": "URL" - } + }, + "description": "- URL: l'adresse de votre instance de nightcout. Exemple : https://myhomeassistant.duckdns.org:5423\n - Cl\u00e9 API (facultative) : \u00e0 n'utiliser que si votre instance est prot\u00e9g\u00e9e (auth_default_roles! = Readable).", + "title": "Entrez les informations de votre serveur Nightscout." } } } diff --git a/homeassistant/components/notion/translations/fr.json b/homeassistant/components/notion/translations/fr.json index b5b6005ab9bbc..3da3197a7b616 100644 --- a/homeassistant/components/notion/translations/fr.json +++ b/homeassistant/components/notion/translations/fr.json @@ -4,6 +4,7 @@ "already_configured": "Ce nom d'utilisateur est d\u00e9j\u00e0 utilis\u00e9." }, "error": { + "invalid_auth": "Authentification invalide", "invalid_credentials": "Nom d'utilisateur ou mot de passe invalide", "no_devices": "Aucun appareil trouv\u00e9 sur le compte" }, diff --git a/homeassistant/components/omnilogic/translations/fr.json b/homeassistant/components/omnilogic/translations/fr.json index 167beb756a8f1..30d1bbb2f2bcf 100644 --- a/homeassistant/components/omnilogic/translations/fr.json +++ b/homeassistant/components/omnilogic/translations/fr.json @@ -16,5 +16,15 @@ } } } - } + }, + "options": { + "step": { + "init": { + "data": { + "polling_interval": "Intervalle d'interrogation (en secondes)" + } + } + } + }, + "title": "Omnilogic" } \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/es.json b/homeassistant/components/onewire/translations/es.json new file mode 100644 index 0000000000000..f4bf44f0e9db1 --- /dev/null +++ b/homeassistant/components/onewire/translations/es.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "already_configured": "El dispositivo ya est\u00e1 configurado" + }, + "error": { + "cannot_connect": "No se pudo conectar", + "invalid_path": "Directorio no encontrado." + }, + "step": { + "owserver": { + "data": { + "host": "Host", + "port": "Puerto" + } + }, + "user": { + "data": { + "type": "Tipo de conexi\u00f3n" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onewire/translations/fr.json b/homeassistant/components/onewire/translations/fr.json new file mode 100644 index 0000000000000..13a5438b1a9a4 --- /dev/null +++ b/homeassistant/components/onewire/translations/fr.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + }, + "error": { + "cannot_connect": "\u00c9chec de connexion", + "invalid_path": "R\u00e9pertoire introuvable." + }, + "step": { + "owserver": { + "data": { + "host": "H\u00f4te", + "port": "Port" + }, + "title": "D\u00e9finir les d\u00e9tails d'owserver" + }, + "user": { + "data": { + "type": "Type de connexion" + }, + "title": "Configurer 1-Wire" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/onvif/translations/fr.json b/homeassistant/components/onvif/translations/fr.json index 2fa433d7441d6..e872b7c29bc05 100644 --- a/homeassistant/components/onvif/translations/fr.json +++ b/homeassistant/components/onvif/translations/fr.json @@ -8,6 +8,7 @@ "onvif_error": "Erreur lors de la configuration du p\u00e9riph\u00e9rique ONVIF. Consultez les journaux pour plus d'informations." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_failed": "Impossible de se connecter au service ONVIF avec les informations d'identification fournies." }, "step": { diff --git a/homeassistant/components/opentherm_gw/translations/es.json b/homeassistant/components/opentherm_gw/translations/es.json index 73918a9e8a9ad..ab6f0743678aa 100644 --- a/homeassistant/components/opentherm_gw/translations/es.json +++ b/homeassistant/components/opentherm_gw/translations/es.json @@ -2,6 +2,7 @@ "config": { "error": { "already_configured": "Gateway ya configurado", + "cannot_connect": "No se pudo conectar", "id_exists": "El ID del Gateway ya existe", "serial_error": "Error de conexi\u00f3n al dispositivo", "timeout": "Intento de conexi\u00f3n agotado" diff --git a/homeassistant/components/opentherm_gw/translations/fr.json b/homeassistant/components/opentherm_gw/translations/fr.json index 11cce45dcd7a3..e69a961d67530 100644 --- a/homeassistant/components/opentherm_gw/translations/fr.json +++ b/homeassistant/components/opentherm_gw/translations/fr.json @@ -2,6 +2,7 @@ "config": { "error": { "already_configured": "Passerelle d\u00e9j\u00e0 configur\u00e9e", + "cannot_connect": "\u00c9chec de connexion", "id_exists": "L'identifiant de la passerelle existe d\u00e9j\u00e0", "serial_error": "Erreur de connexion \u00e0 l'appareil", "timeout": "La tentative de connexion a expir\u00e9" diff --git a/homeassistant/components/ovo_energy/translations/fr.json b/homeassistant/components/ovo_energy/translations/fr.json index b900e75787f3b..44941bab0a996 100644 --- a/homeassistant/components/ovo_energy/translations/fr.json +++ b/homeassistant/components/ovo_energy/translations/fr.json @@ -3,7 +3,9 @@ "error": { "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "authorization_error": "Erreur d'autorisation. V\u00e9rifiez vos identifiants.", - "connection_error": "\u00c9chec de connexion" + "cannot_connect": "\u00c9chec de connexion", + "connection_error": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide" }, "step": { "user": { diff --git a/homeassistant/components/panasonic_viera/translations/fr.json b/homeassistant/components/panasonic_viera/translations/fr.json index 9f8c9b672e526..df7f8002ecee4 100644 --- a/homeassistant/components/panasonic_viera/translations/fr.json +++ b/homeassistant/components/panasonic_viera/translations/fr.json @@ -2,10 +2,12 @@ "config": { "abort": { "already_configured": "Ce t\u00e9l\u00e9viseur Panasonic Viera est d\u00e9j\u00e0 configur\u00e9.", + "cannot_connect": "\u00c9chec de connexion", "not_connected": "La connexion \u00e0 distance avec votre t\u00e9l\u00e9viseur Panasonic Viera a \u00e9t\u00e9 perdue. Consultez les journaux pour plus d'informations.", "unknown": "Une erreur inconnue est survenue. Veuillez consulter les journaux pour obtenir plus de d\u00e9tails." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "invalid_pin_code": "Le code PIN que vous avez entr\u00e9 n'est pas valide", "not_connected": "Impossible d'\u00e9tablir une connexion \u00e0 distance avec votre t\u00e9l\u00e9viseur Panasonic Viera" }, diff --git a/homeassistant/components/plex/translations/fr.json b/homeassistant/components/plex/translations/fr.json index 685eab31bfd29..63a2413316ed0 100644 --- a/homeassistant/components/plex/translations/fr.json +++ b/homeassistant/components/plex/translations/fr.json @@ -4,6 +4,7 @@ "all_configured": "Tous les serveurs li\u00e9s sont d\u00e9j\u00e0 configur\u00e9s", "already_configured": "Ce serveur Plex est d\u00e9j\u00e0 configur\u00e9", "already_in_progress": "Plex en cours de configuration", + "reauth_successful": "La r\u00e9-authentification a r\u00e9ussi", "token_request_timeout": "D\u00e9lai d'obtention du jeton", "unknown": "\u00c9chec pour une raison inconnue" }, diff --git a/homeassistant/components/plugwise/translations/fr.json b/homeassistant/components/plugwise/translations/fr.json index fe4b88ab0f144..8e880acdd3600 100644 --- a/homeassistant/components/plugwise/translations/fr.json +++ b/homeassistant/components/plugwise/translations/fr.json @@ -12,12 +12,22 @@ "step": { "user": { "data": { + "flow_type": "Type de connexion", "host": "Adresse IP de Smile", "password": "ID Smile", "port": "Num\u00e9ro de port Smile" }, "description": "Veuillez saisir :", "title": "Se connecter \u00e0 Smile" + }, + "user_gateway": { + "data": { + "host": "Adresse IP", + "password": "ID Smile", + "port": "Port" + }, + "description": "Veuillez saisir :", + "title": "Se connecter \u00e0 Smile" } } }, diff --git a/homeassistant/components/poolsense/translations/fr.json b/homeassistant/components/poolsense/translations/fr.json index cd9949baa6474..0a9fac750052d 100644 --- a/homeassistant/components/poolsense/translations/fr.json +++ b/homeassistant/components/poolsense/translations/fr.json @@ -12,7 +12,7 @@ "email": "Adresse e-mail", "password": "Mot de passe" }, - "description": "[%key:common::config_flow::description%]", + "description": "Voulez-vous commencer la configuration ?", "title": "PoolSense" } } diff --git a/homeassistant/components/profiler/translations/fr.json b/homeassistant/components/profiler/translations/fr.json new file mode 100644 index 0000000000000..4d10b4f4ecc23 --- /dev/null +++ b/homeassistant/components/profiler/translations/fr.json @@ -0,0 +1,12 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + }, + "step": { + "user": { + "description": "Voulez-vous commencer la configuration ?" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/ps4/translations/fr.json b/homeassistant/components/ps4/translations/fr.json index ca152e727c808..7a811ee095c4d 100644 --- a/homeassistant/components/ps4/translations/fr.json +++ b/homeassistant/components/ps4/translations/fr.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", "credential_error": "Erreur lors de l'extraction des informations d'identification.", "devices_configured": "Tous les p\u00e9riph\u00e9riques trouv\u00e9s sont d\u00e9j\u00e0 configur\u00e9s.", "no_devices_found": "Aucun appareil PlayStation 4 trouv\u00e9 sur le r\u00e9seau.", @@ -8,6 +9,7 @@ "port_997_bind_error": "Impossible de se connecter au port 997. Reportez-vous \u00e0 la [documentation] (https://www.home-assistant.io/components/ps4/) pour plus d'informations." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "credential_timeout": "Le service d'informations d'identification a expir\u00e9. Appuyez sur soumettre pour red\u00e9marrer.", "login_failed": "\u00c9chec de l'association \u00e0 la PlayStation 4. V\u00e9rifiez que le code PIN est correct.", "no_ipaddress": "Entrez l'adresse IP de la PlayStation 4 que vous souhaitez configurer.", diff --git a/homeassistant/components/rainmachine/translations/ca.json b/homeassistant/components/rainmachine/translations/ca.json index cc77b66aef05e..93544fcb72bcf 100644 --- a/homeassistant/components/rainmachine/translations/ca.json +++ b/homeassistant/components/rainmachine/translations/ca.json @@ -18,5 +18,15 @@ "title": "Introdueix la teva informaci\u00f3" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Temps d'execuci\u00f3 predeterminat de la zona (en segons)" + }, + "title": "Configuraci\u00f3 de RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/cs.json b/homeassistant/components/rainmachine/translations/cs.json index 883e731f8389b..f01515a117e2a 100644 --- a/homeassistant/components/rainmachine/translations/cs.json +++ b/homeassistant/components/rainmachine/translations/cs.json @@ -18,5 +18,12 @@ "title": "Vypl\u0148te va\u0161e \u00fadaje" } } + }, + "options": { + "step": { + "init": { + "title": "Nastaven\u00ed RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/es.json b/homeassistant/components/rainmachine/translations/es.json index fc27a8b3089fc..70ea014d1591a 100644 --- a/homeassistant/components/rainmachine/translations/es.json +++ b/homeassistant/components/rainmachine/translations/es.json @@ -18,5 +18,15 @@ "title": "Completa tu informaci\u00f3n" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Tiempo de ejecuci\u00f3n de zona predeterminado (en segundos)" + }, + "title": "Configurar RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/fr.json b/homeassistant/components/rainmachine/translations/fr.json index 34c769faac79b..0db0637bbf05c 100644 --- a/homeassistant/components/rainmachine/translations/fr.json +++ b/homeassistant/components/rainmachine/translations/fr.json @@ -5,6 +5,7 @@ }, "error": { "identifier_exists": "Compte d\u00e9j\u00e0 enregistr\u00e9", + "invalid_auth": "Authentification invalide", "invalid_credentials": "Informations d'identification invalides" }, "step": { @@ -17,5 +18,15 @@ "title": "Veuillez saisir vos informations" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Dur\u00e9e d'ex\u00e9cution de la zone par d\u00e9faut (en secondes)" + }, + "title": "Configurer RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/no.json b/homeassistant/components/rainmachine/translations/no.json index 42ca5985d79d1..0ee0768afc40f 100644 --- a/homeassistant/components/rainmachine/translations/no.json +++ b/homeassistant/components/rainmachine/translations/no.json @@ -18,5 +18,15 @@ "title": "Fyll ut informasjonen din" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Standard sonekj\u00f8ringstid (i sekunder)" + }, + "title": "Konfigurer RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/pl.json b/homeassistant/components/rainmachine/translations/pl.json index a1b7c01725e1c..7fd14d1e1d9b7 100644 --- a/homeassistant/components/rainmachine/translations/pl.json +++ b/homeassistant/components/rainmachine/translations/pl.json @@ -18,5 +18,15 @@ "title": "Wprowad\u017a dane" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Domy\u015blny czas dzia\u0142ania dla strefy (w sekundach)" + }, + "title": "Konfiguracja RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/ru.json b/homeassistant/components/rainmachine/translations/ru.json index 3bb1a95f64745..f4ccff958f91a 100644 --- a/homeassistant/components/rainmachine/translations/ru.json +++ b/homeassistant/components/rainmachine/translations/ru.json @@ -18,5 +18,15 @@ "title": "RainMachine" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "\u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0437\u043e\u043d\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (\u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445)" + }, + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/zh-Hant.json b/homeassistant/components/rainmachine/translations/zh-Hant.json index bb4184b078b96..98b8ae38941b5 100644 --- a/homeassistant/components/rainmachine/translations/zh-Hant.json +++ b/homeassistant/components/rainmachine/translations/zh-Hant.json @@ -18,5 +18,15 @@ "title": "\u586b\u5beb\u8cc7\u8a0a" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "\u9810\u8a2d\u5340\u57df\u57f7\u884c\u6642\u9593\uff08\u79d2\uff09" + }, + "title": "\u8a2d\u5b9a RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rfxtrx/translations/fr.json b/homeassistant/components/rfxtrx/translations/fr.json index 5155bf6dacf6c..dcb1543ab29d6 100644 --- a/homeassistant/components/rfxtrx/translations/fr.json +++ b/homeassistant/components/rfxtrx/translations/fr.json @@ -1,13 +1,37 @@ { "config": { "abort": { - "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", + "cannot_connect": "\u00c9chec de connexion" + }, + "error": { + "cannot_connect": "\u00c9chec de connexion" }, "step": { + "setup_network": { + "data": { + "host": "H\u00f4te", + "port": "Port" + }, + "title": "S\u00e9lectionnez l'adresse de connexion" + }, + "setup_serial": { + "data": { + "device": "S\u00e9lectionner un appareil" + }, + "title": "Appareil" + }, "setup_serial_manual_path": { "data": { "device": "Chemin du p\u00e9riph\u00e9rique USB" - } + }, + "title": "Chemin" + }, + "user": { + "data": { + "type": "Type de connexion" + }, + "title": "S\u00e9lectionnez le type de connexion" } } }, @@ -15,11 +39,30 @@ "error": { "already_configured_device": "L'appareil est d\u00e9j\u00e0 configur\u00e9", "invalid_event_code": "Code d'\u00e9v\u00e9nement non valide", + "invalid_input_2262_off": "Entr\u00e9e non valable pour la commande \u00e9teindre", + "invalid_input_2262_on": "Entr\u00e9e non valide pour le d\u00e9lai d'activation", + "invalid_input_off_delay": "Entr\u00e9e non valide pour le d\u00e9lai de d\u00e9sactivation", "unknown": "Erreur inattendue" }, "step": { + "prompt_options": { + "data": { + "automatic_add": "Activer l'ajout automatique", + "debug": "Activer le d\u00e9bogage", + "device": "S\u00e9lectionnez l'appareil \u00e0 configurer", + "event_code": "Entrez le code d'\u00e9v\u00e9nement \u00e0 ajouter", + "remove_device": "S\u00e9lectionnez l'appareil \u00e0 supprimer" + }, + "title": "Options Rfxtrx" + }, "set_device_options": { "data": { + "command_off": "Valeur des bits de donn\u00e9es pour la commande \u00e9teindre", + "command_on": "Valeur des bits de donn\u00e9es pour la commande allumer", + "data_bit": "Nombre de bits de donn\u00e9es", + "fire_event": "Activer les \u00e9v\u00e9nements d'appareil", + "off_delay": "D\u00e9lai d'arr\u00eat", + "off_delay_enabled": "Activer le d\u00e9lai d'arr\u00eat", "replace_device": "S\u00e9lectionnez l'appareil \u00e0 remplacer", "signal_repetitions": "Nombre de r\u00e9p\u00e9titions du signal" }, diff --git a/homeassistant/components/ruckus_unleashed/translations/fr.json b/homeassistant/components/ruckus_unleashed/translations/fr.json new file mode 100644 index 0000000000000..855ecee20dd73 --- /dev/null +++ b/homeassistant/components/ruckus_unleashed/translations/fr.json @@ -0,0 +1,22 @@ +{ + "config": { + "abort": { + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + }, + "error": { + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide", + "unknown": "Erreur inattendue" + }, + "step": { + "user": { + "data": { + "host": "H\u00f4te", + "password": "Mot de passe", + "username": "Nom d'utilisateur" + } + } + } + }, + "title": "Ruckus Unleashed" +} \ No newline at end of file diff --git a/homeassistant/components/samsungtv/translations/fr.json b/homeassistant/components/samsungtv/translations/fr.json index 43fa17aa315b6..be2199c8f0387 100644 --- a/homeassistant/components/samsungtv/translations/fr.json +++ b/homeassistant/components/samsungtv/translations/fr.json @@ -4,6 +4,7 @@ "already_configured": "Ce t\u00e9l\u00e9viseur Samsung est d\u00e9j\u00e0 configur\u00e9.", "already_in_progress": "La configuration du t\u00e9l\u00e9viseur Samsung est d\u00e9j\u00e0 en cours.", "auth_missing": "Home Assistant n'est pas autoris\u00e9 \u00e0 se connecter \u00e0 ce t\u00e9l\u00e9viseur Samsung. Veuillez v\u00e9rifier les param\u00e8tres de votre t\u00e9l\u00e9viseur pour autoriser Home Assistant.", + "cannot_connect": "\u00c9chec de connexion", "not_successful": "Impossible de se connecter \u00e0 cet appareil Samsung TV.", "not_supported": "Ce t\u00e9l\u00e9viseur Samsung n'est actuellement pas pris en charge." }, diff --git a/homeassistant/components/sharkiq/translations/fr.json b/homeassistant/components/sharkiq/translations/fr.json index b867170a4d2fe..224493d158133 100644 --- a/homeassistant/components/sharkiq/translations/fr.json +++ b/homeassistant/components/sharkiq/translations/fr.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "already_configured_account": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "cannot_connect": "\u00c9chec de connexion", "reauth_successful": "Jeton d'acc\u00e8s mis \u00e0 jour avec succ\u00e8s", diff --git a/homeassistant/components/shelly/translations/fr.json b/homeassistant/components/shelly/translations/fr.json index 0f62629d21a60..5266f657b4862 100644 --- a/homeassistant/components/shelly/translations/fr.json +++ b/homeassistant/components/shelly/translations/fr.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", + "unsupported_firmware": "L'appareil utilise une version de micrologiciel non prise en charge." }, "error": { "auth_not_supported": "Les appareils Shelly n\u00e9cessitant une authentification ne sont actuellement pas pris en charge.", @@ -23,7 +24,8 @@ "user": { "data": { "host": "H\u00f4te" - } + }, + "description": "Avant la configuration, l'appareil aliment\u00e9 par batterie doit \u00eatre r\u00e9veill\u00e9 en appuyant sur le bouton de l'appareil." } } }, diff --git a/homeassistant/components/simplisafe/translations/fr.json b/homeassistant/components/simplisafe/translations/fr.json index 54f89eb3ab4d5..69ac7bbb3278c 100644 --- a/homeassistant/components/simplisafe/translations/fr.json +++ b/homeassistant/components/simplisafe/translations/fr.json @@ -6,6 +6,7 @@ }, "error": { "identifier_exists": "Compte d\u00e9j\u00e0 enregistr\u00e9", + "invalid_auth": "Authentification invalide", "invalid_credentials": "Informations d'identification invalides", "still_awaiting_mfa": "En attente de clic sur le message \u00e9lectronique d'authentification multi facteur", "unknown": "Erreur inattendue" diff --git a/homeassistant/components/smappee/translations/fr.json b/homeassistant/components/smappee/translations/fr.json index 4bbed6615ca86..ecc680e5439d5 100644 --- a/homeassistant/components/smappee/translations/fr.json +++ b/homeassistant/components/smappee/translations/fr.json @@ -4,6 +4,7 @@ "already_configured_device": "L'appareil est d\u00e9j\u00e0 configur\u00e9", "already_configured_local_device": "Le ou les p\u00e9riph\u00e9riques locaux sont d\u00e9j\u00e0 configur\u00e9s. Veuillez les supprimer avant de configurer un appareil cloud.", "authorize_url_timeout": "D\u00e9lai de g\u00e9n\u00e9ration de l'URL d'authentification d\u00e9pass\u00e9.", + "cannot_connect": "\u00c9chec de connexion", "connection_error": "\u00c9chec de la connexion \u00e0 l'appareil Smappee.", "invalid_mdns": "Appareil non pris en charge pour l'int\u00e9gration Smappee.", "missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation.", diff --git a/homeassistant/components/smarthab/translations/fr.json b/homeassistant/components/smarthab/translations/fr.json index 798f252ac5d69..361d48a3e91f4 100644 --- a/homeassistant/components/smarthab/translations/fr.json +++ b/homeassistant/components/smarthab/translations/fr.json @@ -1,7 +1,9 @@ { "config": { "error": { + "invalid_auth": "Authentification invalide", "service": "Erreur de connexion \u00e0 SmartHab. V\u00e9rifiez votre connexion. Le service peut \u00eatre indisponible.", + "unknown": "Erreur inattendue", "unknown_error": "Erreur inattendue", "wrong_login": "Authentification invalide" }, diff --git a/homeassistant/components/sonarr/translations/fr.json b/homeassistant/components/sonarr/translations/fr.json index 91d3b0db419c9..058b7dfe498f1 100644 --- a/homeassistant/components/sonarr/translations/fr.json +++ b/homeassistant/components/sonarr/translations/fr.json @@ -2,6 +2,7 @@ "config": { "abort": { "already_configured": "Le service est d\u00e9j\u00e0 configur\u00e9", + "reauth_successful": "La r\u00e9-authentification a r\u00e9ussi", "unknown": "Erreur innatendue" }, "error": { @@ -11,6 +12,7 @@ "flow_title": "Sonarr: {name}", "step": { "reauth_confirm": { + "description": "L'int\u00e9gration Sonarr doit \u00eatre r\u00e9-authentifi\u00e9e manuellement avec l'API Sonarr h\u00e9berg\u00e9e sur: {host}", "title": "R\u00e9-authentifier avec Sonarr" }, "user": { diff --git a/homeassistant/components/starline/translations/cs.json b/homeassistant/components/starline/translations/cs.json index c7446a1cc80b3..4424c594c01da 100644 --- a/homeassistant/components/starline/translations/cs.json +++ b/homeassistant/components/starline/translations/cs.json @@ -9,7 +9,7 @@ "data": { "app_id": "ID aplikace" }, - "description": "ID aplikace a tajn\u00fd k\u00f3d z [\u00fa\u010dtu v\u00fdvoj\u00e1\u0159e StarLine] (https://my.starline.ru/developer)", + "description": "ID aplikace a tajn\u00fd k\u00f3d z [\u00fa\u010dtu v\u00fdvoj\u00e1\u0159e StarLine](https://my.starline.ru/developer)", "title": "P\u0159ihla\u0161ovac\u00ed \u00fadaje aplikace" }, "auth_captcha": { diff --git a/homeassistant/components/synology_dsm/translations/fr.json b/homeassistant/components/synology_dsm/translations/fr.json index 1c411591f1aeb..8cab081129c20 100644 --- a/homeassistant/components/synology_dsm/translations/fr.json +++ b/homeassistant/components/synology_dsm/translations/fr.json @@ -4,7 +4,9 @@ "already_configured": "H\u00f4te d\u00e9j\u00e0 configur\u00e9" }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection": "Erreur de connexion: veuillez v\u00e9rifier votre h\u00f4te, port et SSL", + "invalid_auth": "Authentification invalide", "login": "Erreur de connexion: veuillez v\u00e9rifier votre nom d'utilisateur et votre mot de passe", "missing_data": "Donn\u00e9es manquantes: veuillez r\u00e9essayer plus tard ou utilisez une autre configuration", "otp_failed": "\u00c9chec de l'authentification en deux \u00e9tapes, r\u00e9essayez avec un nouveau code d'acc\u00e8s", diff --git a/homeassistant/components/tasmota/translations/fr.json b/homeassistant/components/tasmota/translations/fr.json new file mode 100644 index 0000000000000..901de884bcd47 --- /dev/null +++ b/homeassistant/components/tasmota/translations/fr.json @@ -0,0 +1,22 @@ +{ + "config": { + "abort": { + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + }, + "error": { + "invalid_discovery_topic": "Pr\u00e9fixe de sujet de d\u00e9couverte non valide." + }, + "step": { + "config": { + "data": { + "discovery_prefix": "Pr\u00e9fixe du sujet de d\u00e9couverte" + }, + "description": "Veuillez entrer la configuration Tasmota.", + "title": "Tasmota" + }, + "confirm": { + "description": "Voulez-vous configurer Tasmota ?" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/tellduslive/translations/fr.json b/homeassistant/components/tellduslive/translations/fr.json index a6c125fb04e81..1c1f08d2b6b73 100644 --- a/homeassistant/components/tellduslive/translations/fr.json +++ b/homeassistant/components/tellduslive/translations/fr.json @@ -7,7 +7,8 @@ "unknown": "Une erreur inconnue s'est produite" }, "error": { - "auth_error": "Erreur d'authentification, veuillez r\u00e9essayer." + "auth_error": "Erreur d'authentification, veuillez r\u00e9essayer.", + "invalid_auth": "Authentification invalide" }, "step": { "auth": { diff --git a/homeassistant/components/tesla/translations/fr.json b/homeassistant/components/tesla/translations/fr.json index 96fe2e9d082c8..6027c232fa021 100644 --- a/homeassistant/components/tesla/translations/fr.json +++ b/homeassistant/components/tesla/translations/fr.json @@ -1,8 +1,12 @@ { "config": { "error": { + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "already_configured_account": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "cannot_connect": "\u00c9chec de connexion", "connection_error": "Erreur de connexion; v\u00e9rifier le r\u00e9seau et r\u00e9essayer", "identifier_exists": "Email d\u00e9j\u00e0 enregistr\u00e9", + "invalid_auth": "Authentification invalide", "invalid_credentials": "Informations d'identification invalides", "unknown_error": "Erreur inconnue, veuillez signaler les informations du journal" }, diff --git a/homeassistant/components/tibber/translations/fr.json b/homeassistant/components/tibber/translations/fr.json index 24fef7886cabb..7e85624b9dfa4 100644 --- a/homeassistant/components/tibber/translations/fr.json +++ b/homeassistant/components/tibber/translations/fr.json @@ -4,6 +4,7 @@ "already_configured": "Un compte Tibber est d\u00e9j\u00e0 configur\u00e9." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_error": "Erreur de connexion \u00e0 Tibber", "invalid_access_token": "Jeton d'acc\u00e8s non valide", "timeout": "D\u00e9lai de connexion \u00e0 Tibber" diff --git a/homeassistant/components/tile/translations/fr.json b/homeassistant/components/tile/translations/fr.json index c39730167f98f..71d7092e44e24 100644 --- a/homeassistant/components/tile/translations/fr.json +++ b/homeassistant/components/tile/translations/fr.json @@ -4,6 +4,7 @@ "already_configured": "Ce compte Tile est d\u00e9j\u00e0 enregistr\u00e9." }, "error": { + "invalid_auth": "Authentification invalide", "invalid_credentials": "Informations d'identification de Tile non valides." }, "step": { diff --git a/homeassistant/components/transmission/translations/fr.json b/homeassistant/components/transmission/translations/fr.json index 6bad4b15a8120..7dbb571d7d8b7 100644 --- a/homeassistant/components/transmission/translations/fr.json +++ b/homeassistant/components/transmission/translations/fr.json @@ -5,6 +5,7 @@ }, "error": { "cannot_connect": "Impossible de se connecter \u00e0 l'h\u00f4te", + "invalid_auth": "Authentification invalide", "name_exists": "Ce nom est d\u00e9j\u00e0 utilis\u00e9", "wrong_credentials": "Mauvais nom d'utilisateur ou mot de passe" }, diff --git a/homeassistant/components/tuya/translations/ca.json b/homeassistant/components/tuya/translations/ca.json index ca88e8b54a42a..aeaa2cdd450ad 100644 --- a/homeassistant/components/tuya/translations/ca.json +++ b/homeassistant/components/tuya/translations/ca.json @@ -24,5 +24,41 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "Per configurar una selecci\u00f3 de m\u00faltiples dispositius, aquests han de ser del mateix tipus", + "dev_not_config": "El tipus d'aquest dispositiu no \u00e9s configurable", + "dev_not_found": "No s'ha trobat el dispositiu." + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Rang de brillantor utilitzat pel dispositiu", + "curr_temp_divider": "Divisor del valor de temperatura actual (0 = predeterminat)", + "ext_temp_sensor": "Sensor per a la temperatura actual", + "max_kelvin": "Temperatura del color m\u00e0xima suportada, en Kelvin", + "max_temp": "Temperatura desitjada m\u00e0xima (utilitza min i max = 0 per defecte)", + "min_kelvin": "Temperatura del color m\u00ednima suportada, en Kelvin", + "min_temp": "Temperatura desitjada m\u00ednima (utilitza min i max = 0 per defecte)", + "support_color": "For\u00e7a el suport de color", + "temp_divider": "Divisor del valor de temperatura (0 = predeterminat)", + "tuya_max_coltemp": "Temperatura de color m\u00e0xima enviada pel dispositiu", + "unit_of_measurement": "Unitat de temperatura utilitzada pel dispositiu" + }, + "description": "Configura les opcions per ajustar la informaci\u00f3 mostrada per {device_type} dispositiu `{device_name}`", + "title": "Configuraci\u00f3 de dispositiu Tuya" + }, + "init": { + "data": { + "discovery_interval": "Interval de sondeig del dispositiu de descoberta, en segons", + "list_devices": "Selecciona els dispositius a configurar o deixa-ho buit per desar la configuraci\u00f3", + "query_device": "Selecciona el dispositiu que utilitzar\u00e0 m\u00e8tode de consulta, per actualitzacions d'estat m\u00e9s freq\u00fcents", + "query_interval": "Interval de sondeig de consultes del dispositiu, en segons" + }, + "description": "No estableixis valors d'interval de sondeig massa baixos ja que les crides fallaran i generaran missatges d'error al registre", + "title": "Configuraci\u00f3 d'opcions de Tuya" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/es.json b/homeassistant/components/tuya/translations/es.json index 41ab447ec8e8a..9149ec33c1666 100644 --- a/homeassistant/components/tuya/translations/es.json +++ b/homeassistant/components/tuya/translations/es.json @@ -24,5 +24,38 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "Los m\u00faltiples dispositivos seleccionados para configurar deben ser del mismo tipo", + "dev_not_config": "Tipo de dispositivo no configurable", + "dev_not_found": "Dispositivo no encontrado" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Rango de brillo utilizado por el dispositivo", + "curr_temp_divider": "Divisor del valor de la temperatura actual (0 = usar valor por defecto)", + "ext_temp_sensor": "Sensor para la temperatura actual", + "max_kelvin": "Temperatura de color m\u00e1xima admitida en kelvin", + "max_temp": "Temperatura objetivo m\u00e1xima (usa m\u00edn. y m\u00e1x. = 0 por defecto)", + "min_kelvin": "Temperatura de color m\u00ednima soportada en kelvin", + "min_temp": "Temperatura objetivo m\u00ednima (usa m\u00edn. y m\u00e1x. = 0 por defecto)", + "support_color": "Forzar soporte de color", + "temp_divider": "Divisor de los valores de temperatura (0 = usar valor por defecto)", + "tuya_max_coltemp": "Temperatura de color m\u00e1xima notificada por dispositivo", + "unit_of_measurement": "Unidad de temperatura utilizada por el dispositivo" + }, + "description": "Configura las opciones para ajustar la informaci\u00f3n mostrada para {device_type} dispositivo `{device_name}`", + "title": "Configurar dispositivo Tuya" + }, + "init": { + "data": { + "list_devices": "Selecciona los dispositivos a configurar o d\u00e9jalos en blanco para guardar la configuraci\u00f3n", + "query_device": "Selecciona el dispositivo que utilizar\u00e1 el m\u00e9todo de consulta para una actualizaci\u00f3n de estado m\u00e1s r\u00e1pida" + }, + "title": "Configurar opciones de Tuya" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/fr.json b/homeassistant/components/tuya/translations/fr.json index cbd71b0cbd18b..8edd8318650f3 100644 --- a/homeassistant/components/tuya/translations/fr.json +++ b/homeassistant/components/tuya/translations/fr.json @@ -2,11 +2,14 @@ "config": { "abort": { "auth_failed": "Authentification invalide", + "cannot_connect": "\u00c9chec de connexion", "conn_error": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide", "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { - "auth_failed": "Authentification invalide" + "auth_failed": "Authentification invalide", + "invalid_auth": "Authentification invalide" }, "flow_title": "Configuration Tuya", "step": { @@ -21,5 +24,41 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "Plusieurs p\u00e9riph\u00e9riques s\u00e9lectionn\u00e9s \u00e0 configurer doivent \u00eatre du m\u00eame type", + "dev_not_config": "Type d'appareil non configurable", + "dev_not_found": "Appareil non trouv\u00e9" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Plage de luminosit\u00e9 utilis\u00e9e par l'appareil", + "curr_temp_divider": "Diviseur de valeur de temp\u00e9rature actuelle (0 = utiliser la valeur par d\u00e9faut)", + "ext_temp_sensor": "Capteur de temp\u00e9rature actuelle", + "max_kelvin": "Temp\u00e9rature de couleur maximale prise en charge en Kelvin", + "max_temp": "Temp\u00e9rature cible maximale (utilisez min et max = 0 par d\u00e9faut)", + "min_kelvin": "Temp\u00e9rature de couleur minimale prise en charge en kelvin", + "min_temp": "Temp\u00e9rature cible minimale (utilisez min et max = 0 par d\u00e9faut)", + "support_color": "Forcer la prise en charge des couleurs", + "temp_divider": "Diviseur de valeurs de temp\u00e9rature (0 = utiliser la valeur par d\u00e9faut)", + "tuya_max_coltemp": "Temp\u00e9rature de couleur maximale rapport\u00e9e par l'appareil", + "unit_of_measurement": "Unit\u00e9 de temp\u00e9rature utilis\u00e9e par l'appareil" + }, + "description": "Configurer les options pour ajuster les informations affich\u00e9es pour l'appareil {device_type} ` {device_name} `", + "title": "Configurer l'appareil Tuya" + }, + "init": { + "data": { + "discovery_interval": "Intervalle de d\u00e9couverte de l'appareil en secondes", + "list_devices": "S\u00e9lectionnez les appareils \u00e0 configurer ou laissez vide pour enregistrer la configuration", + "query_device": "S\u00e9lectionnez l'appareil qui utilisera la m\u00e9thode de requ\u00eate pour une mise \u00e0 jour plus rapide de l'\u00e9tat", + "query_interval": "Intervalle d'interrogation de l'appareil en secondes" + }, + "description": "Ne d\u00e9finissez pas des valeurs d'intervalle d'interrogation trop faibles ou les appels \u00e9choueront \u00e0 g\u00e9n\u00e9rer un message d'erreur dans le journal", + "title": "Configurer les options de Tuya" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/pl.json b/homeassistant/components/tuya/translations/pl.json index 3e7b62d21eaf3..3e15f133c5f9f 100644 --- a/homeassistant/components/tuya/translations/pl.json +++ b/homeassistant/components/tuya/translations/pl.json @@ -24,5 +24,41 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "Wybrane urz\u0105dzenia do skonfigurowania musz\u0105 by\u0107 tego samego typu", + "dev_not_config": "Typ urz\u0105dzenia nie jest konfigurowalny", + "dev_not_found": "Nie znaleziono urz\u0105dzenia" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Zakres jasno\u015bci u\u017cywany przez urz\u0105dzenie", + "curr_temp_divider": "Dzielnik aktualnej warto\u015bci temperatury (0 = u\u017cyj warto\u015bci domy\u015blnej)", + "ext_temp_sensor": "Sensor aktualnej temperatury", + "max_kelvin": "Maksymalna obs\u0142ugiwana temperatura barwy w kelwinach", + "max_temp": "Maksymalna temperatura docelowa (u\u017cyj min i max = 0 dla warto\u015bci domy\u015blnej)", + "min_kelvin": "Minimalna obs\u0142ugiwana temperatura barwy w kelwinach", + "min_temp": "Minimalna temperatura docelowa (u\u017cyj min i max = 0 dla warto\u015bci domy\u015blnej)", + "support_color": "Wymu\u015b obs\u0142ug\u0119 kolor\u00f3w", + "temp_divider": "Dzielnik warto\u015bci temperatury (0 = u\u017cyj warto\u015bci domy\u015blnej)", + "tuya_max_coltemp": "Maksymalna temperatura barwy raportowana przez urz\u0105dzenie", + "unit_of_measurement": "Jednostka temperatury u\u017cywana przez urz\u0105dzenie" + }, + "description": "Skonfiguruj opcje, aby dostosowa\u0107 wy\u015bwietlane informacje dla urz\u0105dzenia {device_type} `{device_name}'", + "title": "Konfiguracja urz\u0105dzenia Tuya" + }, + "init": { + "data": { + "discovery_interval": "Cz\u0119stotliwo\u015b\u0107 skanowania nowych urz\u0105dze\u0144 (w sekundach)", + "list_devices": "Wybierz urz\u0105dzenia do skonfigurowania lub pozostaw puste, aby zapisa\u0107 konfiguracj\u0119", + "query_device": "Wybierz urz\u0105dzenie, kt\u00f3re b\u0119dzie u\u017cywa\u0107 metody odpytywania w celu szybszej aktualizacji statusu", + "query_interval": "Cz\u0119stotliwo\u015b\u0107 skanowania odpytywanego urz\u0105dzenia (w sekundach)" + }, + "description": "Nie ustawiaj zbyt niskich warto\u015bci skanowania, bo zako\u0144cz\u0105 si\u0119 niepowodzeniem, generuj\u0105c komunikat o b\u0142\u0119dzie w logu", + "title": "Konfiguracja opcji Tuya" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/translations/fr.json b/homeassistant/components/twentemilieu/translations/fr.json index bbdd8f92d7b13..a39b6e3237e95 100644 --- a/homeassistant/components/twentemilieu/translations/fr.json +++ b/homeassistant/components/twentemilieu/translations/fr.json @@ -1,9 +1,11 @@ { "config": { "abort": { - "address_exists": "Adresse d\u00e9j\u00e0 configur\u00e9e." + "address_exists": "Adresse d\u00e9j\u00e0 configur\u00e9e.", + "already_configured": "L'emplacement est d\u00e9j\u00e0 configur\u00e9" }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connection_error": "\u00c9chec de connexion.", "invalid_address": "Adresse introuvable dans la zone de service de Twente Milieu." }, diff --git a/homeassistant/components/twilio/translations/ca.json b/homeassistant/components/twilio/translations/ca.json index b4adcdb1cb49a..a64af0389c027 100644 --- a/homeassistant/components/twilio/translations/ca.json +++ b/homeassistant/components/twilio/translations/ca.json @@ -10,7 +10,7 @@ }, "step": { "user": { - "description": "Est\u00e0s segur que vols configurar Twilio?", + "description": "Vols comen\u00e7ar la configuraci\u00f3?", "title": "Configuraci\u00f3 del Webhook de Twilio" } } diff --git a/homeassistant/components/twilio/translations/cs.json b/homeassistant/components/twilio/translations/cs.json index 1b5acf2107702..a100f0c48129e 100644 --- a/homeassistant/components/twilio/translations/cs.json +++ b/homeassistant/components/twilio/translations/cs.json @@ -10,7 +10,7 @@ }, "step": { "user": { - "description": "Opravdu chcete nastavit slu\u017ebu Twilio?", + "description": "Chcete za\u010d\u00edt nastavovat?", "title": "Nastaven\u00ed Twilio Webhook" } } diff --git a/homeassistant/components/twilio/translations/en.json b/homeassistant/components/twilio/translations/en.json index de5d921dec2b0..8ca163188b36c 100644 --- a/homeassistant/components/twilio/translations/en.json +++ b/homeassistant/components/twilio/translations/en.json @@ -10,7 +10,7 @@ }, "step": { "user": { - "description": "Are you sure you want to set up Twilio?", + "description": "Do you want to start set up?", "title": "Set up the Twilio Webhook" } } diff --git a/homeassistant/components/twilio/translations/no.json b/homeassistant/components/twilio/translations/no.json index 3f73ce0d3e0dc..89480a8ecbd93 100644 --- a/homeassistant/components/twilio/translations/no.json +++ b/homeassistant/components/twilio/translations/no.json @@ -10,7 +10,7 @@ }, "step": { "user": { - "description": "Er du sikker p\u00e5 at du \u00f8nsker \u00e5 sette opp Twilio?", + "description": "Vil du starte oppsettet?", "title": "Sett opp Twilio Webhook" } } diff --git a/homeassistant/components/twilio/translations/ru.json b/homeassistant/components/twilio/translations/ru.json index 74972ab9b0828..f156eb4dbfeef 100644 --- a/homeassistant/components/twilio/translations/ru.json +++ b/homeassistant/components/twilio/translations/ru.json @@ -10,7 +10,7 @@ }, "step": { "user": { - "description": "\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Twilio?", + "description": "\u0425\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443?", "title": "Twilio" } } diff --git a/homeassistant/components/twilio/translations/zh-Hant.json b/homeassistant/components/twilio/translations/zh-Hant.json index 1f07a1f44e10d..caf905009609d 100644 --- a/homeassistant/components/twilio/translations/zh-Hant.json +++ b/homeassistant/components/twilio/translations/zh-Hant.json @@ -10,7 +10,7 @@ }, "step": { "user": { - "description": "\u662f\u5426\u8981\u8a2d\u5b9a Twilio\uff1f", + "description": "\u662f\u5426\u8981\u958b\u59cb\u8a2d\u5b9a\uff1f", "title": "\u8a2d\u5b9a Twilio Webhook" } } diff --git a/homeassistant/components/upb/translations/fr.json b/homeassistant/components/upb/translations/fr.json index ae90d4b9f5502..98a27d37ef0a7 100644 --- a/homeassistant/components/upb/translations/fr.json +++ b/homeassistant/components/upb/translations/fr.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "address_already_configured": "Un UPB PIM avec cette adresse est d\u00e9j\u00e0 configur\u00e9." + "address_already_configured": "Un UPB PIM avec cette adresse est d\u00e9j\u00e0 configur\u00e9.", + "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9" }, "error": { "cannot_connect": "Impossible de se connecter \u00e0 UPB PIM, veuillez r\u00e9essayer.", diff --git a/homeassistant/components/upcloud/translations/fr.json b/homeassistant/components/upcloud/translations/fr.json new file mode 100644 index 0000000000000..e4fe2301f6a6a --- /dev/null +++ b/homeassistant/components/upcloud/translations/fr.json @@ -0,0 +1,25 @@ +{ + "config": { + "error": { + "cannot_connect": "\u00c9chec de connexion", + "invalid_auth": "Authentification invalide" + }, + "step": { + "user": { + "data": { + "password": "Mot de passe", + "username": "Nom d'utilisateur" + } + } + } + }, + "options": { + "step": { + "init": { + "data": { + "scan_interval": "Intervalle de mise \u00e0 jour en secondes, minimum 30" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/velbus/translations/fr.json b/homeassistant/components/velbus/translations/fr.json index 1c771b9d7a2cd..4c756cc747de5 100644 --- a/homeassistant/components/velbus/translations/fr.json +++ b/homeassistant/components/velbus/translations/fr.json @@ -6,6 +6,7 @@ }, "error": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", + "cannot_connect": "\u00c9chec de connexion", "connection_failed": "La connexion velbus a \u00e9chou\u00e9", "port_exists": "Ce port est d\u00e9j\u00e0 configur\u00e9" }, diff --git a/homeassistant/components/vesync/translations/fr.json b/homeassistant/components/vesync/translations/fr.json index 0d00100ae059e..68ba5a18ecb8b 100644 --- a/homeassistant/components/vesync/translations/fr.json +++ b/homeassistant/components/vesync/translations/fr.json @@ -1,9 +1,11 @@ { "config": { "abort": { - "already_setup": "Une seule instance de Vesync est autoris\u00e9e" + "already_setup": "Une seule instance de Vesync est autoris\u00e9e", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { + "invalid_auth": "Authentification invalide", "invalid_login": "Nom d'utilisateur ou mot de passe invalide" }, "step": { diff --git a/homeassistant/components/water_heater/translations/fr.json b/homeassistant/components/water_heater/translations/fr.json new file mode 100644 index 0000000000000..ac72ffab88361 --- /dev/null +++ b/homeassistant/components/water_heater/translations/fr.json @@ -0,0 +1,8 @@ +{ + "device_automation": { + "action_type": { + "turn_off": "\u00c9teindre {entity_name}", + "turn_on": "Allumer {entity_name}" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/withings/translations/fr.json b/homeassistant/components/withings/translations/fr.json index a51efff72766d..4ef450e6059db 100644 --- a/homeassistant/components/withings/translations/fr.json +++ b/homeassistant/components/withings/translations/fr.json @@ -10,6 +10,8 @@ "default": "Authentifi\u00e9 avec succ\u00e8s \u00e0 Withings pour le profil s\u00e9lectionn\u00e9." }, "error": { + "already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", + "already_configured_account": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9", "profile_exists": "Le profil utilisateur est d\u00e9j\u00e0 configur\u00e9. Veuillez fournir un nom de profil unique." }, "flow_title": "Withings: {profile}", diff --git a/homeassistant/components/xbox/translations/fr.json b/homeassistant/components/xbox/translations/fr.json new file mode 100644 index 0000000000000..989bf28f58596 --- /dev/null +++ b/homeassistant/components/xbox/translations/fr.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "authorize_url_timeout": "D\u00e9lai de g\u00e9n\u00e9ration de l'URL d'authentification d\u00e9pass\u00e9.", + "missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation.", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." + }, + "create_entry": { + "default": "Authentification r\u00e9ussie" + }, + "step": { + "pick_implementation": { + "title": "S\u00e9lectionner une m\u00e9thode d'authentification" + } + } + }, + "title": "Xbox" +} \ No newline at end of file diff --git a/homeassistant/components/xiaomi_miio/translations/fr.json b/homeassistant/components/xiaomi_miio/translations/fr.json index e76e5a1ef694c..5db4e5a19ec5e 100644 --- a/homeassistant/components/xiaomi_miio/translations/fr.json +++ b/homeassistant/components/xiaomi_miio/translations/fr.json @@ -5,6 +5,7 @@ "already_in_progress": "Le flux de configuration pour cet appareil Xiaomi Miio est d\u00e9j\u00e0 en cours." }, "error": { + "cannot_connect": "\u00c9chec de connexion", "connect_error": "\u00c9chec de connexion", "no_device_selected": "Aucun appareil s\u00e9lectionn\u00e9, veuillez s\u00e9lectionner un appareil." }, diff --git a/homeassistant/components/zha/translations/ru.json b/homeassistant/components/zha/translations/ru.json index 4070d759a90a9..b97e27ced5d62 100644 --- a/homeassistant/components/zha/translations/ru.json +++ b/homeassistant/components/zha/translations/ru.json @@ -46,8 +46,8 @@ "button_5": "\u041f\u044f\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", "button_6": "\u0428\u0435\u0441\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", "close": "\u0417\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f", - "dim_down": "\u042f\u0440\u043a\u043e\u0441\u0442\u044c \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442\u0441\u044f", - "dim_up": "\u042f\u0440\u043a\u043e\u0441\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f", + "dim_down": "\u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u044f\u0440\u043a\u043e\u0441\u0442\u044c", + "dim_up": "\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u044f\u0440\u043a\u043e\u0441\u0442\u044c", "face_1": "\u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u0439 \u0433\u0440\u0430\u043d\u0438", "face_2": "\u043d\u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0433\u0440\u0430\u043d\u0438", "face_3": "\u043d\u0430 \u0442\u0440\u0435\u0442\u0435\u0439 \u0433\u0440\u0430\u043d\u0438", @@ -58,8 +58,8 @@ "left": "\u043d\u0430\u043b\u0435\u0432\u043e", "open": "\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f", "right": "\u043d\u0430\u043f\u0440\u0430\u0432\u043e", - "turn_off": "\u0412\u044b\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f", - "turn_on": "\u0412\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f" + "turn_off": "\u0412\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c", + "turn_on": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c" }, "trigger_type": { "device_dropped": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441\u0431\u0440\u043e\u0441\u0438\u043b\u0438", @@ -71,20 +71,20 @@ "device_slid": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441\u0434\u0432\u0438\u043d\u0443\u043b\u0438 {subtype}", "device_tilted": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0430\u043a\u043b\u043e\u043d\u0438\u043b\u0438", "remote_button_alt_double_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", - "remote_button_alt_long_press": "{subtype} \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e \u043d\u0430\u0436\u0430\u0442\u0430 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", - "remote_button_alt_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", - "remote_button_alt_quadruple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", + "remote_button_alt_long_press": "{subtype} \u0434\u043e\u043b\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0430 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", + "remote_button_alt_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", + "remote_button_alt_quadruple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", "remote_button_alt_quintuple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", "remote_button_alt_short_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", - "remote_button_alt_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", + "remote_button_alt_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", "remote_button_alt_triple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0442\u0440\u0438 \u0440\u0430\u0437\u0430 (\u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c)", "remote_button_double_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430", - "remote_button_long_press": "{subtype} \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e \u043d\u0430\u0436\u0430\u0442\u0430", - "remote_button_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "remote_button_long_press": "{subtype} \u0434\u043e\u043b\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0430", + "remote_button_long_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", "remote_button_quadruple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430", "remote_button_quintuple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437", "remote_button_short_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430", - "remote_button_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430", + "remote_button_short_release": "{subtype} \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", "remote_button_triple_press": "{subtype} \u043d\u0430\u0436\u0430\u0442\u0430 \u0442\u0440\u0438 \u0440\u0430\u0437\u0430" } } diff --git a/homeassistant/components/zwave/translations/fr.json b/homeassistant/components/zwave/translations/fr.json index d60a1c9f11e0f..cc753548f690e 100644 --- a/homeassistant/components/zwave/translations/fr.json +++ b/homeassistant/components/zwave/translations/fr.json @@ -2,7 +2,8 @@ "config": { "abort": { "already_configured": "Z-Wave est d\u00e9j\u00e0 configur\u00e9", - "one_instance_only": "Le composant ne prend en charge qu'une seule instance Z-Wave" + "one_instance_only": "Le composant ne prend en charge qu'une seule instance Z-Wave", + "single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible." }, "error": { "option_error": "La validation Z-Wave a \u00e9chou\u00e9. Le chemin d'acc\u00e8s \u00e0 la cl\u00e9 USB est-il correct?" From f78e75e16fa1202f8a85c8c172855cdc90d19d30 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Thu, 29 Oct 2020 18:04:12 -0600 Subject: [PATCH 22/43] Properly unload listener for AirVisual config entry updates (#42583) --- homeassistant/components/airvisual/__init__.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/airvisual/__init__.py b/homeassistant/components/airvisual/__init__.py index ef8a4ced1bd31..9b7fe5c258383 100644 --- a/homeassistant/components/airvisual/__init__.py +++ b/homeassistant/components/airvisual/__init__.py @@ -45,6 +45,8 @@ PLATFORMS = ["air_quality", "sensor"] +DATA_LISTENER = "listener" + DEFAULT_ATTRIBUTION = "Data provided by AirVisual" DEFAULT_NODE_PRO_UPDATE_INTERVAL = timedelta(minutes=1) DEFAULT_OPTIONS = {CONF_SHOW_ON_MAP: True} @@ -151,7 +153,7 @@ def async_sync_geo_coordinator_update_intervals(hass, api_key): async def async_setup(hass, config): """Set up the AirVisual component.""" - hass.data[DOMAIN] = {DATA_COORDINATOR: {}} + hass.data[DOMAIN] = {DATA_COORDINATOR: {}, DATA_LISTENER: {}} if DOMAIN not in config: return True @@ -281,7 +283,9 @@ async def async_update_data(): ) # Only geography-based entries have options: - config_entry.add_update_listener(async_reload_entry) + hass.data[DOMAIN][DATA_LISTENER][ + config_entry.entry_id + ] = config_entry.add_update_listener(async_reload_entry) else: _standardize_node_pro_config_entry(hass, config_entry) @@ -365,9 +369,12 @@ async def async_unload_entry(hass, config_entry): ) if unload_ok: hass.data[DOMAIN][DATA_COORDINATOR].pop(config_entry.entry_id) + remove_listener = hass.data[DOMAIN][DATA_LISTENER].pop(config_entry.entry_id) + remove_listener() + if config_entry.data[CONF_INTEGRATION_TYPE] == INTEGRATION_TYPE_GEOGRAPHY: - # Re-calculate the update interval period for any remaining consumes of this - # API key: + # Re-calculate the update interval period for any remaining consumers of + # this API key: async_sync_geo_coordinator_update_intervals( hass, config_entry.data[CONF_API_KEY] ) From 2bbd2a6e70fb0d7ed26edf998f35d2698a5e2602 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 29 Oct 2020 22:35:51 -0500 Subject: [PATCH 23/43] Reduce complexity of storage writes (#42576) * Reduce complexity of storage writes * add test * stop hass * workaround bad test --- homeassistant/core.py | 2 +- homeassistant/helpers/storage.py | 18 ++++---- .../pvpc_hourly_pricing/test_sensor.py | 6 ++- tests/helpers/test_storage.py | 43 +++++++++++++++++++ tests/helpers/test_storage_remove.py | 36 ++++++++++++++++ 5 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 tests/helpers/test_storage_remove.py diff --git a/homeassistant/core.py b/homeassistant/core.py index ca4a27eef3da8..295e813a642ee 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -820,7 +820,7 @@ def _async_remove_listener(self, event_type: str, hassjob: HassJob) -> None: except (KeyError, ValueError): # KeyError is key event_type listener did not exist # ValueError if listener did not exist within event_type - _LOGGER.warning("Unable to remove unknown job listener %s", hassjob) + _LOGGER.exception("Unable to remove unknown job listener %s", hassjob) class State: diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index daf9e2f6a89f2..29e50f06f1acb 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -138,9 +138,6 @@ async def async_save(self, data: Union[Dict, List]) -> None: """Save data.""" self._data = {"version": self.version, "key": self.key, "data": data} - self._async_cleanup_delay_listener() - self._async_cleanup_final_write_listener() - if self.hass.state == CoreState.stopping: self._async_ensure_final_write_listener() return @@ -153,16 +150,14 @@ def async_delay_save(self, data_func: Callable[[], Dict], delay: float = 0) -> N self._data = {"version": self.version, "key": self.key, "data_func": data_func} self._async_cleanup_delay_listener() - self._async_cleanup_final_write_listener() + self._async_ensure_final_write_listener() if self.hass.state == CoreState.stopping: - self._async_ensure_final_write_listener() return self._unsub_delay_listener = async_call_later( self.hass, delay, self._async_callback_delayed_write ) - self._async_ensure_final_write_listener() @callback def _async_ensure_final_write_listener(self): @@ -192,20 +187,20 @@ async def _async_callback_delayed_write(self, _now): if self.hass.state == CoreState.stopping: self._async_ensure_final_write_listener() return - self._unsub_delay_listener = None - self._async_cleanup_final_write_listener() await self._async_handle_write_data() async def _async_callback_final_write(self, _event): """Handle a write because Home Assistant is in final write state.""" self._unsub_final_write_listener = None - self._async_cleanup_delay_listener() await self._async_handle_write_data() async def _async_handle_write_data(self, *_args): """Handle writing the config.""" async with self._write_lock: + self._async_cleanup_delay_listener() + self._async_cleanup_final_write_listener() + if self._data is None: # Another write already consumed the data return @@ -229,7 +224,7 @@ def _write_data(self, path: str, data: Dict) -> None: if not os.path.isdir(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) - _LOGGER.debug("Writing data for %s", self.key) + _LOGGER.debug("Writing data for %s to %s", self.key, path) json_util.save_json(path, data, self._private, encoder=self._encoder) async def _async_migrate_func(self, old_version, old_data): @@ -238,6 +233,9 @@ async def _async_migrate_func(self, old_version, old_data): async def async_remove(self): """Remove all data.""" + self._async_cleanup_delay_listener() + self._async_cleanup_final_write_listener() + try: await self.hass.async_add_executor_job(os.unlink, self.path) except FileNotFoundError: diff --git a/tests/components/pvpc_hourly_pricing/test_sensor.py b/tests/components/pvpc_hourly_pricing/test_sensor.py index 6dae784a0cc87..ca3dec1e89126 100644 --- a/tests/components/pvpc_hourly_pricing/test_sensor.py +++ b/tests/components/pvpc_hourly_pricing/test_sensor.py @@ -54,7 +54,11 @@ def mock_now(): # sensor has no more prices, state is "unavailable" from now on await _process_time_step(hass, mock_data, value="unavailable") await _process_time_step(hass, mock_data, value="unavailable") - num_errors = sum(1 for x in caplog.records if x.levelno == logging.ERROR) + num_errors = sum( + 1 + for x in caplog.records + if x.levelno == logging.ERROR and "unknown job listener" not in x.msg + ) num_warnings = sum(1 for x in caplog.records if x.levelno == logging.WARNING) assert num_warnings == 1 assert num_errors == 0 diff --git a/tests/helpers/test_storage.py b/tests/helpers/test_storage.py index 6325294033f4d..7fa6dd61845ac 100644 --- a/tests/helpers/test_storage.py +++ b/tests/helpers/test_storage.py @@ -186,6 +186,49 @@ async def test_writing_while_writing_delay(hass, store, hass_storage): assert data == {"delay": "no"} +async def test_multiple_delay_save_calls(hass, store, hass_storage): + """Test a write while a write with changing delays.""" + store.async_delay_save(lambda: {"delay": "yes"}, 1) + store.async_delay_save(lambda: {"delay": "yes"}, 2) + store.async_delay_save(lambda: {"delay": "yes"}, 3) + + assert store.key not in hass_storage + await store.async_save({"delay": "no"}) + assert hass_storage[store.key] == { + "version": MOCK_VERSION, + "key": MOCK_KEY, + "data": {"delay": "no"}, + } + + async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=1)) + await hass.async_block_till_done() + assert hass_storage[store.key] == { + "version": MOCK_VERSION, + "key": MOCK_KEY, + "data": {"delay": "no"}, + } + + data = await store.async_load() + assert data == {"delay": "no"} + + +async def test_multiple_save_calls(hass, store, hass_storage): + """Test multiple write tasks.""" + + assert store.key not in hass_storage + + tasks = [store.async_save({"savecount": savecount}) for savecount in range(6)] + await asyncio.gather(*tasks) + assert hass_storage[store.key] == { + "version": MOCK_VERSION, + "key": MOCK_KEY, + "data": {"savecount": 5}, + } + + data = await store.async_load() + assert data == {"savecount": 5} + + async def test_migrator_no_existing_config(hass, store, hass_storage): """Test migrator with no existing config.""" with patch("os.path.isfile", return_value=False), patch.object( diff --git a/tests/helpers/test_storage_remove.py b/tests/helpers/test_storage_remove.py new file mode 100644 index 0000000000000..9a447771ea630 --- /dev/null +++ b/tests/helpers/test_storage_remove.py @@ -0,0 +1,36 @@ +"""Tests for the storage helper with minimal mocking.""" +import asyncio +from datetime import timedelta +import os + +from homeassistant.helpers import storage +from homeassistant.util import dt + +from tests.async_mock import patch +from tests.common import async_fire_time_changed, async_test_home_assistant + + +async def test_removing_while_delay_in_progress(tmpdir): + """Test removing while delay in progress.""" + + loop = asyncio.get_event_loop() + hass = await async_test_home_assistant(loop) + + test_dir = await hass.async_add_executor_job(tmpdir.mkdir, "storage") + + with patch.object(storage, "STORAGE_DIR", test_dir): + real_store = storage.Store(hass, 1, "remove_me") + + await real_store.async_save({"delay": "no"}) + + assert await hass.async_add_executor_job(os.path.exists, real_store.path) + + real_store.async_delay_save(lambda: {"delay": "yes"}, 1) + + await real_store.async_remove() + assert not await hass.async_add_executor_job(os.path.exists, real_store.path) + + async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=1)) + await hass.async_block_till_done() + assert not await hass.async_add_executor_job(os.path.exists, real_store.path) + await hass.async_stop() From 8a403cde0012e9f26600ec20cdfab39f75e02074 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 30 Oct 2020 03:02:00 -0500 Subject: [PATCH 24/43] Defer esphome persistent storage writes until after startup (#42600) Avoid disk I/O during startup as it can cause delays when a user has many esphome devices. --- homeassistant/components/esphome/entry_data.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/esphome/entry_data.py b/homeassistant/components/esphome/entry_data.py index 8f273b682ff25..54da1ed5562db 100644 --- a/homeassistant/components/esphome/entry_data.py +++ b/homeassistant/components/esphome/entry_data.py @@ -31,6 +31,8 @@ DATA_KEY = "esphome" +SAVE_DELAY = 120 + # Mapping from ESPHome info type to HA platform INFO_TYPE_TO_PLATFORM = { BinarySensorInfo: "binary_sensor", @@ -159,7 +161,7 @@ async def async_save_to_store(self) -> None: for service in self.services.values(): store_data["services"].append(service.to_dict()) - await self.store.async_save(store_data) + self.store.async_delay_save(lambda: store_data, SAVE_DELAY) def _attr_obj_from_dict(cls, **kwargs): From f470d1e28d1f191daccc5164b0dc7175f5d1ef18 Mon Sep 17 00:00:00 2001 From: Rob Bierbooms Date: Fri, 30 Oct 2020 09:11:25 +0100 Subject: [PATCH 25/43] Enable polling for DSMR derivative entity (#42524) --- homeassistant/components/dsmr/sensor.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/homeassistant/components/dsmr/sensor.py b/homeassistant/components/dsmr/sensor.py index 3f642ac92d970..964d28686f874 100644 --- a/homeassistant/components/dsmr/sensor.py +++ b/homeassistant/components/dsmr/sensor.py @@ -358,6 +358,16 @@ def state(self): """Return the calculated current hourly rate.""" return self._state + @property + def force_update(self): + """Disable force update.""" + return False + + @property + def should_poll(self): + """Enable polling.""" + return True + async def async_update(self): """Recalculate hourly rate if timestamp has changed. From 6011756e904faf375e387e9af3bcba4bda674865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Suwa=C5=82a?= <63507293+adriansuwala@users.noreply.github.com> Date: Fri, 30 Oct 2020 09:13:33 +0100 Subject: [PATCH 26/43] Rewrite mfi unittest tests to pytest (#42510) --- tests/components/mfi/test_sensor.py | 298 ++++++++++++++-------------- tests/components/mfi/test_switch.py | 203 +++++++++---------- 2 files changed, 253 insertions(+), 248 deletions(-) diff --git a/tests/components/mfi/test_sensor.py b/tests/components/mfi/test_sensor.py index 05e1379cfb46f..39e67d879587f 100644 --- a/tests/components/mfi/test_sensor.py +++ b/tests/components/mfi/test_sensor.py @@ -1,105 +1,101 @@ """The tests for the mFi sensor platform.""" -import unittest - from mficlient.client import FailedToLogin +import pytest import requests import homeassistant.components.mfi.sensor as mfi -import homeassistant.components.sensor as sensor +import homeassistant.components.sensor as sensor_component from homeassistant.const import TEMP_CELSIUS -from homeassistant.setup import setup_component +from homeassistant.setup import async_setup_component import tests.async_mock as mock -from tests.common import get_test_home_assistant - - -class TestMfiSensorSetup(unittest.TestCase): - """Test the mFi sensor platform.""" - - PLATFORM = mfi - COMPONENT = sensor - THING = "sensor" - GOOD_CONFIG = { - "sensor": { - "platform": "mfi", - "host": "foo", - "port": 6123, - "username": "user", - "password": "pass", - "ssl": True, - "verify_ssl": True, - } - } - def setup_method(self, method): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() +PLATFORM = mfi +COMPONENT = sensor_component +THING = "sensor" +GOOD_CONFIG = { + "sensor": { + "platform": "mfi", + "host": "foo", + "port": 6123, + "username": "user", + "password": "pass", + "ssl": True, + "verify_ssl": True, + } +} - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - @mock.patch("homeassistant.components.mfi.sensor.MFiClient") - def test_setup_missing_config(self, mock_client): - """Test setup with missing configuration.""" +async def test_setup_missing_config(hass): + """Test setup with missing configuration.""" + with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: config = {"sensor": {"platform": "mfi"}} - assert setup_component(self.hass, "sensor", config) + assert await async_setup_component(hass, "sensor", config) assert not mock_client.called - @mock.patch("homeassistant.components.mfi.sensor.MFiClient") - def test_setup_failed_login(self, mock_client): - """Test setup with login failure.""" + +async def test_setup_failed_login(hass): + """Test setup with login failure.""" + with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: mock_client.side_effect = FailedToLogin - assert not self.PLATFORM.setup_platform(self.hass, dict(self.GOOD_CONFIG), None) + assert not PLATFORM.setup_platform(hass, dict(GOOD_CONFIG), None) - @mock.patch("homeassistant.components.mfi.sensor.MFiClient") - def test_setup_failed_connect(self, mock_client): - """Test setup with connection failure.""" + +async def test_setup_failed_connect(hass): + """Test setup with connection failure.""" + with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: mock_client.side_effect = requests.exceptions.ConnectionError - assert not self.PLATFORM.setup_platform(self.hass, dict(self.GOOD_CONFIG), None) - - @mock.patch("homeassistant.components.mfi.sensor.MFiClient") - def test_setup_minimum(self, mock_client): - """Test setup with minimum configuration.""" - config = dict(self.GOOD_CONFIG) - del config[self.THING]["port"] - assert setup_component(self.hass, self.COMPONENT.DOMAIN, config) - self.hass.block_till_done() + assert not PLATFORM.setup_platform(hass, dict(GOOD_CONFIG), None) + + +async def test_setup_minimum(hass): + """Test setup with minimum configuration.""" + with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: + config = dict(GOOD_CONFIG) + del config[THING]["port"] + assert await async_setup_component(hass, COMPONENT.DOMAIN, config) + await hass.async_block_till_done() assert mock_client.call_count == 1 assert mock_client.call_args == mock.call( "foo", "user", "pass", port=6443, use_tls=True, verify=True ) - @mock.patch("homeassistant.components.mfi.sensor.MFiClient") - def test_setup_with_port(self, mock_client): - """Test setup with port.""" - config = dict(self.GOOD_CONFIG) - config[self.THING]["port"] = 6123 - assert setup_component(self.hass, self.COMPONENT.DOMAIN, config) - self.hass.block_till_done() + +async def test_setup_with_port(hass): + """Test setup with port.""" + with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: + config = dict(GOOD_CONFIG) + config[THING]["port"] = 6123 + assert await async_setup_component(hass, COMPONENT.DOMAIN, config) + await hass.async_block_till_done() assert mock_client.call_count == 1 assert mock_client.call_args == mock.call( "foo", "user", "pass", port=6123, use_tls=True, verify=True ) - @mock.patch("homeassistant.components.mfi.sensor.MFiClient") - def test_setup_with_tls_disabled(self, mock_client): - """Test setup without TLS.""" - config = dict(self.GOOD_CONFIG) - del config[self.THING]["port"] - config[self.THING]["ssl"] = False - config[self.THING]["verify_ssl"] = False - assert setup_component(self.hass, self.COMPONENT.DOMAIN, config) - self.hass.block_till_done() + +async def test_setup_with_tls_disabled(hass): + """Test setup without TLS.""" + with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: + config = dict(GOOD_CONFIG) + del config[THING]["port"] + config[THING]["ssl"] = False + config[THING]["verify_ssl"] = False + assert await async_setup_component(hass, COMPONENT.DOMAIN, config) + await hass.async_block_till_done() assert mock_client.call_count == 1 assert mock_client.call_args == mock.call( "foo", "user", "pass", port=6080, use_tls=False, verify=False ) - @mock.patch("homeassistant.components.mfi.sensor.MFiClient") - @mock.patch("homeassistant.components.mfi.sensor.MfiSensor") - def test_setup_adds_proper_devices(self, mock_sensor, mock_client): - """Test if setup adds devices.""" + +async def test_setup_adds_proper_devices(hass): + """Test if setup adds devices.""" + with mock.patch( + "homeassistant.components.mfi.sensor.MFiClient" + ) as mock_client, mock.patch( + "homeassistant.components.mfi.sensor.MfiSensor" + ) as mock_sensor: ports = { i: mock.MagicMock(model=model) for i, model in enumerate(mfi.SENSOR_MODELS) } @@ -107,82 +103,90 @@ def test_setup_adds_proper_devices(self, mock_sensor, mock_client): mock_client.return_value.get_devices.return_value = [ mock.MagicMock(ports=ports) ] - assert setup_component(self.hass, sensor.DOMAIN, self.GOOD_CONFIG) - self.hass.block_till_done() + assert await async_setup_component(hass, COMPONENT.DOMAIN, GOOD_CONFIG) + await hass.async_block_till_done() for ident, port in ports.items(): if ident != "bad": - mock_sensor.assert_any_call(port, self.hass) - assert mock.call(ports["bad"], self.hass) not in mock_sensor.mock_calls - - -class TestMfiSensor(unittest.TestCase): - """Test for mFi sensor platform.""" - - def setup_method(self, method): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.port = mock.MagicMock() - self.sensor = mfi.MfiSensor(self.port, self.hass) - - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - - def test_name(self): - """Test the name.""" - assert self.port.label == self.sensor.name - - def test_uom_temp(self): - """Test the UOM temperature.""" - self.port.tag = "temperature" - assert TEMP_CELSIUS == self.sensor.unit_of_measurement - - def test_uom_power(self): - """Test the UOEM power.""" - self.port.tag = "active_pwr" - assert "Watts" == self.sensor.unit_of_measurement - - def test_uom_digital(self): - """Test the UOM digital input.""" - self.port.model = "Input Digital" - assert "State" == self.sensor.unit_of_measurement - - def test_uom_unknown(self): - """Test the UOM.""" - self.port.tag = "balloons" - assert "balloons" == self.sensor.unit_of_measurement - - def test_uom_uninitialized(self): - """Test that the UOM defaults if not initialized.""" - type(self.port).tag = mock.PropertyMock(side_effect=ValueError) - assert "State" == self.sensor.unit_of_measurement - - def test_state_digital(self): - """Test the digital input.""" - self.port.model = "Input Digital" - self.port.value = 0 - assert mfi.STATE_OFF == self.sensor.state - self.port.value = 1 - assert mfi.STATE_ON == self.sensor.state - self.port.value = 2 - assert mfi.STATE_ON == self.sensor.state - - def test_state_digits(self): - """Test the state of digits.""" - self.port.tag = "didyoucheckthedict?" - self.port.value = 1.25 - with mock.patch.dict(mfi.DIGITS, {"didyoucheckthedict?": 1}): - assert 1.2 == self.sensor.state - with mock.patch.dict(mfi.DIGITS, {}): - assert 1.0 == self.sensor.state - - def test_state_uninitialized(self): - """Test the state of uninitialized sensors.""" - type(self.port).tag = mock.PropertyMock(side_effect=ValueError) - assert mfi.STATE_OFF == self.sensor.state - - def test_update(self): - """Test the update.""" - self.sensor.update() - assert self.port.refresh.call_count == 1 - assert self.port.refresh.call_args == mock.call() + mock_sensor.assert_any_call(port, hass) + assert mock.call(ports["bad"], hass) not in mock_sensor.mock_calls + + +@pytest.fixture(name="port") +def port_fixture(): + """Port fixture.""" + return mock.MagicMock() + + +@pytest.fixture(name="sensor") +def sensor_fixture(hass, port): + """Sensor fixture.""" + return mfi.MfiSensor(port, hass) + + +async def test_name(port, sensor): + """Test the name.""" + assert port.label == sensor.name + + +async def test_uom_temp(port, sensor): + """Test the UOM temperature.""" + port.tag = "temperature" + assert TEMP_CELSIUS == sensor.unit_of_measurement + + +async def test_uom_power(port, sensor): + """Test the UOEM power.""" + port.tag = "active_pwr" + assert sensor.unit_of_measurement == "Watts" + + +async def test_uom_digital(port, sensor): + """Test the UOM digital input.""" + port.model = "Input Digital" + assert sensor.unit_of_measurement == "State" + + +async def test_uom_unknown(port, sensor): + """Test the UOM.""" + port.tag = "balloons" + assert sensor.unit_of_measurement == "balloons" + + +async def test_uom_uninitialized(port, sensor): + """Test that the UOM defaults if not initialized.""" + type(port).tag = mock.PropertyMock(side_effect=ValueError) + assert sensor.unit_of_measurement == "State" + + +async def test_state_digital(port, sensor): + """Test the digital input.""" + port.model = "Input Digital" + port.value = 0 + assert mfi.STATE_OFF == sensor.state + port.value = 1 + assert mfi.STATE_ON == sensor.state + port.value = 2 + assert mfi.STATE_ON == sensor.state + + +async def test_state_digits(port, sensor): + """Test the state of digits.""" + port.tag = "didyoucheckthedict?" + port.value = 1.25 + with mock.patch.dict(mfi.DIGITS, {"didyoucheckthedict?": 1}): + assert sensor.state == 1.2 + with mock.patch.dict(mfi.DIGITS, {}): + assert sensor.state == 1.0 + + +async def test_state_uninitialized(port, sensor): + """Test the state of uninitialized sensorfs.""" + type(port).tag = mock.PropertyMock(side_effect=ValueError) + assert mfi.STATE_OFF == sensor.state + + +async def test_update(port, sensor): + """Test the update.""" + sensor.update() + assert port.refresh.call_count == 1 + assert port.refresh.call_args == mock.call() diff --git a/tests/components/mfi/test_switch.py b/tests/components/mfi/test_switch.py index 45bb353026686..77a7a72da9e4b 100644 --- a/tests/components/mfi/test_switch.py +++ b/tests/components/mfi/test_switch.py @@ -1,44 +1,35 @@ """The tests for the mFi switch platform.""" -import unittest +import pytest import homeassistant.components.mfi.switch as mfi -import homeassistant.components.switch as switch -from homeassistant.setup import setup_component +import homeassistant.components.switch as switch_component +from homeassistant.setup import async_setup_component import tests.async_mock as mock -from tests.common import get_test_home_assistant - - -class TestMfiSwitchSetup(unittest.TestCase): - """Test the mFi switch.""" - - PLATFORM = mfi - COMPONENT = switch - THING = "switch" - GOOD_CONFIG = { - "switch": { - "platform": "mfi", - "host": "foo", - "port": 6123, - "username": "user", - "password": "pass", - "ssl": True, - "verify_ssl": True, - } - } - def setup_method(self, method): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() +PLATFORM = mfi +COMPONENT = switch_component +THING = "switch" +GOOD_CONFIG = { + "switch": { + "platform": "mfi", + "host": "foo", + "port": 6123, + "username": "user", + "password": "pass", + "ssl": True, + "verify_ssl": True, + } +} - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - @mock.patch("homeassistant.components.mfi.switch.MFiClient") - @mock.patch("homeassistant.components.mfi.switch.MfiSwitch") - def test_setup_adds_proper_devices(self, mock_switch, mock_client): - """Test if setup adds devices.""" +async def test_setup_adds_proper_devices(hass): + """Test if setup adds devices.""" + with mock.patch( + "homeassistant.components.mfi.switch.MFiClient" + ) as mock_client, mock.patch( + "homeassistant.components.mfi.switch.MfiSwitch" + ) as mock_switch: ports = { i: mock.MagicMock(model=model) for i, model in enumerate(mfi.SWITCH_MODELS) } @@ -47,74 +38,84 @@ def test_setup_adds_proper_devices(self, mock_switch, mock_client): mock_client.return_value.get_devices.return_value = [ mock.MagicMock(ports=ports) ] - assert setup_component(self.hass, switch.DOMAIN, self.GOOD_CONFIG) - self.hass.block_till_done() + assert await async_setup_component(hass, COMPONENT.DOMAIN, GOOD_CONFIG) + await hass.async_block_till_done() for ident, port in ports.items(): if ident != "bad": mock_switch.assert_any_call(port) - assert mock.call(ports["bad"], self.hass) not in mock_switch.mock_calls - - -class TestMfiSwitch(unittest.TestCase): - """Test for mFi switch platform.""" - - def setup_method(self, method): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.port = mock.MagicMock() - self.switch = mfi.MfiSwitch(self.port) - - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - - def test_name(self): - """Test the name.""" - assert self.port.label == self.switch.name - - def test_update(self): - """Test update.""" - self.switch.update() - assert self.port.refresh.call_count == 1 - assert self.port.refresh.call_args == mock.call() - - def test_update_with_target_state(self): - """Test update with target state.""" - self.switch._target_state = True - self.port.data = {} - self.port.data["output"] = "stale" - self.switch.update() - assert 1.0 == self.port.data["output"] - assert self.switch._target_state is None - self.port.data["output"] = "untouched" - self.switch.update() - assert "untouched" == self.port.data["output"] - - def test_turn_on(self): - """Test turn_on.""" - self.switch.turn_on() - assert self.port.control.call_count == 1 - assert self.port.control.call_args == mock.call(True) - assert self.switch._target_state - - def test_turn_off(self): - """Test turn_off.""" - self.switch.turn_off() - assert self.port.control.call_count == 1 - assert self.port.control.call_args == mock.call(False) - assert not self.switch._target_state - - def test_current_power_w(self): - """Test current power.""" - self.port.data = {"active_pwr": 10} - assert 10 == self.switch.current_power_w - - def test_current_power_w_no_data(self): - """Test current power if there is no data.""" - self.port.data = {"notpower": 123} - assert 0 == self.switch.current_power_w - - def test_device_state_attributes(self): - """Test the state attributes.""" - self.port.data = {"v_rms": 1.25, "i_rms": 2.75} - assert {"volts": 1.2, "amps": 2.8} == self.switch.device_state_attributes + assert mock.call(ports["bad"], hass) not in mock_switch.mock_calls + + +@pytest.fixture(name="port") +def port_fixture(): + """Port fixture.""" + return mock.MagicMock() + + +@pytest.fixture(name="switch") +def switch_fixture(port): + """Switch fixture.""" + return mfi.MfiSwitch(port) + + +async def test_name(port, switch): + """Test the name.""" + assert port.label == switch.name + + +async def test_update(port, switch): + """Test update.""" + switch.update() + assert port.refresh.call_count == 1 + assert port.refresh.call_args == mock.call() + + +async def test_update_with_target_state(port, switch): + """Test update with target state.""" + # pylint: disable=protected-access + switch._target_state = True + port.data = {} + port.data["output"] = "stale" + switch.update() + assert port.data["output"] == 1.0 + # pylint: disable=protected-access + assert switch._target_state is None + port.data["output"] = "untouched" + switch.update() + assert port.data["output"] == "untouched" + + +async def test_turn_on(port, switch): + """Test turn_on.""" + switch.turn_on() + assert port.control.call_count == 1 + assert port.control.call_args == mock.call(True) + # pylint: disable=protected-access + assert switch._target_state + + +async def test_turn_off(port, switch): + """Test turn_off.""" + switch.turn_off() + assert port.control.call_count == 1 + assert port.control.call_args == mock.call(False) + # pylint: disable=protected-access + assert not switch._target_state + + +async def test_current_power_w(port, switch): + """Test current power.""" + port.data = {"active_pwr": 10} + assert switch.current_power_w == 10 + + +async def test_current_power_w_no_data(port, switch): + """Test current power if there is no data.""" + port.data = {"notpower": 123} + assert switch.current_power_w == 0 + + +async def test_device_state_attributes(port, switch): + """Test the state attributes.""" + port.data = {"v_rms": 1.25, "i_rms": 2.75} + assert switch.device_state_attributes == {"volts": 1.2, "amps": 2.8} From df552f08c32f2e909d4acbd9347aaf274dd79403 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 30 Oct 2020 03:29:12 -0500 Subject: [PATCH 27/43] Purge unused constants from template helper (#42618) --- homeassistant/helpers/template.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index cd286b15dc743..eae98b44044fb 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -48,12 +48,6 @@ _RENDER_INFO = "template.render_info" _ENVIRONMENT = "template.environment" -_RE_NONE_ENTITIES = re.compile(r"distance\(|closest\(", re.I | re.M) -_RE_GET_ENTITIES = re.compile( - r"(?:(?:(?:states\.|(?Pis_state|is_state_attr|state_attr|states|expand)\((?:[\ \'\"]?))(?P[\w]+\.[\w]+)|states\.(?P[a-z]+)|states\[(?:[\'\"]?)(?P[\w]+))|(?P[\w]+))", - re.I | re.M, -) - _RE_JINJA_DELIMITERS = re.compile(r"\{%|\{\{|\{#") _RESERVED_NAMES = {"contextfunction", "evalcontextfunction", "environmentfunction"} From b228ffc761e3f73edba2965420526079d5f763fb Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Fri, 30 Oct 2020 01:51:22 -0700 Subject: [PATCH 28/43] Add missing config flow translation key to script scaffold (#42621) Add missing config key for no_url_available when generating new oauth2 config entry based integrations. This was found in issue #42423 where the nest integration was missing a string when a user had a misconfiguration. --- script/scaffold/generate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/script/scaffold/generate.py b/script/scaffold/generate.py index 4c50b8971fb03..4cf1624eb4b82 100644 --- a/script/scaffold/generate.py +++ b/script/scaffold/generate.py @@ -165,6 +165,7 @@ def _custom_tasks(template, info) -> None: "abort": { "missing_configuration": "[%key:common::config_flow::abort::oauth2_missing_configuration%]", "authorize_url_timeout": "[%key:common::config_flow::abort::oauth2_authorize_url_timeout%]", + "no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]", }, "create_entry": { "default": "[%key:common::config_flow::create_entry::authenticated%]" From 62b5279d863fe39d66282b5e6799be11a8e4a314 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 30 Oct 2020 09:56:41 +0100 Subject: [PATCH 29/43] Add WS command to remove a Tasmota device (#42266) --- homeassistant/components/tasmota/__init__.py | 84 ++++++++- homeassistant/components/tasmota/const.py | 1 + .../components/tasmota/device_automation.py | 13 +- .../components/tasmota/device_trigger.py | 6 +- tests/components/tasmota/test_init.py | 176 ++++++++++++++++++ 5 files changed, 265 insertions(+), 15 deletions(-) create mode 100644 tests/components/tasmota/test_init.py diff --git a/homeassistant/components/tasmota/__init__.py b/homeassistant/components/tasmota/__init__.py index a82d95474ccf5..c0ebae7695eb8 100644 --- a/homeassistant/components/tasmota/__init__.py +++ b/homeassistant/components/tasmota/__init__.py @@ -11,23 +11,32 @@ ) from hatasmota.discovery import clear_discovery_topic from hatasmota.mqtt import TasmotaMQTTClient +import voluptuous as vol -from homeassistant.components import mqtt +from homeassistant.components import mqtt, websocket_api from homeassistant.components.mqtt.subscription import ( async_subscribe_topics, async_unsubscribe_topics, ) from homeassistant.core import callback -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC +from homeassistant.helpers.device_registry import ( + CONNECTION_NETWORK_MAC, + EVENT_DEVICE_REGISTRY_UPDATED, + async_entries_for_config_entry, +) from homeassistant.helpers.typing import HomeAssistantType from . import device_automation, discovery -from .const import CONF_DISCOVERY_PREFIX, DATA_REMOVE_DISCOVER_COMPONENT, PLATFORMS +from .const import ( + CONF_DISCOVERY_PREFIX, + DATA_REMOVE_DISCOVER_COMPONENT, + DATA_UNSUB, + DOMAIN, + PLATFORMS, +) _LOGGER = logging.getLogger(__name__) -DEVICE_MACS = "tasmota_devices" - async def async_setup(hass: HomeAssistantType, config: dict): """Set up the Tasmota component.""" @@ -36,7 +45,8 @@ async def async_setup(hass: HomeAssistantType, config: dict): async def async_setup_entry(hass, entry): """Set up Tasmota from a config entry.""" - hass.data[DEVICE_MACS] = {} + websocket_api.async_register_command(hass, websocket_remove_device) + hass.data[DATA_UNSUB] = [] def _publish(*args, **kwds): mqtt.async_publish(hass, *args, **kwds) @@ -59,6 +69,25 @@ def async_discover_device(config, mac): """Discover and add a Tasmota device.""" async_setup_device(hass, mac, config, entry, tasmota_mqtt, device_registry) + async def async_device_removed(event): + """Handle the removal of a device.""" + device_registry = await hass.helpers.device_registry.async_get_registry() + if event.data["action"] != "remove": + return + + device = device_registry.deleted_devices[event.data["device_id"]] + + if entry.entry_id not in device.config_entries: + return + + macs = [c[1] for c in device.connections if c[0] == CONNECTION_NETWORK_MAC] + for mac in macs: + clear_discovery_topic(mac, entry.data[CONF_DISCOVERY_PREFIX], tasmota_mqtt) + + hass.data[DATA_UNSUB].append( + hass.bus.async_listen(EVENT_DEVICE_REGISTRY_UPDATED, async_device_removed) + ) + async def start_platforms(): await device_automation.async_setup_entry(hass, entry) await asyncio.gather( @@ -94,11 +123,20 @@ async def async_unload_entry(hass, entry): # disable discovery await discovery.async_stop(hass) - hass.data.pop(DEVICE_MACS) + + # cleanup subscriptions + for unsub in hass.data[DATA_UNSUB]: + unsub() hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format("device_automation"))() for component in PLATFORMS: hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format(component))() + # deattach device triggers + device_registry = await hass.helpers.device_registry.async_get_registry() + devices = async_entries_for_config_entry(device_registry, entry.entry_id) + for device in devices: + await device_automation.async_remove_automations(hass, device.id) + return True @@ -126,8 +164,7 @@ def _update_device(hass, config_entry, config, device_registry): "config_entry_id": config_entry_id, } _LOGGER.debug("Adding or updating tasmota device %s", config[CONF_MAC]) - device = device_registry.async_get_or_create(**device_info) - hass.data[DEVICE_MACS][device.id] = config[CONF_MAC] + device_registry.async_get_or_create(**device_info) def async_setup_device(hass, mac, config, config_entry, tasmota_mqtt, device_registry): @@ -136,3 +173,32 @@ def async_setup_device(hass, mac, config, config_entry, tasmota_mqtt, device_reg _remove_device(hass, config_entry, mac, tasmota_mqtt, device_registry) else: _update_device(hass, config_entry, config, device_registry) + + +@websocket_api.websocket_command( + {vol.Required("type"): "tasmota/device/remove", vol.Required("device_id"): str} +) +@websocket_api.async_response +async def websocket_remove_device(hass, connection, msg): + """Delete device.""" + device_id = msg["device_id"] + dev_registry = await hass.helpers.device_registry.async_get_registry() + + device = dev_registry.async_get(device_id) + if not device: + connection.send_error( + msg["id"], websocket_api.const.ERR_NOT_FOUND, "Device not found" + ) + return + + for config_entry in device.config_entries: + config_entry = hass.config_entries.async_get_entry(config_entry) + # Only delete the device if it belongs to a Tasmota device entry + if config_entry.domain == DOMAIN: + dev_registry.async_remove_device(device_id) + connection.send_message(websocket_api.result_message(msg["id"])) + return + + connection.send_error( + msg["id"], websocket_api.const.ERR_NOT_FOUND, "Non Tasmota device" + ) diff --git a/homeassistant/components/tasmota/const.py b/homeassistant/components/tasmota/const.py index 7cddeb7a6033f..0f4dfde164606 100644 --- a/homeassistant/components/tasmota/const.py +++ b/homeassistant/components/tasmota/const.py @@ -2,6 +2,7 @@ CONF_DISCOVERY_PREFIX = "discovery_prefix" DATA_REMOVE_DISCOVER_COMPONENT = "tasmota_discover_{}" +DATA_UNSUB = "tasmota_subscriptions" DEFAULT_PREFIX = "tasmota/discovery" diff --git a/homeassistant/components/tasmota/device_automation.py b/homeassistant/components/tasmota/device_automation.py index e921a186fea44..aab0064bb968a 100644 --- a/homeassistant/components/tasmota/device_automation.py +++ b/homeassistant/components/tasmota/device_automation.py @@ -6,10 +6,15 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from . import device_trigger -from .const import DATA_REMOVE_DISCOVER_COMPONENT +from .const import DATA_REMOVE_DISCOVER_COMPONENT, DATA_UNSUB from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW +async def async_remove_automations(hass, device_id): + """Remove automations for a Tasmota device.""" + await device_trigger.async_remove_triggers(hass, device_id) + + async def async_setup_entry(hass, config_entry): """Set up Tasmota device automation dynamically through discovery.""" @@ -17,7 +22,7 @@ async def async_device_removed(event): """Handle the removal of a device.""" if event.data["action"] != "remove": return - await device_trigger.async_device_removed(hass, event.data["device_id"]) + await async_remove_automations(hass, event.data["device_id"]) async def async_discover(tasmota_automation, discovery_hash): """Discover and add a Tasmota device automation.""" @@ -33,4 +38,6 @@ async def async_discover(tasmota_automation, discovery_hash): TASMOTA_DISCOVERY_ENTITY_NEW.format("device_automation", "tasmota"), async_discover, ) - hass.bus.async_listen(EVENT_DEVICE_REGISTRY_UPDATED, async_device_removed) + hass.data[DATA_UNSUB].append( + hass.bus.async_listen(EVENT_DEVICE_REGISTRY_UPDATED, async_device_removed) + ) diff --git a/homeassistant/components/tasmota/device_trigger.py b/homeassistant/components/tasmota/device_trigger.py index 9db7ca492afe8..e7dad0885a02f 100644 --- a/homeassistant/components/tasmota/device_trigger.py +++ b/homeassistant/components/tasmota/device_trigger.py @@ -224,8 +224,8 @@ async def discovery_update(trigger_config): await device_trigger.arm_tasmota_trigger() -async def async_device_removed(hass: HomeAssistant, device_id: str): - """Handle the removal of a Tasmota device - cleanup any device triggers.""" +async def async_remove_triggers(hass: HomeAssistant, device_id: str): + """Cleanup any device triggers for a Tasmota device.""" triggers = await async_get_triggers(hass, device_id) for trig in triggers: device_trigger = hass.data[DEVICE_TRIGGERS].pop(trig[CONF_DISCOVERY_ID]) @@ -239,7 +239,7 @@ async def async_device_removed(hass: HomeAssistant, device_id: str): async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: - """List device triggers for Tasmota devices.""" + """List device triggers for a Tasmota device.""" triggers = [] if DEVICE_TRIGGERS not in hass.data: diff --git a/tests/components/tasmota/test_init.py b/tests/components/tasmota/test_init.py new file mode 100644 index 0000000000000..39d998727415c --- /dev/null +++ b/tests/components/tasmota/test_init.py @@ -0,0 +1,176 @@ +"""The tests for the Tasmota binary sensor platform.""" +import copy +import json + +from homeassistant.components import websocket_api +from homeassistant.components.tasmota.const import DEFAULT_PREFIX + +from .test_common import DEFAULT_CONFIG + +from tests.async_mock import call +from tests.common import MockConfigEntry, async_fire_mqtt_message + + +async def test_device_remove( + hass, mqtt_mock, caplog, device_reg, entity_reg, setup_tasmota +): + """Test removing a discovered device through device registry.""" + config = copy.deepcopy(DEFAULT_CONFIG) + mac = config["mac"] + + async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) + await hass.async_block_till_done() + + # Verify device entry is created + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + assert device_entry is not None + + device_reg.async_remove_device(device_entry.id) + await hass.async_block_till_done() + + # Verify device entry is removed + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + assert device_entry is None + + # Verify retained discovery topic has been cleared + mqtt_mock.async_publish.assert_has_calls( + [ + call(f"tasmota/discovery/{mac}/config", "", 0, True), + call(f"tasmota/discovery/{mac}/sensors", "", 0, True), + ], + any_order=True, + ) + + +async def test_device_remove_non_tasmota_device( + hass, device_reg, hass_ws_client, mqtt_mock, setup_tasmota +): + """Test removing a non Tasmota device through device registry.""" + config_entry = MockConfigEntry(domain="test") + config_entry.add_to_hass(hass) + + mac = "12:34:56:AB:CD:EF" + device_entry = device_reg.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={("mac", mac)}, + ) + assert device_entry is not None + + device_reg.async_remove_device(device_entry.id) + await hass.async_block_till_done() + + # Verify device entry is removed + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + assert device_entry is None + + # Verify no Tasmota discovery message was sent + mqtt_mock.async_publish.assert_not_called() + + +async def test_device_remove_stale_tasmota_device( + hass, device_reg, hass_ws_client, mqtt_mock, setup_tasmota +): + """Test removing a stale (undiscovered) Tasmota device through device registry.""" + config_entry = hass.config_entries.async_entries("tasmota")[0] + + mac = "12:34:56:AB:CD:EF" + device_entry = device_reg.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={("mac", mac)}, + ) + assert device_entry is not None + + device_reg.async_remove_device(device_entry.id) + await hass.async_block_till_done() + + # Verify device entry is removed + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + assert device_entry is None + + # Verify retained discovery topic has been cleared + mac = mac.replace(":", "") + mqtt_mock.async_publish.assert_has_calls( + [ + call(f"tasmota/discovery/{mac}/config", "", 0, True), + call(f"tasmota/discovery/{mac}/sensors", "", 0, True), + ], + any_order=True, + ) + + +async def test_tasmota_ws_remove_discovered_device( + hass, device_reg, entity_reg, hass_ws_client, mqtt_mock, setup_tasmota +): + """Test Tasmota websocket device removal.""" + config = copy.deepcopy(DEFAULT_CONFIG) + mac = config["mac"] + + async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) + await hass.async_block_till_done() + + # Verify device entry is created + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + assert device_entry is not None + + client = await hass_ws_client(hass) + await client.send_json( + {"id": 5, "type": "tasmota/device/remove", "device_id": device_entry.id} + ) + response = await client.receive_json() + assert response["success"] + + # Verify device entry is cleared + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + assert device_entry is None + + +async def test_tasmota_ws_remove_discovered_device_twice( + hass, device_reg, hass_ws_client, mqtt_mock, setup_tasmota +): + """Test Tasmota websocket device removal.""" + config = copy.deepcopy(DEFAULT_CONFIG) + mac = config["mac"] + + async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) + await hass.async_block_till_done() + + # Verify device entry is created + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + assert device_entry is not None + + client = await hass_ws_client(hass) + await client.send_json( + {"id": 5, "type": "tasmota/device/remove", "device_id": device_entry.id} + ) + response = await client.receive_json() + assert response["success"] + + await client.send_json( + {"id": 6, "type": "tasmota/device/remove", "device_id": device_entry.id} + ) + response = await client.receive_json() + assert not response["success"] + assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND + assert response["error"]["message"] == "Device not found" + + +async def test_tasmota_ws_remove_non_tasmota_device( + hass, device_reg, hass_ws_client, mqtt_mock, setup_tasmota +): + """Test Tasmota websocket device removal of device belonging to other domain.""" + config_entry = MockConfigEntry(domain="test") + config_entry.add_to_hass(hass) + + device_entry = device_reg.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={("mac", "12:34:56:AB:CD:EF")}, + ) + assert device_entry is not None + + client = await hass_ws_client(hass) + await client.send_json( + {"id": 5, "type": "tasmota/device/remove", "device_id": device_entry.id} + ) + response = await client.receive_json() + assert not response["success"] + assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND From b3d7f940c54900e1cd178559f54323bae6f259de Mon Sep 17 00:00:00 2001 From: SNoof85 Date: Fri, 30 Oct 2020 12:21:00 +0100 Subject: [PATCH 30/43] Fix typo in Flunearyou config flow (#42617) --- homeassistant/components/flunearyou/strings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/flunearyou/strings.json b/homeassistant/components/flunearyou/strings.json index 5736b266e6c40..4df0326fc3b4a 100644 --- a/homeassistant/components/flunearyou/strings.json +++ b/homeassistant/components/flunearyou/strings.json @@ -3,7 +3,7 @@ "step": { "user": { "title": "Configure Flu Near You", - "description": "Monitor user-based and CDC repots for a pair of coordinates.", + "description": "Monitor user-based and CDC reports for a pair of coordinates.", "data": { "latitude": "[%key:common::config_flow::data::latitude%]", "longitude": "[%key:common::config_flow::data::longitude%]" @@ -17,4 +17,4 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_location%]" } } -} \ No newline at end of file +} From 8c239f23047772660f813d84e13260bfcc76e3c6 Mon Sep 17 00:00:00 2001 From: Malte Franken Date: Fri, 30 Oct 2020 22:23:07 +1100 Subject: [PATCH 31/43] Fix geo_rss_events import statement (#42629) * bump integration library version * fix import statement --- homeassistant/components/geo_rss_events/manifest.json | 2 +- homeassistant/components/geo_rss_events/sensor.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/geo_rss_events/manifest.json b/homeassistant/components/geo_rss_events/manifest.json index 77d38d58ad77c..4a434aed8d765 100644 --- a/homeassistant/components/geo_rss_events/manifest.json +++ b/homeassistant/components/geo_rss_events/manifest.json @@ -2,6 +2,6 @@ "domain": "geo_rss_events", "name": "GeoRSS", "documentation": "https://www.home-assistant.io/integrations/geo_rss_events", - "requirements": ["georss_generic_client==0.3"], + "requirements": ["georss_generic_client==0.4"], "codeowners": ["@exxamalte"] } diff --git a/homeassistant/components/geo_rss_events/sensor.py b/homeassistant/components/geo_rss_events/sensor.py index 5a11136fd4313..c75234f5f2b31 100644 --- a/homeassistant/components/geo_rss_events/sensor.py +++ b/homeassistant/components/geo_rss_events/sensor.py @@ -9,7 +9,7 @@ import logging from georss_client import UPDATE_OK, UPDATE_OK_NO_DATA -from georss_client.generic_feed import GenericFeed +from georss_generic_client import GenericFeed import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA diff --git a/requirements_all.txt b/requirements_all.txt index f713ef221c3de..6b0b7a09927e0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -641,7 +641,7 @@ geojson_client==0.4 geopy==1.21.0 # homeassistant.components.geo_rss_events -georss_generic_client==0.3 +georss_generic_client==0.4 # homeassistant.components.ign_sismologia georss_ign_sismologia_client==0.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3c1ecc048e3f0..957f345a13559 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -318,7 +318,7 @@ geojson_client==0.4 geopy==1.21.0 # homeassistant.components.geo_rss_events -georss_generic_client==0.3 +georss_generic_client==0.4 # homeassistant.components.ign_sismologia georss_ign_sismologia_client==0.2 From 2dc5c4dd69e22d6afc45c174233e0a5358127874 Mon Sep 17 00:00:00 2001 From: Federico Leoni Date: Fri, 30 Oct 2020 10:59:36 -0300 Subject: [PATCH 32/43] Bump hatasmota to 0.0.26 (#42613) * Tasmota : Add new Status Sensors * Tasmota: add new Status Sensors * Update RSSI sensor icon Co-authored-by: Erik Montnemery --- homeassistant/components/tasmota/manifest.json | 2 +- homeassistant/components/tasmota/sensor.py | 14 +++++++++++++- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/tasmota/manifest.json b/homeassistant/components/tasmota/manifest.json index b087e13ece0cf..7cc6413e162f5 100644 --- a/homeassistant/components/tasmota/manifest.json +++ b/homeassistant/components/tasmota/manifest.json @@ -3,7 +3,7 @@ "name": "Tasmota (beta)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tasmota", - "requirements": ["hatasmota==0.0.25"], + "requirements": ["hatasmota==0.0.26"], "dependencies": ["mqtt"], "mqtt": ["tasmota/discovery/#"], "codeowners": ["@emontnemery"] diff --git a/homeassistant/components/tasmota/sensor.py b/homeassistant/components/tasmota/sensor.py index 076ca457a23f5..badf20956650f 100644 --- a/homeassistant/components/tasmota/sensor.py +++ b/homeassistant/components/tasmota/sensor.py @@ -1,6 +1,7 @@ """Support for Tasmota sensors.""" from typing import Optional +from hatasmota import status_sensor from hatasmota.const import ( SENSOR_AMBIENT, SENSOR_APPARENT_POWERUSAGE, @@ -33,7 +34,12 @@ SENSOR_PRESSUREATSEALEVEL, SENSOR_PROXIMITY, SENSOR_REACTIVE_POWERUSAGE, + SENSOR_STATUS_IP, + SENSOR_STATUS_LINK_COUNT, + SENSOR_STATUS_MQTT_COUNT, + SENSOR_STATUS_RSSI, SENSOR_STATUS_SIGNAL, + SENSOR_STATUS_UPTIME, SENSOR_TEMPERATURE, SENSOR_TODAY, SENSOR_TOTAL, @@ -53,6 +59,7 @@ DEVICE_CLASS_PRESSURE, DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_TIMESTAMP, ) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -82,7 +89,10 @@ SENSOR_FREQUENCY: {ICON: "mdi:current-ac"}, SENSOR_HUMIDITY: {DEVICE_CLASS: DEVICE_CLASS_HUMIDITY}, SENSOR_ILLUMINANCE: {DEVICE_CLASS: DEVICE_CLASS_ILLUMINANCE}, + SENSOR_STATUS_IP: {ICON: "mdi:ip-network"}, + SENSOR_STATUS_LINK_COUNT: {ICON: "mdi:counter"}, SENSOR_MOISTURE: {ICON: "mdi:cup-water"}, + SENSOR_STATUS_MQTT_COUNT: {ICON: "mdi:counter"}, SENSOR_PB0_3: {ICON: "mdi:flask"}, SENSOR_PB0_5: {ICON: "mdi:flask"}, SENSOR_PB10: {ICON: "mdi:flask"}, @@ -99,11 +109,13 @@ SENSOR_PROXIMITY: {ICON: "mdi:ruler"}, SENSOR_REACTIVE_POWERUSAGE: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_STATUS_SIGNAL: {DEVICE_CLASS: DEVICE_CLASS_SIGNAL_STRENGTH}, + SENSOR_STATUS_RSSI: {ICON: "mdi:access-point"}, SENSOR_TEMPERATURE: {DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE}, SENSOR_TODAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_TOTAL: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_TOTAL_START_TIME: {ICON: "mdi:progress-clock"}, SENSOR_TVOC: {ICON: "mdi:air-filter"}, + SENSOR_STATUS_UPTIME: {DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP}, SENSOR_VOLTAGE: {ICON: "mdi:alpha-v-circle-outline"}, SENSOR_WEIGHT: {ICON: "mdi:scale"}, SENSOR_YESTERDAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, @@ -162,7 +174,7 @@ def device_class(self) -> Optional[str]: def entity_registry_enabled_default(self) -> bool: """Return if the entity should be enabled when first added to the entity registry.""" # Hide status sensors to not overwhelm users - if self._tasmota_entity.quantity == SENSOR_STATUS_SIGNAL: + if self._tasmota_entity.quantity in status_sensor.SENSORS: return False return True diff --git a/requirements_all.txt b/requirements_all.txt index 6b0b7a09927e0..e4a9ccd2682e2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -738,7 +738,7 @@ hass-nabucasa==0.37.1 hass_splunk==0.1.1 # homeassistant.components.tasmota -hatasmota==0.0.25 +hatasmota==0.0.26 # homeassistant.components.jewish_calendar hdate==0.9.12 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 957f345a13559..667b5ab9fbf47 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -373,7 +373,7 @@ hangups==0.4.11 hass-nabucasa==0.37.1 # homeassistant.components.tasmota -hatasmota==0.0.25 +hatasmota==0.0.26 # homeassistant.components.jewish_calendar hdate==0.9.12 From 92379ad8d2bc32e47f708ca0e59a011e5e2d7a70 Mon Sep 17 00:00:00 2001 From: springstan <46536646+springstan@users.noreply.github.com> Date: Fri, 30 Oct 2020 15:19:13 +0100 Subject: [PATCH 33/43] Use list literal without using dict.keys() (#42573) --- homeassistant/auth/providers/__init__.py | 2 +- homeassistant/components/asuswrt/device_tracker.py | 2 +- .../components/blink/alarm_control_panel.py | 2 +- homeassistant/components/denon/media_player.py | 2 +- .../components/environment_canada/sensor.py | 2 +- homeassistant/components/eq3btsmart/climate.py | 4 ++-- homeassistant/components/homekit/util.py | 2 +- homeassistant/components/insteon/climate.py | 4 ++-- homeassistant/components/izone/climate.py | 2 +- homeassistant/components/mqtt/discovery.py | 4 ++-- homeassistant/components/nad/media_player.py | 2 +- homeassistant/components/pioneer/media_player.py | 2 +- homeassistant/components/qnap/sensor.py | 12 ++++++------ homeassistant/components/sma/sensor.py | 4 ++-- homeassistant/components/upnp/sensor.py | 2 +- homeassistant/components/webostv/media_player.py | 2 +- homeassistant/components/yeelight/light.py | 2 +- homeassistant/helpers/config_entry_oauth2_flow.py | 2 +- 18 files changed, 27 insertions(+), 27 deletions(-) diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index b60fa8eff9ce8..1fe59346b0080 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -207,7 +207,7 @@ async def async_step_select_mfa_module( errors["base"] = "invalid_auth_module" if len(self.available_mfa_modules) == 1: - self._auth_module_id = list(self.available_mfa_modules.keys())[0] + self._auth_module_id = list(self.available_mfa_modules)[0] return await self.async_step_mfa() return self.async_show_form( diff --git a/homeassistant/components/asuswrt/device_tracker.py b/homeassistant/components/asuswrt/device_tracker.py index a7c4f9a7a7c04..a3545183d2e59 100644 --- a/homeassistant/components/asuswrt/device_tracker.py +++ b/homeassistant/components/asuswrt/device_tracker.py @@ -35,7 +35,7 @@ async def async_connect(self): async def async_scan_devices(self): """Scan for new devices and return a list with found device IDs.""" await self.async_update_info() - return list(self.last_results.keys()) + return list(self.last_results) async def async_get_device_name(self, device): """Return the name of the given device or None if we don't know.""" diff --git a/homeassistant/components/blink/alarm_control_panel.py b/homeassistant/components/blink/alarm_control_panel.py index 1ca4c4beac9c4..dbcb6d30143a2 100644 --- a/homeassistant/components/blink/alarm_control_panel.py +++ b/homeassistant/components/blink/alarm_control_panel.py @@ -66,7 +66,7 @@ def device_state_attributes(self): """Return the state attributes.""" attr = self.sync.attributes attr["network_info"] = self.data.networks - attr["associated_cameras"] = list(self.sync.cameras.keys()) + attr["associated_cameras"] = list(self.sync.cameras) attr[ATTR_ATTRIBUTION] = DEFAULT_ATTRIBUTION return attr diff --git a/homeassistant/components/denon/media_player.py b/homeassistant/components/denon/media_player.py index ed90c2ddcb00d..b909dc7c07008 100644 --- a/homeassistant/components/denon/media_player.py +++ b/homeassistant/components/denon/media_player.py @@ -230,7 +230,7 @@ def is_volume_muted(self): @property def source_list(self): """Return the list of available input sources.""" - return sorted(list(self._source_list.keys())) + return sorted(list(self._source_list)) @property def media_title(self): diff --git a/homeassistant/components/environment_canada/sensor.py b/homeassistant/components/environment_canada/sensor.py index afd75956a9f5c..a8772909f6837 100644 --- a/homeassistant/components/environment_canada/sensor.py +++ b/homeassistant/components/environment_canada/sensor.py @@ -61,7 +61,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): lon = config.get(CONF_LONGITUDE, hass.config.longitude) ec_data = ECData(coordinates=(lat, lon), language=config.get(CONF_LANGUAGE)) - sensor_list = list(ec_data.conditions.keys()) + list(ec_data.alerts.keys()) + sensor_list = list(ec_data.conditions) + list(ec_data.alerts) add_entities([ECSensor(sensor_type, ec_data) for sensor_type in sensor_list], True) diff --git a/homeassistant/components/eq3btsmart/climate.py b/homeassistant/components/eq3btsmart/climate.py index 6eb0276c31433..737b3fe357a4b 100644 --- a/homeassistant/components/eq3btsmart/climate.py +++ b/homeassistant/components/eq3btsmart/climate.py @@ -136,7 +136,7 @@ def hvac_mode(self): @property def hvac_modes(self): """Return the list of available operation modes.""" - return list(HA_TO_EQ_HVAC.keys()) + return list(HA_TO_EQ_HVAC) def set_hvac_mode(self, hvac_mode): """Set operation mode.""" @@ -181,7 +181,7 @@ def preset_modes(self): Requires SUPPORT_PRESET_MODE. """ - return list(HA_TO_EQ_PRESET.keys()) + return list(HA_TO_EQ_PRESET) def set_preset_mode(self, preset_mode): """Set new preset mode.""" diff --git a/homeassistant/components/homekit/util.py b/homeassistant/components/homekit/util.py index 2ea4fcb551bbf..453ae13d846db 100644 --- a/homeassistant/components/homekit/util.py +++ b/homeassistant/components/homekit/util.py @@ -357,7 +357,7 @@ def speed_to_states(self, speed): for state, speed_range in reversed(self.speed_ranges.items()): if speed_range.start <= speed: return state - return list(self.speed_ranges.keys())[0] + return list(self.speed_ranges)[0] def show_setup_message(hass, entry_id, bridge_name, pincode, uri): diff --git a/homeassistant/components/insteon/climate.py b/homeassistant/components/insteon/climate.py index f05cf9d29404e..7d4d9543c3fe6 100644 --- a/homeassistant/components/insteon/climate.py +++ b/homeassistant/components/insteon/climate.py @@ -202,12 +202,12 @@ async def async_set_temperature(self, **kwargs) -> None: async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" - mode = list(FAN_MODES.keys())[list(FAN_MODES.values()).index(fan_mode)] + mode = list(FAN_MODES)[list(FAN_MODES.values()).index(fan_mode)] await self._insteon_device.async_set_mode(mode) async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set new target hvac mode.""" - mode = list(HVAC_MODES.keys())[list(HVAC_MODES.values()).index(hvac_mode)] + mode = list(HVAC_MODES)[list(HVAC_MODES.values()).index(hvac_mode)] await self._insteon_device.async_set_mode(mode) async def async_set_humidity(self, humidity): diff --git a/homeassistant/components/izone/climate.py b/homeassistant/components/izone/climate.py index cd14d1cadcf5f..443a80298f131 100644 --- a/homeassistant/components/izone/climate.py +++ b/homeassistant/components/izone/climate.py @@ -509,7 +509,7 @@ def hvac_mode(self): @property def hvac_modes(self): """Return the list of available operation modes.""" - return list(self._state_to_pizone.keys()) + return list(self._state_to_pizone) @property def current_temperature(self): diff --git a/homeassistant/components/mqtt/discovery.py b/homeassistant/components/mqtt/discovery.py index 7a478733826a1..7f9a6730285a6 100644 --- a/homeassistant/components/mqtt/discovery.py +++ b/homeassistant/components/mqtt/discovery.py @@ -102,14 +102,14 @@ async def async_entity_message_received(msg): payload = MQTTConfig(payload) - for key in list(payload.keys()): + for key in list(payload): abbreviated_key = key key = ABBREVIATIONS.get(key, key) payload[key] = payload.pop(abbreviated_key) if CONF_DEVICE in payload: device = payload[CONF_DEVICE] - for key in list(device.keys()): + for key in list(device): abbreviated_key = key key = DEVICE_ABBREVIATIONS.get(key, key) device[key] = device.pop(abbreviated_key) diff --git a/homeassistant/components/nad/media_player.py b/homeassistant/components/nad/media_player.py index 7d8537db6c624..782b8735e3ae2 100644 --- a/homeassistant/components/nad/media_player.py +++ b/homeassistant/components/nad/media_player.py @@ -163,7 +163,7 @@ def source(self): @property def source_list(self): """List of available input sources.""" - return sorted(list(self._reverse_mapping.keys())) + return sorted(list(self._reverse_mapping)) @property def available(self): diff --git a/homeassistant/components/pioneer/media_player.py b/homeassistant/components/pioneer/media_player.py index a04b79e31881d..e573bf0929c13 100644 --- a/homeassistant/components/pioneer/media_player.py +++ b/homeassistant/components/pioneer/media_player.py @@ -203,7 +203,7 @@ def source(self): @property def source_list(self): """List of available input sources.""" - return list(self._source_name_to_number.keys()) + return list(self._source_name_to_number) @property def media_title(self): diff --git a/homeassistant/components/qnap/sensor.py b/homeassistant/components/qnap/sensor.py index fe4003a942390..11faba0f210ba 100644 --- a/homeassistant/components/qnap/sensor.py +++ b/homeassistant/components/qnap/sensor.py @@ -85,12 +85,12 @@ } _MONITORED_CONDITIONS = ( - list(_SYSTEM_MON_COND.keys()) - + list(_CPU_MON_COND.keys()) - + list(_MEMORY_MON_COND.keys()) - + list(_NETWORK_MON_COND.keys()) - + list(_DRIVE_MON_COND.keys()) - + list(_VOLUME_MON_COND.keys()) + list(_SYSTEM_MON_COND) + + list(_CPU_MON_COND) + + list(_MEMORY_MON_COND) + + list(_NETWORK_MON_COND) + + list(_DRIVE_MON_COND) + + list(_VOLUME_MON_COND) ) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( diff --git a/homeassistant/components/sma/sensor.py b/homeassistant/components/sma/sensor.py index ce61d4ff17b0d..119d9a366d6ef 100644 --- a/homeassistant/components/sma/sensor.py +++ b/homeassistant/components/sma/sensor.py @@ -40,7 +40,7 @@ def _check_sensor_schema(conf): except (ImportError, AttributeError): return conf - customs = list(conf[CONF_CUSTOM].keys()) + customs = list(conf[CONF_CUSTOM]) for sensor in conf[CONF_SENSORS]: if sensor in customs: @@ -120,7 +120,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= if isinstance(config_sensors, list): if not config_sensors: # Use all sensors by default config_sensors = [s.name for s in sensor_def] - used_sensors = list(set(config_sensors + list(config[CONF_CUSTOM].keys()))) + used_sensors = list(set(config_sensors + list(config[CONF_CUSTOM]))) for sensor in used_sensors: hass_sensors.append(SMAsensor(sensor_def[sensor], [])) diff --git a/homeassistant/components/upnp/sensor.py b/homeassistant/components/upnp/sensor.py index 80a5ce7021c1f..a9906e535b92f 100644 --- a/homeassistant/components/upnp/sensor.py +++ b/homeassistant/components/upnp/sensor.py @@ -88,7 +88,7 @@ async def async_setup_entry( udn = data[CONFIG_ENTRY_UDN] else: # any device will do - udn = list(hass.data[DOMAIN][DOMAIN_DEVICES].keys())[0] + udn = list(hass.data[DOMAIN][DOMAIN_DEVICES])[0] device: Device = hass.data[DOMAIN][DOMAIN_DEVICES][udn] diff --git a/homeassistant/components/webostv/media_player.py b/homeassistant/components/webostv/media_player.py index 82950e4f7f8d2..4807d780a480d 100644 --- a/homeassistant/components/webostv/media_player.py +++ b/homeassistant/components/webostv/media_player.py @@ -271,7 +271,7 @@ def source(self): @property def source_list(self): """List of available input sources.""" - return sorted(self._source_list.keys()) + return sorted(list(self._source_list)) @property def media_content_type(self): diff --git a/homeassistant/components/yeelight/light.py b/homeassistant/components/yeelight/light.py index 06cf91faf27dc..90704a6edfba7 100644 --- a/homeassistant/components/yeelight/light.py +++ b/homeassistant/components/yeelight/light.py @@ -471,7 +471,7 @@ def custom_effects(self): @property def custom_effects_names(self): """Return list with custom effects names.""" - return list(self.custom_effects.keys()) + return list(self.custom_effects) @property def light_type(self): diff --git a/homeassistant/helpers/config_entry_oauth2_flow.py b/homeassistant/helpers/config_entry_oauth2_flow.py index ba43a057ca3a6..4d05ad7beabb1 100644 --- a/homeassistant/helpers/config_entry_oauth2_flow.py +++ b/homeassistant/helpers/config_entry_oauth2_flow.py @@ -233,7 +233,7 @@ async def async_step_pick_implementation( data_schema=vol.Schema( { vol.Required( - "implementation", default=list(implementations.keys())[0] + "implementation", default=list(implementations)[0] ): vol.In({key: impl.name for key, impl in implementations.items()}) } ), From b302534042f3ed464e47b2449328f13eda7efe6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Fri, 30 Oct 2020 15:20:42 +0100 Subject: [PATCH 34/43] Bump pycfdns to 1.2.1 (#42634) --- homeassistant/components/cloudflare/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/cloudflare/manifest.json b/homeassistant/components/cloudflare/manifest.json index cab768953b151..e2f55b13a7fef 100644 --- a/homeassistant/components/cloudflare/manifest.json +++ b/homeassistant/components/cloudflare/manifest.json @@ -2,7 +2,7 @@ "domain": "cloudflare", "name": "Cloudflare", "documentation": "https://www.home-assistant.io/integrations/cloudflare", - "requirements": ["pycfdns==1.1.1"], + "requirements": ["pycfdns==1.2.1"], "codeowners": ["@ludeeus", "@ctalkington"], "config_flow": true } diff --git a/requirements_all.txt b/requirements_all.txt index e4a9ccd2682e2..8485bfc480bfb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1292,7 +1292,7 @@ pybotvac==0.0.17 pycarwings2==2.9 # homeassistant.components.cloudflare -pycfdns==1.1.1 +pycfdns==1.2.1 # homeassistant.components.channels pychannels==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 667b5ab9fbf47..62b2e5ec42b32 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -643,7 +643,7 @@ pyblackbird==0.5 pybotvac==0.0.17 # homeassistant.components.cloudflare -pycfdns==1.1.1 +pycfdns==1.2.1 # homeassistant.components.cast pychromecast==7.5.1 From 251d8286e0f5ade12c7941b7c72f481d2883485d Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 30 Oct 2020 18:02:44 +0100 Subject: [PATCH 35/43] Revert "Bump hatasmota to 0.0.26 (#42613)" (#42641) This reverts commit 2dc5c4dd69e22d6afc45c174233e0a5358127874. --- homeassistant/components/tasmota/manifest.json | 2 +- homeassistant/components/tasmota/sensor.py | 14 +------------- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/tasmota/manifest.json b/homeassistant/components/tasmota/manifest.json index 7cc6413e162f5..b087e13ece0cf 100644 --- a/homeassistant/components/tasmota/manifest.json +++ b/homeassistant/components/tasmota/manifest.json @@ -3,7 +3,7 @@ "name": "Tasmota (beta)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tasmota", - "requirements": ["hatasmota==0.0.26"], + "requirements": ["hatasmota==0.0.25"], "dependencies": ["mqtt"], "mqtt": ["tasmota/discovery/#"], "codeowners": ["@emontnemery"] diff --git a/homeassistant/components/tasmota/sensor.py b/homeassistant/components/tasmota/sensor.py index badf20956650f..076ca457a23f5 100644 --- a/homeassistant/components/tasmota/sensor.py +++ b/homeassistant/components/tasmota/sensor.py @@ -1,7 +1,6 @@ """Support for Tasmota sensors.""" from typing import Optional -from hatasmota import status_sensor from hatasmota.const import ( SENSOR_AMBIENT, SENSOR_APPARENT_POWERUSAGE, @@ -34,12 +33,7 @@ SENSOR_PRESSUREATSEALEVEL, SENSOR_PROXIMITY, SENSOR_REACTIVE_POWERUSAGE, - SENSOR_STATUS_IP, - SENSOR_STATUS_LINK_COUNT, - SENSOR_STATUS_MQTT_COUNT, - SENSOR_STATUS_RSSI, SENSOR_STATUS_SIGNAL, - SENSOR_STATUS_UPTIME, SENSOR_TEMPERATURE, SENSOR_TODAY, SENSOR_TOTAL, @@ -59,7 +53,6 @@ DEVICE_CLASS_PRESSURE, DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_TIMESTAMP, ) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -89,10 +82,7 @@ SENSOR_FREQUENCY: {ICON: "mdi:current-ac"}, SENSOR_HUMIDITY: {DEVICE_CLASS: DEVICE_CLASS_HUMIDITY}, SENSOR_ILLUMINANCE: {DEVICE_CLASS: DEVICE_CLASS_ILLUMINANCE}, - SENSOR_STATUS_IP: {ICON: "mdi:ip-network"}, - SENSOR_STATUS_LINK_COUNT: {ICON: "mdi:counter"}, SENSOR_MOISTURE: {ICON: "mdi:cup-water"}, - SENSOR_STATUS_MQTT_COUNT: {ICON: "mdi:counter"}, SENSOR_PB0_3: {ICON: "mdi:flask"}, SENSOR_PB0_5: {ICON: "mdi:flask"}, SENSOR_PB10: {ICON: "mdi:flask"}, @@ -109,13 +99,11 @@ SENSOR_PROXIMITY: {ICON: "mdi:ruler"}, SENSOR_REACTIVE_POWERUSAGE: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_STATUS_SIGNAL: {DEVICE_CLASS: DEVICE_CLASS_SIGNAL_STRENGTH}, - SENSOR_STATUS_RSSI: {ICON: "mdi:access-point"}, SENSOR_TEMPERATURE: {DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE}, SENSOR_TODAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_TOTAL: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_TOTAL_START_TIME: {ICON: "mdi:progress-clock"}, SENSOR_TVOC: {ICON: "mdi:air-filter"}, - SENSOR_STATUS_UPTIME: {DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP}, SENSOR_VOLTAGE: {ICON: "mdi:alpha-v-circle-outline"}, SENSOR_WEIGHT: {ICON: "mdi:scale"}, SENSOR_YESTERDAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, @@ -174,7 +162,7 @@ def device_class(self) -> Optional[str]: def entity_registry_enabled_default(self) -> bool: """Return if the entity should be enabled when first added to the entity registry.""" # Hide status sensors to not overwhelm users - if self._tasmota_entity.quantity in status_sensor.SENSORS: + if self._tasmota_entity.quantity == SENSOR_STATUS_SIGNAL: return False return True diff --git a/requirements_all.txt b/requirements_all.txt index 8485bfc480bfb..47df2c4250d54 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -738,7 +738,7 @@ hass-nabucasa==0.37.1 hass_splunk==0.1.1 # homeassistant.components.tasmota -hatasmota==0.0.26 +hatasmota==0.0.25 # homeassistant.components.jewish_calendar hdate==0.9.12 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 62b2e5ec42b32..9867e35afd674 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -373,7 +373,7 @@ hangups==0.4.11 hass-nabucasa==0.37.1 # homeassistant.components.tasmota -hatasmota==0.0.26 +hatasmota==0.0.25 # homeassistant.components.jewish_calendar hdate==0.9.12 From f9208634bd2bc5f370534d1e9adfe0b2cc502584 Mon Sep 17 00:00:00 2001 From: Felipe Martins Diel <41558831+felipediel@users.noreply.github.com> Date: Fri, 30 Oct 2020 14:08:37 -0300 Subject: [PATCH 36/43] Fix on/off button (#42443) --- homeassistant/components/broadlink/remote.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/broadlink/remote.py b/homeassistant/components/broadlink/remote.py index 7c7a05ac1676b..cd86244cea8e5 100644 --- a/homeassistant/components/broadlink/remote.py +++ b/homeassistant/components/broadlink/remote.py @@ -26,7 +26,7 @@ SUPPORT_LEARN_COMMAND, RemoteEntity, ) -from homeassistant.const import CONF_HOST, STATE_ON +from homeassistant.const import CONF_HOST, STATE_OFF from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.config_validation as cv @@ -202,7 +202,7 @@ def get_flags(self): async def async_added_to_hass(self): """Call when the remote is added to hass.""" state = await self.async_get_last_state() - self._state = state is None or state.state == STATE_ON + self._state = state is None or state.state != STATE_OFF self.async_on_remove( self._coordinator.async_add_listener(self.async_write_ha_state) From c8944760b7bae9572ec5b3cde09905461e55e1e3 Mon Sep 17 00:00:00 2001 From: airthusiast <67556031+airthusiast@users.noreply.github.com> Date: Fri, 30 Oct 2020 18:50:59 +0100 Subject: [PATCH 37/43] Fix Fibaro HC2 climate device missing temperature (#42627) --- homeassistant/components/fibaro/climate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/fibaro/climate.py b/homeassistant/components/fibaro/climate.py index 6a7a6f145d835..58fde1e370bd3 100644 --- a/homeassistant/components/fibaro/climate.py +++ b/homeassistant/components/fibaro/climate.py @@ -321,7 +321,7 @@ def current_temperature(self): """Return the current temperature.""" if self._temp_sensor_device: device = self._temp_sensor_device.fibaro_device - if device.properties.heatingThermostatSetpoint: + if "heatingThermostatSetpoint" in device.properties: return float(device.properties.heatingThermostatSetpoint) return float(device.properties.value) return None @@ -331,7 +331,7 @@ def target_temperature(self): """Return the temperature we try to reach.""" if self._target_temp_device: device = self._target_temp_device.fibaro_device - if device.properties.heatingThermostatSetpointFuture: + if "heatingThermostatSetpointFuture" in device.properties: return float(device.properties.heatingThermostatSetpointFuture) return float(device.properties.targetLevel) return None From 6e9b0b4614acae6f97603fa2fb329a1e1b9bc405 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 30 Oct 2020 19:02:26 +0100 Subject: [PATCH 38/43] Bump hatasmota to 0.0.26 (#42644) --- homeassistant/components/tasmota/manifest.json | 2 +- homeassistant/components/tasmota/sensor.py | 11 +++++++++++ requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/tasmota/manifest.json b/homeassistant/components/tasmota/manifest.json index b087e13ece0cf..7cc6413e162f5 100644 --- a/homeassistant/components/tasmota/manifest.json +++ b/homeassistant/components/tasmota/manifest.json @@ -3,7 +3,7 @@ "name": "Tasmota (beta)", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tasmota", - "requirements": ["hatasmota==0.0.25"], + "requirements": ["hatasmota==0.0.26"], "dependencies": ["mqtt"], "mqtt": ["tasmota/discovery/#"], "codeowners": ["@emontnemery"] diff --git a/homeassistant/components/tasmota/sensor.py b/homeassistant/components/tasmota/sensor.py index 076ca457a23f5..d96fbf02406da 100644 --- a/homeassistant/components/tasmota/sensor.py +++ b/homeassistant/components/tasmota/sensor.py @@ -33,7 +33,12 @@ SENSOR_PRESSUREATSEALEVEL, SENSOR_PROXIMITY, SENSOR_REACTIVE_POWERUSAGE, + SENSOR_STATUS_IP, + SENSOR_STATUS_LINK_COUNT, + SENSOR_STATUS_MQTT_COUNT, + SENSOR_STATUS_RSSI, SENSOR_STATUS_SIGNAL, + SENSOR_STATUS_UPTIME, SENSOR_TEMPERATURE, SENSOR_TODAY, SENSOR_TOTAL, @@ -53,6 +58,7 @@ DEVICE_CLASS_PRESSURE, DEVICE_CLASS_SIGNAL_STRENGTH, DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_TIMESTAMP, ) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -82,7 +88,10 @@ SENSOR_FREQUENCY: {ICON: "mdi:current-ac"}, SENSOR_HUMIDITY: {DEVICE_CLASS: DEVICE_CLASS_HUMIDITY}, SENSOR_ILLUMINANCE: {DEVICE_CLASS: DEVICE_CLASS_ILLUMINANCE}, + SENSOR_STATUS_IP: {ICON: "mdi:ip-network"}, + SENSOR_STATUS_LINK_COUNT: {ICON: "mdi:counter"}, SENSOR_MOISTURE: {ICON: "mdi:cup-water"}, + SENSOR_STATUS_MQTT_COUNT: {ICON: "mdi:counter"}, SENSOR_PB0_3: {ICON: "mdi:flask"}, SENSOR_PB0_5: {ICON: "mdi:flask"}, SENSOR_PB10: {ICON: "mdi:flask"}, @@ -99,11 +108,13 @@ SENSOR_PROXIMITY: {ICON: "mdi:ruler"}, SENSOR_REACTIVE_POWERUSAGE: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_STATUS_SIGNAL: {DEVICE_CLASS: DEVICE_CLASS_SIGNAL_STRENGTH}, + SENSOR_STATUS_RSSI: {ICON: "mdi:access-point"}, SENSOR_TEMPERATURE: {DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE}, SENSOR_TODAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_TOTAL: {DEVICE_CLASS: DEVICE_CLASS_POWER}, SENSOR_TOTAL_START_TIME: {ICON: "mdi:progress-clock"}, SENSOR_TVOC: {ICON: "mdi:air-filter"}, + SENSOR_STATUS_UPTIME: {DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP}, SENSOR_VOLTAGE: {ICON: "mdi:alpha-v-circle-outline"}, SENSOR_WEIGHT: {ICON: "mdi:scale"}, SENSOR_YESTERDAY: {DEVICE_CLASS: DEVICE_CLASS_POWER}, diff --git a/requirements_all.txt b/requirements_all.txt index 47df2c4250d54..8485bfc480bfb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -738,7 +738,7 @@ hass-nabucasa==0.37.1 hass_splunk==0.1.1 # homeassistant.components.tasmota -hatasmota==0.0.25 +hatasmota==0.0.26 # homeassistant.components.jewish_calendar hdate==0.9.12 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9867e35afd674..62b2e5ec42b32 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -373,7 +373,7 @@ hangups==0.4.11 hass-nabucasa==0.37.1 # homeassistant.components.tasmota -hatasmota==0.0.25 +hatasmota==0.0.26 # homeassistant.components.jewish_calendar hdate==0.9.12 From 73eaef0b1cbef12fa88920302b988c65fb678ce8 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 30 Oct 2020 19:04:11 +0100 Subject: [PATCH 39/43] Make sure Tasmota status sensors are disabled (#42643) --- homeassistant/components/tasmota/sensor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/tasmota/sensor.py b/homeassistant/components/tasmota/sensor.py index d96fbf02406da..badf20956650f 100644 --- a/homeassistant/components/tasmota/sensor.py +++ b/homeassistant/components/tasmota/sensor.py @@ -1,6 +1,7 @@ """Support for Tasmota sensors.""" from typing import Optional +from hatasmota import status_sensor from hatasmota.const import ( SENSOR_AMBIENT, SENSOR_APPARENT_POWERUSAGE, @@ -173,7 +174,7 @@ def device_class(self) -> Optional[str]: def entity_registry_enabled_default(self) -> bool: """Return if the entity should be enabled when first added to the entity registry.""" # Hide status sensors to not overwhelm users - if self._tasmota_entity.quantity == SENSOR_STATUS_SIGNAL: + if self._tasmota_entity.quantity in status_sensor.SENSORS: return False return True From 2b24b9658fcfa9ee155a2e5592ad0ddcc68d7483 Mon Sep 17 00:00:00 2001 From: Glenn Waters Date: Fri, 30 Oct 2020 14:41:13 -0400 Subject: [PATCH 40/43] Bump ElkM1 library to 0.8.7 (#42645) This is a bump by two dot versions of the library. The 0.8.6 version had a number of internal improvements to the library. No external changes. The 0.8.7 version fixes https://github.com/home-assistant/core/issues/20630. --- homeassistant/components/elkm1/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/elkm1/manifest.json b/homeassistant/components/elkm1/manifest.json index d7e7e226ea0e9..1875ce4e97092 100644 --- a/homeassistant/components/elkm1/manifest.json +++ b/homeassistant/components/elkm1/manifest.json @@ -2,7 +2,7 @@ "domain": "elkm1", "name": "Elk-M1 Control", "documentation": "https://www.home-assistant.io/integrations/elkm1", - "requirements": ["elkm1-lib==0.8.5"], + "requirements": ["elkm1-lib==0.8.7"], "codeowners": ["@gwww", "@bdraco"], "config_flow": true } diff --git a/requirements_all.txt b/requirements_all.txt index 8485bfc480bfb..2a0358924dc50 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -538,7 +538,7 @@ elgato==0.2.0 eliqonline==1.2.2 # homeassistant.components.elkm1 -elkm1-lib==0.8.5 +elkm1-lib==0.8.7 # homeassistant.components.mobile_app emoji==0.5.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 62b2e5ec42b32..2f893e0b6618e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -281,7 +281,7 @@ eebrightbox==0.0.4 elgato==0.2.0 # homeassistant.components.elkm1 -elkm1-lib==0.8.5 +elkm1-lib==0.8.7 # homeassistant.components.mobile_app emoji==0.5.4 From 036a8b566763a5aca460568c9a0bf19e14f65899 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Fri, 30 Oct 2020 14:10:32 -0600 Subject: [PATCH 41/43] Small cleanup to IQVIA DataUpdateCoordinator logic (#42642) --- homeassistant/components/iqvia/__init__.py | 27 +++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/iqvia/__init__.py b/homeassistant/components/iqvia/__init__.py index 9aa00ef3f3f76..d730b406896b5 100644 --- a/homeassistant/components/iqvia/__init__.py +++ b/homeassistant/components/iqvia/__init__.py @@ -1,6 +1,7 @@ """Support for IQVIA.""" import asyncio from datetime import timedelta +from functools import partial from pyiqvia import Client from pyiqvia.errors import IQVIAError @@ -77,7 +78,7 @@ async def async_get_data_from_api(api_coro): LOGGER, name=f"{entry.data[CONF_ZIP_CODE]} {sensor_type}", update_interval=DEFAULT_SCAN_INTERVAL, - update_method=lambda coro=api_coro: async_get_data_from_api(coro), + update_method=partial(async_get_data_from_api, api_coro), ) init_data_update_tasks.append(coordinator.async_refresh()) @@ -151,22 +152,22 @@ def unit_of_measurement(self): """Return the unit the value is expressed in.""" return "index" + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self.update_from_latest_data() + self.async_write_ha_state() + async def async_added_to_hass(self): """Register callbacks.""" - - @callback - def update(): - """Update the state.""" - self.update_from_latest_data() - self.async_write_ha_state() - - self.async_on_remove(self.coordinator.async_add_listener(update)) + await super().async_added_to_hass() if self._type == TYPE_ALLERGY_FORECAST: - outlook_coordinator = self.hass.data[DOMAIN][DATA_COORDINATOR][ - self._entry.entry_id - ][TYPE_ALLERGY_OUTLOOK] - self.async_on_remove(outlook_coordinator.async_add_listener(update)) + self.async_on_remove( + self.hass.data[DOMAIN][DATA_COORDINATOR][self._entry.entry_id][ + TYPE_ALLERGY_OUTLOOK + ].async_add_listener(self._handle_coordinator_update) + ) self.update_from_latest_data() From ee528e1a60a230d69f1532a380696f2523b817a1 Mon Sep 17 00:00:00 2001 From: Petro31 <35082313+Petro31@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:18:53 -0400 Subject: [PATCH 42/43] Add hassio service descriptions (#42597) * Add yaml for snapshot services Adds snapshot_full and snapshot_partial service descriptions. * fixes Added password to full & partial. Added name to partial. --- homeassistant/components/hassio/services.yaml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/homeassistant/components/hassio/services.yaml b/homeassistant/components/hassio/services.yaml index 30314c646b030..8afdcc633bff1 100644 --- a/homeassistant/components/hassio/services.yaml +++ b/homeassistant/components/hassio/services.yaml @@ -73,6 +73,32 @@ host_update: description: Optional or it will be use the latest version. example: "0.3" +snapshot_full: + description: Create a full snapshot. + fields: + name: + description: Optional or it will be the current date and time. + example: "Snapshot 1" + password: + description: Optional password. + example: "password" + +snapshot_partial: + description: Create a partial snapshot. + fields: + addons: + description: Optional list of addon slugs. + example: ["core_ssh", "core_samba", "core_mosquitto"] + folders: + description: Optional list of directories. + example: ["homeassistant", "share"] + name: + description: Optional or it will be the current date and time. + example: "Partial Snapshot 1" + password: + description: Optional password. + example: "password" + supervisor_reload: description: Reload the Hass.io supervisor. From c7ba2341e39512e1375e2040007a09e20ac6d2ba Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Sat, 31 Oct 2020 00:04:15 +0000 Subject: [PATCH 43/43] [ci skip] Translation update --- .../components/cover/translations/ru.json | 2 +- .../components/dexcom/translations/it.json | 1 + .../components/esphome/translations/sl.json | 5 +-- .../flunearyou/translations/en.json | 2 +- .../flunearyou/translations/no.json | 2 +- .../flunearyou/translations/ru.json | 2 +- .../flunearyou/translations/zh-Hant.json | 2 +- .../homematicip_cloud/translations/sl.json | 1 + .../components/life360/translations/it.json | 3 ++ .../components/mqtt/translations/sl.json | 22 ++++++++++++ .../rainmachine/translations/et.json | 10 ++++++ .../rainmachine/translations/it.json | 10 ++++++ .../components/tuya/translations/es.json | 5 ++- .../components/tuya/translations/et.json | 3 ++ .../components/tuya/translations/it.json | 36 +++++++++++++++++++ .../components/twilio/translations/it.json | 2 +- .../components/updater/translations/sl.json | 2 +- 17 files changed, 100 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/cover/translations/ru.json b/homeassistant/components/cover/translations/ru.json index e23296940b7ce..f2eff4388cf59 100644 --- a/homeassistant/components/cover/translations/ru.json +++ b/homeassistant/components/cover/translations/ru.json @@ -35,5 +35,5 @@ "stopped": "\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e" } }, - "title": "\u0416\u0430\u043b\u044e\u0437\u0438" + "title": "\u0428\u0442\u043e\u0440\u044b" } \ No newline at end of file diff --git a/homeassistant/components/dexcom/translations/it.json b/homeassistant/components/dexcom/translations/it.json index 0042c585cd1a1..87536efa08f84 100644 --- a/homeassistant/components/dexcom/translations/it.json +++ b/homeassistant/components/dexcom/translations/it.json @@ -1,6 +1,7 @@ { "config": { "abort": { + "already_configured": "L'account \u00e8 gi\u00e0 configurato", "already_configured_account": "L'account \u00e8 gi\u00e0 configurato" }, "error": { diff --git a/homeassistant/components/esphome/translations/sl.json b/homeassistant/components/esphome/translations/sl.json index b16a5cd422606..3f15c2a826f54 100644 --- a/homeassistant/components/esphome/translations/sl.json +++ b/homeassistant/components/esphome/translations/sl.json @@ -1,11 +1,12 @@ { "config": { "abort": { - "already_configured": "ESP je \u017ee konfiguriran", - "already_in_progress": "Konfiguracija ESP je \u017ee v teku" + "already_configured": "Naprava je \u017ee nastavljena.", + "already_in_progress": "Konfiguracijski postopek je \u017ee v teku" }, "error": { "connection_error": "Ne morem se povezati z ESP. Poskrbite, da va\u0161a datoteka YAML vsebuje vrstico \"api:\".", + "invalid_auth": "Neveljavna avtentikacija", "invalid_password": "Neveljavno geslo!", "resolve_error": "Ne moremo razre\u0161iti naslova ESP. \u010ce se napaka ponovi, prosimo nastavite stati\u010dni IP naslov: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, diff --git a/homeassistant/components/flunearyou/translations/en.json b/homeassistant/components/flunearyou/translations/en.json index d94d5c771f498..ad3116a5dae55 100644 --- a/homeassistant/components/flunearyou/translations/en.json +++ b/homeassistant/components/flunearyou/translations/en.json @@ -13,7 +13,7 @@ "latitude": "Latitude", "longitude": "Longitude" }, - "description": "Monitor user-based and CDC repots for a pair of coordinates.", + "description": "Monitor user-based and CDC reports for a pair of coordinates.", "title": "Configure Flu Near You" } } diff --git a/homeassistant/components/flunearyou/translations/no.json b/homeassistant/components/flunearyou/translations/no.json index 94fed8237619f..7c78c1e35a956 100644 --- a/homeassistant/components/flunearyou/translations/no.json +++ b/homeassistant/components/flunearyou/translations/no.json @@ -13,7 +13,7 @@ "latitude": "Breddegrad", "longitude": "Lengdegrad" }, - "description": "Overv\u00e5k brukerbaserte og CDC-repoter for et par koordinater.", + "description": "Overv\u00e5k brukerbaserte rapporter og CDC-rapporter for et par koordinater.", "title": "Konfigurere influensa i n\u00e6rheten av deg" } } diff --git a/homeassistant/components/flunearyou/translations/ru.json b/homeassistant/components/flunearyou/translations/ru.json index e7d56ae1323ae..ef9957b5a76fd 100644 --- a/homeassistant/components/flunearyou/translations/ru.json +++ b/homeassistant/components/flunearyou/translations/ru.json @@ -13,7 +13,7 @@ "latitude": "\u0428\u0438\u0440\u043e\u0442\u0430", "longitude": "\u0414\u043e\u043b\u0433\u043e\u0442\u0430" }, - "description": "\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438 CDC \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f.", + "description": "\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438 CDC \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c.", "title": "Flu Near You" } } diff --git a/homeassistant/components/flunearyou/translations/zh-Hant.json b/homeassistant/components/flunearyou/translations/zh-Hant.json index 6b62857244e02..e4ea0974cc1b2 100644 --- a/homeassistant/components/flunearyou/translations/zh-Hant.json +++ b/homeassistant/components/flunearyou/translations/zh-Hant.json @@ -13,7 +13,7 @@ "latitude": "\u7def\u5ea6", "longitude": "\u7d93\u5ea6" }, - "description": "\u76e3\u6e2c\u4f7f\u7528\u8005\u8207 CDC \u56de\u5831\u5ea7\u6a19\u3002", + "description": "\u76e3\u6e2c\u4f7f\u7528\u8005\u8207 CDC \u56de\u5831\u76f8\u5c0d\u61c9\u5ea7\u6a19\u3002", "title": "\u8a2d\u5b9a Flu Near You" } } diff --git a/homeassistant/components/homematicip_cloud/translations/sl.json b/homeassistant/components/homematicip_cloud/translations/sl.json index 3ced2a1a9bd08..7bf47c666ee12 100644 --- a/homeassistant/components/homematicip_cloud/translations/sl.json +++ b/homeassistant/components/homematicip_cloud/translations/sl.json @@ -6,6 +6,7 @@ "unknown": "Pri\u0161lo je do neznane napake" }, "error": { + "invalid_pin": "Neveljaven PIN, poskusite znova.", "invalid_sgtin_or_pin": "Neveljavna koda PIN, poskusite znova.", "press_the_button": "Prosimo, pritisnite modri gumb.", "register_failed": "Registracija ni uspela, poskusite znova", diff --git a/homeassistant/components/life360/translations/it.json b/homeassistant/components/life360/translations/it.json index ca28b28a2cc57..3f93a93e05ae9 100644 --- a/homeassistant/components/life360/translations/it.json +++ b/homeassistant/components/life360/translations/it.json @@ -3,16 +3,19 @@ "abort": { "invalid_auth": "Autenticazione non valida", "invalid_credentials": "Credenziali non valide", + "unknown": "Errore imprevisto", "user_already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "create_entry": { "default": "Per impostare le opzioni avanzate, consultare la [Documentazione Life360]({docs_url})." }, "error": { + "already_configured": "L'account \u00e8 gi\u00e0 configurato", "invalid_auth": "Autenticazione non valida", "invalid_credentials": "Credenziali non valide", "invalid_username": "Nome utente non valido", "unexpected": "Errore imprevisto durante la comunicazione con il server di Life360", + "unknown": "Errore imprevisto", "user_already_configured": "L'account \u00e8 gi\u00e0 configurato" }, "step": { diff --git a/homeassistant/components/mqtt/translations/sl.json b/homeassistant/components/mqtt/translations/sl.json index 691fdcf058a25..afd2f3b80007c 100644 --- a/homeassistant/components/mqtt/translations/sl.json +++ b/homeassistant/components/mqtt/translations/sl.json @@ -47,5 +47,27 @@ "button_short_release": "Gumb \"{subtype}\" spro\u0161\u010den", "button_triple_press": "Gumb \"{subtype}\" trikrat kliknjen" } + }, + "options": { + "error": { + "cannot_connect": "Povezava ni uspela" + }, + "step": { + "broker": { + "data": { + "broker": "Posrednik", + "password": "Geslo", + "port": "Vrata", + "username": "Uporabni\u0161ko ime" + }, + "description": "Prosimo, vnesite podatke o povezavi do va\u0161ega MQTT posrednika." + }, + "options": { + "data": { + "discovery": "Omogo\u010di odkrivanje" + }, + "description": "Izberite mo\u017enosti MQTT." + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/et.json b/homeassistant/components/rainmachine/translations/et.json index 1b17200b76281..a5e35d02d5645 100644 --- a/homeassistant/components/rainmachine/translations/et.json +++ b/homeassistant/components/rainmachine/translations/et.json @@ -17,5 +17,15 @@ } } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Vaiketsooni k\u00e4itamisaeg (sekundites)" + }, + "title": "Seadista RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/rainmachine/translations/it.json b/homeassistant/components/rainmachine/translations/it.json index 7850ea19c33e6..b8afc7fd0fcbf 100644 --- a/homeassistant/components/rainmachine/translations/it.json +++ b/homeassistant/components/rainmachine/translations/it.json @@ -18,5 +18,15 @@ "title": "Inserisci i tuoi dati" } } + }, + "options": { + "step": { + "init": { + "data": { + "zone_run_time": "Tempo di esecuzione della zona di default (in secondi)" + }, + "title": "Configura RainMachine" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/es.json b/homeassistant/components/tuya/translations/es.json index 9149ec33c1666..f180f43b7f81f 100644 --- a/homeassistant/components/tuya/translations/es.json +++ b/homeassistant/components/tuya/translations/es.json @@ -51,9 +51,12 @@ }, "init": { "data": { + "discovery_interval": "Intervalo de sondeo del descubrimiento al dispositivo en segundos", "list_devices": "Selecciona los dispositivos a configurar o d\u00e9jalos en blanco para guardar la configuraci\u00f3n", - "query_device": "Selecciona el dispositivo que utilizar\u00e1 el m\u00e9todo de consulta para una actualizaci\u00f3n de estado m\u00e1s r\u00e1pida" + "query_device": "Selecciona el dispositivo que utilizar\u00e1 el m\u00e9todo de consulta para una actualizaci\u00f3n de estado m\u00e1s r\u00e1pida", + "query_interval": "Intervalo de sondeo de la consulta al dispositivo en segundos" }, + "description": "No establezcas valores de intervalo de sondeo demasiado bajos o las llamadas fallar\u00e1n generando un mensaje de error en el registro", "title": "Configurar opciones de Tuya" } } diff --git a/homeassistant/components/tuya/translations/et.json b/homeassistant/components/tuya/translations/et.json index b99cfd93d6ebb..ca496952831a3 100644 --- a/homeassistant/components/tuya/translations/et.json +++ b/homeassistant/components/tuya/translations/et.json @@ -45,13 +45,16 @@ "temp_divider": "Temperatuuri v\u00e4\u00e4rtuse eraldaja (0 = kasuta vaikev\u00e4\u00e4rtust)", "unit_of_measurement": "Seadme temperatuuri\u00fchik" }, + "description": "Suvandid \u00fcksuse {device_type} {device_name} kuvatava teabe muutmiseks", "title": "H\u00e4\u00e4lesta Tuya seade" }, "init": { "data": { "discovery_interval": "Seadme leidmisp\u00e4ringute intervall (sekundites)", + "list_devices": "Vali seadistatavad seadmed v\u00f5i j\u00e4ta s\u00e4tete salvestamiseks t\u00fchjaks", "query_interval": "P\u00e4ringute intervall (sekundites)" }, + "description": "\u00c4ra m\u00e4\u00e4ra k\u00fcsitlusintervalli v\u00e4\u00e4rtusi liiga madalaks, vastasel korral v\u00f5ivad p\u00e4ringud logis t\u00f5rketeate genereerida", "title": "Tuya suvandite seadistamine" } } diff --git a/homeassistant/components/tuya/translations/it.json b/homeassistant/components/tuya/translations/it.json index 027764d614fb8..1823cb708dbf0 100644 --- a/homeassistant/components/tuya/translations/it.json +++ b/homeassistant/components/tuya/translations/it.json @@ -24,5 +24,41 @@ "title": "Tuya" } } + }, + "options": { + "error": { + "dev_multi_type": "Pi\u00f9 dispositivi selezionati da configurare devono essere dello stesso tipo", + "dev_not_config": "Tipo di dispositivo non configurabile", + "dev_not_found": "Dispositivo non trovato" + }, + "step": { + "device": { + "data": { + "brightness_range_mode": "Intervallo di luminosit\u00e0 utilizzato dal dispositivo", + "curr_temp_divider": "Divisore del valore della temperatura corrente (0 = usa il valore predefinito)", + "ext_temp_sensor": "Sensore per la temperatura attuale", + "max_kelvin": "Temperatura colore massima supportata in kelvin", + "max_temp": "Temperatura di destinazione massima (utilizzare min e max = 0 per impostazione predefinita)", + "min_kelvin": "Temperatura colore minima supportata in kelvin", + "min_temp": "Temperatura di destinazione minima (utilizzare min e max = 0 per impostazione predefinita)", + "support_color": "Forza il supporto del colore", + "temp_divider": "Divisore dei valori di temperatura (0 = utilizzare il valore predefinito)", + "tuya_max_coltemp": "Temperatura di colore massima riportata dal dispositivo", + "unit_of_measurement": "Unit\u00e0 di temperatura utilizzata dal dispositivo" + }, + "description": "Configura le opzioni per regolare le informazioni visualizzate per il dispositivo {device_type} `{device_name}`", + "title": "Configura il dispositivo Tuya" + }, + "init": { + "data": { + "discovery_interval": "Intervallo di scansione di rilevamento dispositivo in secondi", + "list_devices": "Selezionare i dispositivi da configurare o lasciare vuoto per salvare la configurazione", + "query_device": "Selezionare il dispositivo che utilizzer\u00e0 il metodo di interrogazione per un pi\u00f9 rapido aggiornamento dello stato", + "query_interval": "Intervallo di scansione di interrogazione dispositivo in secondi" + }, + "description": "Non impostare valori dell'intervallo di scansione troppo bassi o le chiamate non riusciranno a generare un messaggio di errore nel registro", + "title": "Configura le opzioni Tuya" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/twilio/translations/it.json b/homeassistant/components/twilio/translations/it.json index ee7ed374cea15..53206b6777136 100644 --- a/homeassistant/components/twilio/translations/it.json +++ b/homeassistant/components/twilio/translations/it.json @@ -10,7 +10,7 @@ }, "step": { "user": { - "description": "Sei sicuro di voler configurare Twilio?", + "description": "Vuoi iniziare la configurazione?", "title": "Configura il webhook di Twilio" } } diff --git a/homeassistant/components/updater/translations/sl.json b/homeassistant/components/updater/translations/sl.json index ac2a2cab3f824..7972844cb69df 100644 --- a/homeassistant/components/updater/translations/sl.json +++ b/homeassistant/components/updater/translations/sl.json @@ -1,3 +1,3 @@ { - "title": "Posodobitelj" + "title": "Posodabljalnik" } \ No newline at end of file